From cf98d240907339ea9bd09c14fda507f1d8ed228b Mon Sep 17 00:00:00 2001 From: pyrite Date: Fri, 27 Jun 2025 16:59:38 +0200 Subject: [PATCH 1/2] feat(codegen): various improvements to robustness --- torn-api-codegen/Cargo.toml | 2 +- torn-api-codegen/src/model/enum.rs | 6 + torn-api-codegen/src/model/mod.rs | 126 +++++++++++++++++-- torn-api-codegen/src/model/object.rs | 175 ++++++++++++++++++--------- torn-api-codegen/src/model/path.rs | 108 +++++++++++++---- torn-api-codegen/src/model/union.rs | 19 ++- torn-api/build.rs | 4 + 7 files changed, 344 insertions(+), 96 deletions(-) diff --git a/torn-api-codegen/Cargo.toml b/torn-api-codegen/Cargo.toml index da49172..ad3162d 100644 --- a/torn-api-codegen/Cargo.toml +++ b/torn-api-codegen/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "torn-api-codegen" authors = ["Pyrit [2111649]"] -version = "0.6.2" +version = "0.7.0" edition = "2021" description = "Contains the v2 torn API model descriptions and codegen for the bindings" license-file = { workspace = true } diff --git a/torn-api-codegen/src/model/enum.rs b/torn-api-codegen/src/model/enum.rs index 4920c03..8a2d556 100644 --- a/torn-api-codegen/src/model/enum.rs +++ b/torn-api-codegen/src/model/enum.rs @@ -77,6 +77,11 @@ impl EnumVariantTupleValue { format: Some("int32"), .. } => Some(Self::Primitive(PrimitiveType::I32)), + OpenApiType { + r#type: Some("number"), + format: Some("float") | None, + .. + } => Some(Self::Primitive(PrimitiveType::Float)), _ => None, } } @@ -146,6 +151,7 @@ impl EnumVariantTupleValue { pub fn is_comparable(&self, resolved: &ResolvedSchema) -> bool { match self { + Self::Primitive(PrimitiveType::Float) => false, Self::Primitive(_) => true, Self::Enum { inner, .. } => inner.is_comparable(resolved), Self::Ref { ty_name } | Self::ArrayOfRefs { ty_name } => resolved diff --git a/torn-api-codegen/src/model/mod.rs b/torn-api-codegen/src/model/mod.rs index 1a8ea80..47748a2 100644 --- a/torn-api-codegen/src/model/mod.rs +++ b/torn-api-codegen/src/model/mod.rs @@ -1,8 +1,10 @@ +use std::{cell::RefCell, rc::Rc}; + use indexmap::IndexMap; use newtype::Newtype; use object::Object; use parameter::Parameter; -use path::Path; +use path::{Path, PrettySegments}; use proc_macro2::TokenStream; use r#enum::Enum; use scope::Scope; @@ -35,11 +37,73 @@ impl Model { } } -#[derive(Debug, Default)] +#[derive(Default)] pub struct ResolvedSchema { pub models: IndexMap, pub paths: IndexMap, pub parameters: Vec, + + pub warnings: WarningReporter, +} + +#[derive(Clone)] +pub struct Warning { + pub message: String, + pub path: Vec, +} + +impl std::fmt::Display for Warning { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "in {}: {}", self.path.join("."), self.message) + } +} + +#[derive(Default)] +struct WarningReporterState { + warnings: Vec, + path: Vec, +} + +#[derive(Clone, Default)] +pub struct WarningReporter { + state: Rc>, +} + +impl WarningReporter { + pub fn new() -> Self { + Self::default() + } + + fn push(&self, message: impl ToString) { + let mut state = self.state.borrow_mut(); + let path = state.path.iter().map(ToString::to_string).collect(); + state.warnings.push(Warning { + message: message.to_string(), + path, + }); + } + + fn child(&self, name: impl ToString) -> WarningReporter { + self.state.borrow_mut().path.push(name.to_string()); + + Self { + state: self.state.clone(), + } + } + + pub fn is_empty(&self) -> bool { + self.state.borrow().warnings.is_empty() + } + + pub fn get_warnings(&self) -> Vec { + self.state.borrow().warnings.clone() + } +} + +impl Drop for WarningReporter { + fn drop(&mut self) { + self.state.borrow_mut().path.pop(); + } } impl ResolvedSchema { @@ -49,14 +113,20 @@ impl ResolvedSchema { for (name, r#type) in &schema.components.schemas { result.models.insert( name.to_string(), - resolve(r#type, name, &schema.components.schemas), + resolve(r#type, name, &schema.components.schemas, &result.warnings), ); } for (path, body) in &schema.paths { result.paths.insert( path.to_string(), - Path::from_schema(path, body, &schema.components.parameters).unwrap(), + Path::from_schema( + path, + body, + &schema.components.parameters, + result.warnings.child(path), + ) + .unwrap(), ); } @@ -83,7 +153,9 @@ impl ResolvedSchema { let mut output = TokenStream::default(); for path in self.paths.values() { - output.extend(path.codegen_request(self)); + output.extend( + path.codegen_request(self, self.warnings.child(PrettySegments(&path.segments))), + ); } output @@ -112,7 +184,12 @@ impl ResolvedSchema { } } -pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenApiType>) -> Model { +pub fn resolve( + r#type: &OpenApiType, + name: &str, + schemas: &IndexMap<&str, OpenApiType>, + warnings: &WarningReporter, +) -> Model { match r#type { OpenApiType { r#enum: Some(_), .. @@ -120,8 +197,12 @@ pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenAp OpenApiType { r#type: Some("object"), .. - } => Object::from_schema_object(name, r#type, schemas) - .map_or(Model::Unresolved, Model::Object), + } => Model::Object(Object::from_schema_object( + name, + r#type, + schemas, + warnings.child(name), + )), OpenApiType { r#type: Some(_), .. } => Newtype::from_schema(name, r#type).map_or(Model::Unresolved, Model::Newtype), @@ -132,7 +213,12 @@ pub fn resolve(r#type: &OpenApiType, name: &str, schemas: &IndexMap<&str, OpenAp OpenApiType { all_of: Some(types), .. - } => Object::from_all_of(name, types, schemas).map_or(Model::Unresolved, Model::Object), + } => Model::Object(Object::from_all_of( + name, + types, + schemas, + warnings.child(name), + )), _ => Model::Unresolved, } } @@ -159,7 +245,14 @@ mod test { let user_id_schema = schema.components.schemas.get("UserId").unwrap(); - let user_id = resolve(user_id_schema, "UserId", &schema.components.schemas); + let reporter = WarningReporter::new(); + let user_id = resolve( + user_id_schema, + "UserId", + &schema.components.schemas, + &reporter, + ); + assert!(reporter.is_empty()); assert_eq!( user_id, @@ -174,7 +267,13 @@ mod test { let attack_code_schema = schema.components.schemas.get("AttackCode").unwrap(); - let attack_code = resolve(attack_code_schema, "AttackCode", &schema.components.schemas); + let attack_code = resolve( + attack_code_schema, + "AttackCode", + &schema.components.schemas, + &reporter, + ); + assert!(reporter.is_empty()); assert_eq!( attack_code, @@ -196,7 +295,10 @@ mod test { let total = schema.components.schemas.len(); for (name, desc) in &schema.components.schemas { - if resolve(desc, name, &schema.components.schemas) == Model::Unresolved { + let reporter = WarningReporter::new(); + if resolve(desc, name, &schema.components.schemas, &reporter) == Model::Unresolved + || !reporter.is_empty() + { unresolved.push(name); } } diff --git a/torn-api-codegen/src/model/object.rs b/torn-api-codegen/src/model/object.rs index 48b3688..b7f454f 100644 --- a/torn-api-codegen/src/model/object.rs +++ b/torn-api-codegen/src/model/object.rs @@ -1,12 +1,12 @@ use heck::{ToSnakeCase, ToUpperCamelCase}; -use indexmap::IndexMap; +use indexmap::{map::Entry, IndexMap}; use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use syn::Ident; use crate::openapi::r#type::OpenApiType; -use super::{r#enum::Enum, ResolvedSchema}; +use super::{r#enum::Enum, ResolvedSchema, WarningReporter}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PrimitiveType { @@ -85,6 +85,7 @@ impl PropertyType { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Property { + pub field_name: String, pub name: String, pub description: Option, pub required: bool, @@ -99,24 +100,31 @@ impl Property { required: bool, schema: &OpenApiType, schemas: &IndexMap<&str, OpenApiType>, + warnings: WarningReporter, ) -> Option { let name = name.to_owned(); + let field_name = name.to_snake_case(); let description = schema.description.as_deref().map(ToOwned::to_owned); match schema { OpenApiType { r#enum: Some(_), .. - } => Some(Self { - r#type: PropertyType::Enum(Enum::from_schema( - &name.clone().to_upper_camel_case(), - schema, - )?), - name, - description, - required, - deprecated: schema.deprecated, - nullable: false, - }), + } => { + let Some(r#enum) = Enum::from_schema(&name.clone().to_upper_camel_case(), schema) + else { + warnings.push("Failed to create enum"); + return None; + }; + Some(Self { + r#type: PropertyType::Enum(r#enum), + name, + field_name, + description, + required, + deprecated: schema.deprecated, + nullable: false, + }) + } OpenApiType { one_of: Some(types), .. @@ -125,7 +133,7 @@ impl Property { r#type: Some("null"), .. }] => { - let mut inner = Self::from_schema(&name, required, left, schemas)?; + let mut inner = Self::from_schema(&name, required, left, schemas, warnings)?; inner.nullable = true; Some(inner) } @@ -137,14 +145,19 @@ impl Property { one_of: Some(left.to_owned()), ..schema.clone() }; - let mut inner = Self::from_schema(&name, required, &rest, schemas)?; + let mut inner = Self::from_schema(&name, required, &rest, schemas, warnings)?; inner.nullable = true; Some(inner) } cases => { - let r#enum = Enum::from_one_of(&name.to_upper_camel_case(), cases)?; + let Some(r#enum) = Enum::from_one_of(&name.to_upper_camel_case(), cases) else { + warnings.push("Failed to create oneOf enum"); + return None; + }; + Some(Self { name, + field_name, description, required, nullable: false, @@ -157,9 +170,12 @@ impl Property { all_of: Some(types), .. } => { - let composite = Object::from_all_of(&name.to_upper_camel_case(), types, schemas)?; + let obj_name = name.to_upper_camel_case(); + let composite = + Object::from_all_of(&obj_name, types, schemas, warnings.child(&obj_name)); Some(Self { name, + field_name, description, required, nullable: false, @@ -170,23 +186,29 @@ impl Property { OpenApiType { r#type: Some("object"), .. - } => Some(Self { - r#type: PropertyType::Nested(Box::new(Object::from_schema_object( - &name.clone().to_upper_camel_case(), - schema, - schemas, - )?)), - name, - description, - required, - deprecated: schema.deprecated, - nullable: false, - }), + } => { + let obj_name = name.to_upper_camel_case(); + Some(Self { + r#type: PropertyType::Nested(Box::new(Object::from_schema_object( + &obj_name, + schema, + schemas, + warnings.child(&obj_name), + ))), + name, + field_name, + description, + required, + deprecated: schema.deprecated, + nullable: false, + }) + } OpenApiType { ref_path: Some(path), .. } => Some(Self { name, + field_name, description, r#type: PropertyType::Ref((*path).to_owned()), required, @@ -198,10 +220,11 @@ impl Property { items: Some(items), .. } => { - let inner = Self::from_schema(&name, required, items, schemas)?; + let inner = Self::from_schema(&name, required, items, schemas, warnings)?; Some(Self { name, + field_name, description, required, nullable: false, @@ -226,6 +249,7 @@ impl Property { Some(Self { name, + field_name, description, required, nullable: false, @@ -233,7 +257,10 @@ impl Property { r#type: PropertyType::Primitive(prim), }) } - _ => None, + _ => { + warnings.push("Could not resolve property type"); + None + } } } @@ -247,11 +274,11 @@ impl Property { let name = &self.name; let (name, serde_attr) = match name.as_str() { "type" => (format_ident!("r#type"), None), - name if name != name.to_snake_case() => ( - format_ident!("{}", name.to_snake_case()), + name if name != self.field_name => ( + format_ident!("{}", self.field_name), Some(quote! { #[serde(rename = #name)]}), ), - _ => (format_ident!("{name}"), None), + _ => (format_ident!("{}", self.field_name), None), }; let ty_inner = self.r#type.codegen(namespace, resolved)?; @@ -283,7 +310,7 @@ impl Property { pub struct Object { pub name: String, pub description: Option, - pub properties: Vec, + pub properties: IndexMap, } impl Object { @@ -291,7 +318,8 @@ impl Object { name: &str, schema: &OpenApiType, schemas: &IndexMap<&str, OpenApiType>, - ) -> Option { + warnings: WarningReporter, + ) -> Self { let mut result = Object { name: name.to_owned(), description: schema.description.as_deref().map(ToOwned::to_owned), @@ -299,39 +327,54 @@ impl Object { }; let Some(props) = &schema.properties else { - return None; + warnings.push("Missing properties"); + return result; }; let required = schema.required.clone().unwrap_or_default(); for (prop_name, prop) in props { - // HACK: This will cause a duplicate key otherwise - if ["itemDetails", "sci-fi", "non-attackers", "co-leader_id"].contains(prop_name) { - continue; - } - - // TODO: implement custom enum for this (depends on overrides being added) - // Maybe this is an issue with the schema instead? - if *prop_name == "value" && name == "TornHof" { - continue; - } - - result.properties.push(Property::from_schema( + let Some(prop) = Property::from_schema( prop_name, required.contains(prop_name), prop, schemas, - )?); + warnings.child(prop_name), + ) else { + continue; + }; + + let field_name = prop.field_name.clone(); + + let entry = result.properties.entry(field_name.clone()); + if let Entry::Occupied(mut entry) = entry { + let other_name = entry.get().name.clone(); + warnings.push(format!( + "Property name collision: {other_name} and {field_name}" + )); + // deprioritise kebab and camelcase + if other_name.contains('-') + || other_name + .chars() + .filter(|c| c.is_alphabetic()) + .all(|c| c.is_ascii_lowercase()) + { + entry.insert(prop); + } + } else { + entry.insert_entry(prop); + } } - Some(result) + result } pub fn from_all_of( name: &str, types: &[OpenApiType], schemas: &IndexMap<&str, OpenApiType>, - ) -> Option { + warnings: WarningReporter, + ) -> Self { let mut result = Self { name: name.to_owned(), ..Default::default() @@ -339,22 +382,29 @@ impl Object { for r#type in types { let r#type = if let OpenApiType { - ref_path: Some(path), + ref_path: Some(ref_path), .. } = r#type { - let name = path.strip_prefix("#/components/schemas/")?; - schemas.get(name)? + let Some(name) = ref_path.strip_prefix("#/components/schemas/") else { + warnings.push(format!("Malformed ref {ref_path}")); + continue; + }; + let Some(schema) = schemas.get(name) else { + warnings.push(format!("Missing schema for ref {name}")); + continue; + }; + schema } else { r#type }; - let obj = Self::from_schema_object(name, r#type, schemas)?; + let obj = Self::from_schema_object(name, r#type, schemas, warnings.child("variant")); result.description = result.description.or(obj.description); result.properties.extend(obj.properties); } - Some(result) + result } pub fn codegen(&self, resolved: &ResolvedSchema) -> Option { @@ -371,7 +421,7 @@ impl Object { }; let mut props = Vec::with_capacity(self.properties.len()); - for prop in &self.properties { + for (_, prop) in &self.properties { props.push(prop.codegen(&mut namespace, resolved)?); } @@ -441,7 +491,14 @@ mod test { for (name, desc) in &schema.components.schemas { if desc.r#type == Some("object") { objects += 1; - if Object::from_schema_object(name, desc, &schema.components.schemas).is_none() { + let reporter = WarningReporter::new(); + Object::from_schema_object( + name, + desc, + &schema.components.schemas, + reporter.clone(), + ); + if !reporter.is_empty() { unresolved.push(name); } } diff --git a/torn-api-codegen/src/model/path.rs b/torn-api-codegen/src/model/path.rs index 319360b..8360baa 100644 --- a/torn-api-codegen/src/model/path.rs +++ b/torn-api-codegen/src/model/path.rs @@ -14,7 +14,7 @@ use crate::openapi::{ use super::{ parameter::{Parameter, ParameterLocation, ParameterType}, union::Union, - ResolvedSchema, + ResolvedSchema, WarningReporter, }; #[derive(Debug, Clone)] @@ -23,6 +23,21 @@ pub enum PathSegment { Parameter { name: String }, } +pub struct PrettySegments<'a>(pub &'a [PathSegment]); + +impl std::fmt::Display for PrettySegments<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for segment in self.0 { + match segment { + PathSegment::Constant(c) => write!(f, "/{c}")?, + PathSegment::Parameter { name } => write!(f, "/{{{name}}}")?, + } + } + + Ok(()) + } +} + #[derive(Debug, Clone)] pub enum PathParameter { Inline(Parameter), @@ -51,6 +66,7 @@ impl Path { path: &str, schema: &OpenApiPath, parameters: &IndexMap<&str, OpenApiParameter>, + warnings: WarningReporter, ) -> Option { let mut segments = Vec::new(); for segment in path.strip_prefix('/')?.split('/') { @@ -111,9 +127,13 @@ impl Path { .strip_prefix("#/components/schemas/")? .to_owned(), }, - OpenApiResponseBody::Union { any_of: _ } => PathResponse::ArbitraryUnion( - Union::from_schema("Response", &schema.get.response_content)?, - ), + OpenApiResponseBody::Union { any_of: _ } => { + PathResponse::ArbitraryUnion(Union::from_schema( + "Response", + &schema.get.response_content, + warnings.child("response"), + )?) + } }; Some(Self { @@ -126,7 +146,11 @@ impl Path { }) } - pub fn codegen_request(&self, resolved: &ResolvedSchema) -> Option { + pub fn codegen_request( + &self, + resolved: &ResolvedSchema, + warnings: WarningReporter, + ) -> Option { let name = if self.segments.len() == 1 { let Some(PathSegment::Constant(first)) = self.segments.first() else { return None; @@ -207,17 +231,30 @@ impl Path { let query_val = ¶m.value; if param.location == ParameterLocation::Path { - discriminant.push(ty.clone()); - discriminant_val.push(quote! { self.#name }); - let path_name = format_ident!("{}", param.value); - start_fields.push(quote! { - #[cfg_attr(feature = "builder", builder(start_fn))] - #builder_param - pub #name: #ty - }); - fmt_val.push(quote! { - #path_name=self.#name - }); + if self.segments.iter().any(|s| { + if let PathSegment::Parameter { name } = s { + name == ¶m.value + } else { + false + } + }) { + discriminant.push(ty.clone()); + discriminant_val.push(quote! { self.#name }); + let path_name = format_ident!("{}", param.value); + start_fields.push(quote! { + #[cfg_attr(feature = "builder", builder(start_fn))] + #builder_param + pub #name: #ty + }); + fmt_val.push(quote! { + #path_name=self.#name + }); + } else { + warnings.push(format!( + "Provided path parameter is not present in the url: {}", + param.value + )); + } } else { let ty = if param.required { convert_field.push(quote! { @@ -329,7 +366,15 @@ impl Path { PathParameter::Component(param) => (param, false), }; - if param.location == ParameterLocation::Path { + if param.location == ParameterLocation::Path + && self.segments.iter().any(|s| { + if let PathSegment::Parameter { name } = s { + name == ¶m.value + } else { + false + } + }) + { let ty = match ¶m.r#type { ParameterType::I32 { .. } | ParameterType::Enum { .. } => { let ty_name = format_ident!("{}", param.name); @@ -444,8 +489,15 @@ impl Path { PathParameter::Inline(param) => (param, true), PathParameter::Component(param) => (param, false), }; - - if param.location == ParameterLocation::Path { + if param.location == ParameterLocation::Path + && self.segments.iter().any(|s| { + if let PathSegment::Parameter { name } = s { + name == ¶m.value + } else { + false + } + }) + { let ty = match ¶m.r#type { ParameterType::I32 { .. } | ParameterType::Enum { .. } => { let ty_name = format_ident!("{}", param.name); @@ -604,7 +656,14 @@ mod test { for (name, desc) in &schema.paths { paths += 1; - if Path::from_schema(name, desc, &schema.components.parameters).is_none() { + if Path::from_schema( + name, + desc, + &schema.components.parameters, + WarningReporter::new(), + ) + .is_none() + { unresolved.push(name); } } @@ -627,18 +686,23 @@ mod test { fn codegen_paths() { let schema = get_schema(); let resolved = ResolvedSchema::from_open_api(&schema); + let reporter = WarningReporter::new(); let mut paths = 0; let mut unresolved = vec![]; for (name, desc) in &schema.paths { paths += 1; - let Some(path) = Path::from_schema(name, desc, &schema.components.parameters) else { + let Some(path) = + Path::from_schema(name, desc, &schema.components.parameters, reporter.clone()) + else { unresolved.push(name); continue; }; - if path.codegen_scope_call().is_none() || path.codegen_request(&resolved).is_none() { + if path.codegen_scope_call().is_none() + || path.codegen_request(&resolved, reporter.clone()).is_none() + { unresolved.push(name); } } diff --git a/torn-api-codegen/src/model/union.rs b/torn-api-codegen/src/model/union.rs index 4cabae3..64e0def 100644 --- a/torn-api-codegen/src/model/union.rs +++ b/torn-api-codegen/src/model/union.rs @@ -4,6 +4,8 @@ use quote::{format_ident, quote}; use crate::openapi::path::OpenApiResponseBody; +use super::WarningReporter; + #[derive(Debug, Clone)] pub struct Union { pub name: String, @@ -11,10 +13,23 @@ pub struct Union { } impl Union { - pub fn from_schema(name: &str, schema: &OpenApiResponseBody) -> Option { + pub fn from_schema( + name: &str, + schema: &OpenApiResponseBody, + warnings: WarningReporter, + ) -> Option { let members = match schema { OpenApiResponseBody::Union { any_of } => { - any_of.iter().map(|l| l.ref_path.to_owned()).collect() + let mut members = Vec::with_capacity(any_of.len()); + for l in any_of { + let path = l.ref_path.to_owned(); + if members.contains(&path) { + warnings.push(format!("Duplicate member: {path}")); + } else { + members.push(path); + } + } + members } _ => return None, }; diff --git a/torn-api/build.rs b/torn-api/build.rs index 0d74a6b..5669358 100644 --- a/torn-api/build.rs +++ b/torn-api/build.rs @@ -28,4 +28,8 @@ fn main() { let scopes_file = syn::parse2(resolved.codegen_scopes()).unwrap(); let scopes_pretty = prettyplease::unparse(&scopes_file); fs::write(&scopes_dest, scopes_pretty).unwrap(); + + for warning in resolved.warnings.get_warnings() { + println!("cargo:warning={}", warning); + } } From 485c2ea176aa6910736c846d330490dc0784ebc5 Mon Sep 17 00:00:00 2001 From: pyrite Date: Fri, 27 Jun 2025 17:01:50 +0200 Subject: [PATCH 2/2] chore(torn-api): updated spec --- Cargo.lock | 4 +- Cargo.toml | 4 +- torn-api/Cargo.toml | 4 +- torn-api/openapi.json | 2475 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 2440 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99356c7..d4fb4ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2294,7 +2294,7 @@ dependencies = [ [[package]] name = "torn-api" -version = "1.6.6" +version = "1.7.0" dependencies = [ "bon", "bytes", @@ -2316,7 +2316,7 @@ dependencies = [ [[package]] name = "torn-api-codegen" -version = "0.6.2" +version = "0.7.0" dependencies = [ "heck", "indexmap", diff --git a/Cargo.toml b/Cargo.toml index bd0a83c..e7fa4ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ members = ["torn-api", "torn-api-codegen", "torn-key-pool"] [workspace.package] license-file = "./LICENSE" -repository = "https://github.com/TotallyNot/torn-api.rs.git" -homepage = "https://github.com/TotallyNot/torn-api.rs.git" +repository = "https://git.elimination.me/pyrite/torn-api.rs.git" +homepage = "https://git.elimination.me/pyrite/torn-api.rs" [workspace.dependencies] serde = { version = "1", features = ["derive"] } diff --git a/torn-api/Cargo.toml b/torn-api/Cargo.toml index 262da7f..ee47443 100644 --- a/torn-api/Cargo.toml +++ b/torn-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "torn-api" -version = "1.6.6" +version = "1.7.0" edition = "2021" description = "Auto-generated bindings for the v2 torn api" license-file = { workspace = true } @@ -39,7 +39,7 @@ strum = { version = "0.27.1", features = ["derive"], optional = true } tokio = { version = "1", features = ["full"] } [build-dependencies] -torn-api-codegen = { path = "../torn-api-codegen", version = "0.6.2" } +torn-api-codegen = { path = "../torn-api-codegen", version = "0.7.0" } syn = { workspace = true, features = ["parsing"] } proc-macro2 = { workspace = true } prettyplease = "0.2" diff --git a/torn-api/openapi.json b/torn-api/openapi.json index 88bce60..6fb982b 100644 --- a/torn-api/openapi.json +++ b/torn-api/openapi.json @@ -3,7 +3,7 @@ "info": { "title": "Torn API", "description": "\n * The development of Torn's API v2 is still ongoing.\n * If selections remain unaltered, they will default to the API v1 version.\n * Unlike API v1, API v2 accepts both selections and IDs as path and query parameters.\n * If any discrepancies or errors are found, please submit a [bug report](https://www.torn.com/forums.php#/p=forums&f=19&b=0&a=0) on the Torn Forums.\n * In case you're using bots to check for changes on openapi.json file, make sure to specificy a custom user-agent header - CloudFlare sometimes prevents requests from default user-agents.", - "version": "1.8.3" + "version": "1.11.4" }, "servers": [ { @@ -1161,6 +1161,192 @@ "x-stability": "Stable" } }, + "/user/properties": { + "get": { + "tags": [ + "User" + ], + "summary": "Get your own properties", + "description": "Requires public access key.
Extended responses are available when requesting the data with Limited or higher access keys.", + "operationId": "574a416ca46717830f03a2f685955b87", + "parameters": [ + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit100Default20" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPropertiesResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/user/{id}/properties": { + "get": { + "tags": [ + "User" + ], + "summary": "Get specific user's properties", + "description": "Requires public access key.
Extended responses are available when requesting the data with Limited or higher access keys for yourself or your spouse.", + "operationId": "601f7b38ac25e1ac47b33fb64120198b", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "User id", + "required": true, + "schema": { + "$ref": "#/components/schemas/UserId" + } + }, + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit100Default20" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPropertiesResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/user/property": { + "get": { + "tags": [ + "User" + ], + "summary": "Get your current property", + "description": "Requires public access key.
", + "operationId": "0452cb8fd031b80d3b7e9fcb7b0bdf09", + "parameters": [ + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPropertyResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/user/{id}/property": { + "get": { + "tags": [ + "User" + ], + "summary": "Get specific user's property", + "description": "Requires public access key.
", + "operationId": "f36ce18449194dd9d2b62bccd4bb8343", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "User id", + "required": true, + "schema": { + "$ref": "#/components/schemas/UserId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPropertyResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/user/races": { "get": { "tags": [ @@ -1221,6 +1407,45 @@ "x-stability": "Stable" } }, + "/user/racingrecords": { + "get": { + "tags": [ + "User" + ], + "summary": "Get your current racing records", + "description": "Requires minimal access key.
", + "operationId": "e1b2c1039ea41f7607b9c94660fc72cb", + "parameters": [ + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyMinimal" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserRacingRecordsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/user/reports": { "get": { "tags": [ @@ -1613,6 +1838,9 @@ { "$ref": "#/components/schemas/UserCalendarResponse" }, + { + "$ref": "#/components/schemas/UserRacingRecordsResponse" + }, { "$ref": "#/components/schemas/UserEducationResponse" }, @@ -1622,6 +1850,9 @@ { "$ref": "#/components/schemas/UserJobRanksResponse" }, + { + "$ref": "#/components/schemas/UserPropertiesResponse" + }, { "$ref": "#/components/schemas/UserFactionBalanceResponse" }, @@ -2288,13 +2519,13 @@ "Faction" ], "summary": "Get your faction's organized crimes", - "description": "Requires minimal access key with faction API access permissions.
It's possible to get older entries either by timestamp range (from, to) or with offset.", + "description": "Requires minimal access key with faction API access permissions.
It's possible to get older entries either by timestamp range (from, to) or with offset.
Crimes are ordered depending on the category chosen:\n * For categories 'all' & 'available', the ordering field is 'created_at'.\n * For categories 'successful', 'failed' & 'completed', the ordering field is 'executed_at'.\n * For categories 'recruiting' & 'expired', the ordering field is 'expired_at'.\n * For category 'planning', the ordering field is 'ready_at'.", "operationId": "72e5db8a773908fedff4bb002f3f4406", "parameters": [ { "name": "cat", "in": "query", - "description": "Category of organized crimes returned. Category 'available' includes both 'recruiting' & 'planning', and category 'completed' includes both 'successful' & 'failure'
Default category is 'all'", + "description": "Category of organized crimes returned. Category 'available' includes both 'recruiting' & 'planning', and category 'completed' includes both 'successful' & 'failure'
Default category is 'all'.", "required": false, "schema": { "type": "string", @@ -2310,6 +2541,21 @@ ] } }, + { + "name": "filters", + "in": "query", + "description": "It's possible to set this parameter to specify a field used for the sort, from & to query parameters. If not specified, the field will default to the category sorting as described above.", + "required": false, + "schema": { + "type": "string", + "enum": [ + "created_at", + "executed_at", + "ready_at", + "expired_at" + ] + } + }, { "$ref": "#/components/parameters/ApiOffset" }, @@ -2721,19 +2967,165 @@ "x-stability": "Unstable" } }, + "/faction/{raidWarId}/raidreport": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get raid war details", + "description": "Requires public access key.
", + "operationId": "9a48477c16e86235efce00a11d56510f", + "parameters": [ + { + "name": "raidWarId", + "in": "path", + "description": "Raid war id", + "required": true, + "schema": { + "$ref": "#/components/schemas/RaidWarId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionRaidWarReportResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/raids": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get raids history for your faction", + "description": "Requires public access key.
", + "operationId": "6a2b0604d0ebe31933f93facfa69f171", + "parameters": [ + { + "$ref": "#/components/parameters/ApiFrom" + }, + { + "$ref": "#/components/parameters/ApiTo" + }, + { + "$ref": "#/components/parameters/ApiSortDesc" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionRaidsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/{id}/raids": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a faction's raids history", + "description": "Requires public access key.
", + "operationId": "67622543dbbc4857f1ea575be5af7fcd", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Faction id", + "required": true, + "schema": { + "$ref": "#/components/schemas/FactionId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionRaidsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/faction/rankedwars": { "get": { "tags": [ "Faction" ], - "summary": "Get ranked wars list", - "description": "Requires public access key.
When category 'all' is chosen, you can use 'from', 'to' & 'sort' query parameters.
When category 'ongoing' is chosen, all currently active ranked wars are returned.
When no category is chosen, this selection will return ranked war history of your own faction (if any).", + "summary": "Get ranked wars history for your faction", + "description": "Requires public access key.
", "operationId": "4f5d624a86e2d389a7a738b6b3ce8c9e", "parameters": [ { "name": "cat", "in": "query", + "description": "This parameter is deprecated. The ranked wars list can now instead be fetched via 'faction' -> 'warfare' endpoint. This functionality will be removed on 1st of September 2025.", "required": false, + "deprecated": true, "schema": { "$ref": "#/components/schemas/FactionRankedWarsCategoryEnum" } @@ -3060,7 +3452,7 @@ "$ref": "#/components/parameters/ApiFactionSearchFilter" }, { - "$ref": "#/components/parameters/ApiLimit20" + "$ref": "#/components/parameters/ApiLimit50Default20" }, { "$ref": "#/components/parameters/ApiOffset" @@ -3271,14 +3663,16 @@ "tags": [ "Faction" ], - "summary": "Get territory wars list", - "description": "Requires public access key.
When category 'finished' is chosen, you can use 'from', 'to' & 'sort' query parameters.
When category 'ongoing' is chosen, all currently active territory wars are returned.
When no category is chosen, this selection will return territory war history of your own faction (if any).", + "summary": "Get territory wars history for your faction", + "description": "Requires public access key.
", "operationId": "0258963246159d1e3e54547c32aac7c8", "parameters": [ { "name": "cat", "in": "query", + "description": "This parameter is deprecated. The territory wars list can now instead be fetched via 'faction' -> 'warfare' endpoint. This functionality will be removed on 1st of September 2025.", "required": false, + "deprecated": true, "schema": { "$ref": "#/components/schemas/FactionTerritoryWarsCategoryEnum" } @@ -3460,6 +3854,65 @@ "x-stability": "Unstable" } }, + "/faction/warfare": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get faction warfare", + "description": "Requires public access key.
The response depends on the selected category.", + "operationId": "ae7f06db4618d3e7927fd700cfa58f16", + "parameters": [ + { + "name": "cat", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/FactionWarfareTypeEnum" + } + }, + { + "$ref": "#/components/parameters/ApiLimit100" + }, + { + "$ref": "#/components/parameters/ApiSort" + }, + { + "$ref": "#/components/parameters/ApiFrom" + }, + { + "$ref": "#/components/parameters/ApiTo" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionWarfareResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Stable" + } + }, "/faction/wars": { "get": { "tags": [ @@ -3668,6 +4121,9 @@ }, { "$ref": "#/components/schemas/TerritoryWarId" + }, + { + "$ref": "#/components/schemas/RaidWarId" } ] } @@ -3717,6 +4173,9 @@ { "$ref": "#/components/schemas/ReportTypeEnum" }, + { + "$ref": "#/components/schemas/FactionWarfareTypeEnum" + }, { "$ref": "#/components/schemas/FactionTerritoryWarsCategoryEnum" } @@ -3732,6 +4191,20 @@ "$ref": "#/components/schemas/FactionStatEnum" } }, + { + "name": "filters", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "created_at", + "executed_at", + "ready_at", + "expired_at" + ] + } + }, { "$ref": "#/components/parameters/ApiStripTags" }, @@ -3785,6 +4258,9 @@ { "$ref": "#/components/schemas/FactionBalanceResponse" }, + { + "$ref": "#/components/schemas/FactionRaidWarReportResponse" + }, { "$ref": "#/components/schemas/FactionTerritoriesOwnershipResponse" }, @@ -3815,6 +4291,12 @@ { "$ref": "#/components/schemas/FactionCrimeResponse" }, + { + "$ref": "#/components/schemas/FactionRaidsResponse" + }, + { + "$ref": "#/components/schemas/FactionWarfareResponse" + }, { "$ref": "#/components/schemas/FactionRankedWarReportResponse" }, @@ -4455,6 +4937,102 @@ "x-stability": "Stable" } }, + "/market/bazaar": { + "get": { + "tags": [ + "Market" + ], + "summary": "Get bazaar directory", + "description": "Requires public access key.
The default response is of type 'BazaarWeekly', but if a category is chosen, the response will be of type 'BazaarSpecialized'.", + "operationId": "422876deda064e2f3a2cc3c4bf6d73a9", + "parameters": [ + { + "name": "cat", + "in": "query", + "description": "Category of specialized bazaars returned", + "required": false, + "schema": { + "$ref": "#/components/schemas/MarketSpecializedBazaarCategoryEnum" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BazaarResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/market/{id}/bazaar": { + "get": { + "tags": [ + "Market" + ], + "summary": "Get item specialized bazaar directory", + "description": "Requires public access key.
", + "operationId": "8254489388603bf1b21740e6f71bef06", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Item id", + "required": true, + "schema": { + "$ref": "#/components/schemas/ItemId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BazaarResponseSpecialized" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/market/{id}/itemmarket": { "get": { "tags": [ @@ -4515,6 +5093,120 @@ "x-stability": "Unstable" } }, + "/market/{propertyTypeId}/properties": { + "get": { + "tags": [ + "Market" + ], + "summary": "Get properties market listings", + "description": "Requires public access key.
", + "operationId": "17e406574ff1eb686891c0fb0e15343a", + "parameters": [ + { + "name": "propertyTypeId", + "in": "path", + "description": "Property type id", + "required": true, + "schema": { + "$ref": "#/components/schemas/PropertyTypeId" + } + }, + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit100Default20" + }, + { + "$ref": "#/components/parameters/ApiSort" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarketPropertiesResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/market/{propertyTypeId}/rentals": { + "get": { + "tags": [ + "Market" + ], + "summary": "Get properties rental listings", + "description": "Requires public access key.
", + "operationId": "38cd1a2c47e266a703a13e0dd401f4a9", + "parameters": [ + { + "name": "propertyTypeId", + "in": "path", + "description": "Property type id", + "required": true, + "schema": { + "$ref": "#/components/schemas/PropertyTypeId" + } + }, + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit100Default20" + }, + { + "$ref": "#/components/parameters/ApiSort" + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MarketRentalsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/market/lookup": { "get": { "tags": [ @@ -4622,7 +5314,23 @@ "description": "selection id", "required": false, "schema": { - "$ref": "#/components/schemas/ItemId" + "oneOf": [ + { + "$ref": "#/components/schemas/ItemId" + }, + { + "$ref": "#/components/schemas/PropertyTypeId" + } + ] + } + }, + { + "name": "cat", + "in": "query", + "description": "Category of specialized bazaars returned", + "required": false, + "schema": { + "$ref": "#/components/schemas/MarketSpecializedBazaarCategoryEnum" } }, { @@ -4650,6 +5358,9 @@ { "$ref": "#/components/parameters/ApiOffsetNoDefault" }, + { + "$ref": "#/components/parameters/ApiLimit100Default20" + }, { "$ref": "#/components/parameters/ApiTimestamp" }, @@ -4667,9 +5378,21 @@ "application/json": { "schema": { "anyOf": [ + { + "$ref": "#/components/schemas/BazaarResponse" + }, + { + "$ref": "#/components/schemas/BazaarResponseSpecialized" + }, { "$ref": "#/components/schemas/MarketItemMarketResponse" }, + { + "$ref": "#/components/schemas/MarketRentalsResponse" + }, + { + "$ref": "#/components/schemas/MarketPropertiesResponse" + }, { "$ref": "#/components/schemas/MarketLookupResponse" }, @@ -4882,7 +5605,7 @@ "Racing" ], "summary": "Get track records", - "description": "Requires public access key.
Returns a list of 10 best lap records for the chosen track and car class. Results are cached globally 1 hour.", + "description": "Requires public access key.
Returns a list of 5 best lap records for the chosen track and car class.", "operationId": "5fbc62db3b9380b155d7e33100620da7", "parameters": [ { @@ -5175,6 +5898,204 @@ "x-stability": "Stable" } }, + "/property/{id}/property": { + "get": { + "tags": [ + "Property" + ], + "summary": "Get a specific property", + "description": "Requires public access key.
", + "operationId": "87bd73ddaf3749bce7cbf5aa28e921e2", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Property id", + "required": true, + "schema": { + "$ref": "#/components/schemas/PropertyId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserPropertyResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/property/lookup": { + "get": { + "tags": [ + "Property" + ], + "summary": "Get all available property selections", + "description": "Requires public access key.
", + "operationId": "87fe6e3a7ec186e108922fed781c8d6d", + "parameters": [ + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PropertyLookupResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Stable" + } + }, + "/property/timestamp": { + "get": { + "tags": [ + "Property" + ], + "summary": "Get current server time", + "description": "Requires public access key.
", + "operationId": "423c130a5cdf6bc801c42537c07fddec", + "parameters": [ + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TimestampResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Stable" + } + }, + "/property": { + "get": { + "tags": [ + "Property" + ], + "summary": "Get any property selection", + "description": "Requires public access key.
Choose one or more selections (comma separated).", + "operationId": "2a45b6d9d77224d9a1e13d0b698f6c4b", + "parameters": [ + { + "name": "selections", + "in": "query", + "description": "Selection names", + "required": false, + "style": "form", + "explode": false, + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertySelectionName" + } + } + }, + { + "name": "id", + "in": "query", + "description": "Property id", + "required": true, + "schema": { + "$ref": "#/components/schemas/PropertyId" + } + }, + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/UserPropertyResponse" + }, + { + "$ref": "#/components/schemas/PropertyLookupResponse" + }, + { + "$ref": "#/components/schemas/TimestampResponse" + } + ] + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Stable" + } + }, "/torn/attacklog": { "get": { "tags": [ @@ -5852,6 +6773,45 @@ "x-stability": "Stable" } }, + "/torn/properties": { + "get": { + "tags": [ + "Torn" + ], + "summary": "Get properties details", + "description": "Requires public access key.
", + "operationId": "c44f572f4672071280a28e6f8217c3b6", + "parameters": [ + { + "$ref": "#/components/parameters/ApiTimestamp" + }, + { + "$ref": "#/components/parameters/ApiComment" + }, + { + "$ref": "#/components/parameters/ApiKeyPublic" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TornProperties" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/torn/{crimeId}/subcrimes": { "get": { "tags": [ @@ -6175,6 +7135,9 @@ { "$ref": "#/components/schemas/TornItemAmmoResponse" }, + { + "$ref": "#/components/schemas/TornProperties" + }, { "$ref": "#/components/schemas/TornFactionTreeResponse" }, @@ -10401,6 +11364,7 @@ "gymtrains", "gymstrength", "gymspeed", + "gymenergy", "gymdefense", "gymdexterity", "candyused", @@ -10440,6 +11404,35 @@ "custom" ] }, + "MarketSpecializedBazaarCategoryEnum": { + "type": "string", + "enum": [ + "Alcohol", + "Artifact", + "Booster", + "Candy", + "Car", + "Clothing", + "Collectible", + "Defensive", + "Drug", + "Energy Drink", + "Enhancer", + "Flower", + "Jewelry", + "Material", + "Medical", + "Melee", + "Other", + "Plushie", + "Primary", + "Secondary", + "Special", + "Supply Pack", + "Temporary", + "Tool" + ] + }, "FactionPositionAbilityEnum": { "type": "string", "enum": [ @@ -10826,7 +11819,8 @@ "enum": [ "accepted", "declined", - "withdrawn" + "withdrawn", + "active" ] }, "FactionRankedWarsCategoryEnum": { @@ -10857,6 +11851,18 @@ "type": "integer", "format": "int32" }, + "PropertyTypeId": { + "type": "integer", + "format": "int32" + }, + "PropertyId": { + "type": "integer", + "format": "int64" + }, + "DirtyBombId": { + "type": "integer", + "format": "int32" + }, "RaceTrackId": { "type": "integer", "format": "int32" @@ -10889,6 +11895,10 @@ "type": "integer", "format": "int32" }, + "RaidWarId": { + "type": "integer", + "format": "int32" + }, "ItemUid": { "type": "integer", "format": "int64" @@ -11064,6 +12074,47 @@ "Unknown" ] }, + "FactionWarfareTypeEnum": { + "type": "string", + "enum": [ + "ranked", + "territory", + "raid", + "chain", + "db" + ] + }, + "PropertyModificationEnum": { + "type": "string", + "enum": [ + "Hot Tub", + "Sauna", + "Open Bar", + "Small Pool", + "Medium Pool", + "Large Pool", + "Small Vault", + "Medium Vault", + "Large Vault", + "Extra Large Vault", + "Medical Facility", + "Advanced Shooting Range", + "Airstrip", + "Private Yacht", + "Sufficient Interior Modification", + "Superior Interior Modification" + ] + }, + "PropertyStaffEnum": { + "type": "string", + "enum": [ + "Maid", + "Guard", + "Doctor", + "Pilot", + "Butler" + ] + }, "FactionCrimeStatusEnum": { "type": "string", "enum": [ @@ -11594,7 +12645,8 @@ "required": [ "id", "name", - "faction" + "faction", + "skill" ], "properties": { "id": { @@ -11624,6 +12676,18 @@ "type": "null" } ] + }, + "skill": { + "description": "Entries before 16/06/2025 will have this field set as null.", + "oneOf": [ + { + "type": "number", + "format": "float" + }, + { + "type": "null" + } + ] } }, "type": "object" @@ -12306,6 +13370,315 @@ } ] }, + "BasicUser": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "UserPropertyBasicDetails": { + "required": [ + "id", + "owner", + "property", + "happy", + "upkeep", + "market_price", + "modifications", + "staff" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/PropertyId" + }, + "owner": { + "$ref": "#/components/schemas/BasicUser" + }, + "property": { + "$ref": "#/components/schemas/BasicProperty" + }, + "happy": { + "type": "integer", + "format": "int32" + }, + "upkeep": { + "required": [ + "property", + "staff" + ], + "properties": { + "property": { + "type": "integer", + "format": "int32" + }, + "staff": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "market_price": { + "type": "integer", + "format": "int64" + }, + "modifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyModificationEnum" + } + }, + "staff": { + "type": "array", + "items": { + "required": [ + "type", + "amount" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/PropertyStaffEnum" + }, + "amount": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + } + }, + "type": "object" + }, + "UserPropertyDetailsExtended": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "required": [ + "status", + "used_by" + ], + "properties": { + "used_by": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BasicUser" + } + }, + "status": { + "type": "string", + "enum": [ + "none", + "in_use" + ] + } + }, + "type": "object" + } + ] + }, + "UserPropertyDetails": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "required": [ + "used_by" + ], + "properties": { + "used_by": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BasicUser" + } + } + }, + "type": "object" + } + ] + }, + "UserPropertyDetailsExtendedRented": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "required": [ + "status", + "used_by", + "cost", + "cost_per_day", + "rental_period", + "rental_period_remaining" + ], + "properties": { + "used_by": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BasicUser" + } + }, + "status": { + "type": "string", + "enum": [ + "rented" + ] + }, + "cost": { + "type": "integer", + "format": "int64" + }, + "cost_per_day": { + "type": "integer", + "format": "int64" + }, + "rental_period": { + "type": "integer", + "format": "int32" + }, + "rental_period_remaining": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "UserPropertyDetailsExtendedForRent": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "required": [ + "status", + "used_by", + "cost", + "cost_per_day", + "rental_period" + ], + "properties": { + "used_by": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BasicUser" + } + }, + "status": { + "type": "string", + "enum": [ + "for_rent" + ] + }, + "cost": { + "type": "integer", + "format": "int64" + }, + "cost_per_day": { + "type": "integer", + "format": "int64" + }, + "rental_period": { + "type": "integer", + "format": "int32" + }, + "renter_asked": { + "$ref": "#/components/schemas/BasicUser" + } + }, + "type": "object" + } + ] + }, + "UserPropertyDetailsExtendedForSale": { + "allOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "required": [ + "status", + "used_by", + "cost" + ], + "properties": { + "used_by": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BasicUser" + } + }, + "status": { + "type": "string", + "enum": [ + "for_sale" + ] + }, + "cost": { + "type": "integer", + "format": "int64" + } + }, + "type": "object" + } + ] + }, + "UserPropertiesResponse": { + "required": [ + "properties", + "_metadata" + ], + "properties": { + "properties": { + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/UserPropertyBasicDetails" + }, + { + "$ref": "#/components/schemas/UserPropertyDetailsExtended" + }, + { + "$ref": "#/components/schemas/UserPropertyDetailsExtendedRented" + }, + { + "$ref": "#/components/schemas/UserPropertyDetailsExtendedForRent" + }, + { + "$ref": "#/components/schemas/UserPropertyDetailsExtendedForSale" + } + ] + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, + "UserPropertyResponse": { + "required": [ + "property" + ], + "properties": { + "property": { + "$ref": "#/components/schemas/UserPropertyDetails" + } + }, + "type": "object" + }, "UserCurrentEducation": { "required": [ "id", @@ -12436,12 +13809,6 @@ "type": "integer", "format": "int32" }, - "sci-fi": { - "description": "This is replaced with 'sci_fi' field and will be removed on 1st June 2025.", - "type": "integer", - "format": "int32", - "deprecated": true - }, "sci_fi": { "type": "integer", "format": "int32" @@ -13703,7 +15070,7 @@ "UserSelectionName": { "oneOf": [ { - "description": "The following selections will fallback to API v1 and may change at any time: 'ammo','bars','basic','battlestats','bazaar','cooldowns','criminalrecord','discord','display','education','equipment','events','gym','honors','icons','inventory','jobpoints','log','medals','merits','messages','missions','money','networth','newevents','newmessages','notifications','perks','profile','properties','refills','reports','skills','stocks','travel','weaponexp','workstats'.", + "description": "The following selections will fallback to API v1 and may change at any time: 'ammo','bars','basic','battlestats','bazaar','cooldowns','criminalrecord','discord','display','education','equipment','events','gym','honors','icons','inventory','jobpoints','log','medals','merits','messages','missions','money','networth','newevents','newmessages','notifications','perks','profile','refills','reports','skills','stocks','travel','weaponexp','workstats'.", "type": "string", "enum": [ "attacks", @@ -13725,7 +15092,10 @@ "lookup", "organizedcrime", "personalstats", + "properties", + "property", "races", + "racingrecords", "revives", "revivesfull", "timestamp", @@ -13758,7 +15128,6 @@ "notifications", "perks", "profile", - "properties", "refills", "reports", "skills", @@ -16826,6 +18195,339 @@ "scammingskill" ] }, + "FactionRaidReport": { + "required": [ + "id", + "start", + "end", + "aggressor", + "defender" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/RaidWarId" + }, + "start": { + "type": "integer", + "format": "int32" + }, + "end": { + "type": "integer", + "format": "int32" + }, + "aggressor": { + "$ref": "#/components/schemas/FactionRaidReportFaction" + }, + "defender": { + "$ref": "#/components/schemas/FactionRaidReportFaction" + } + }, + "type": "object" + }, + "FactionRaidReportFaction": { + "required": [ + "id", + "name", + "score", + "attackers", + "non_attackers" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "number", + "format": "float" + }, + "attackers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRaidReportAttacker" + } + }, + "non_attackers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRaidReportUser" + } + } + }, + "type": "object" + }, + "FactionRaidReportAttacker": { + "required": [ + "user", + "attacks", + "damage" + ], + "properties": { + "user": { + "$ref": "#/components/schemas/FactionRaidReportUser" + }, + "attacks": { + "type": "integer", + "format": "int32" + }, + "damage": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "FactionRaidReportUser": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "FactionRaidWarReportResponse": { + "required": [ + "raidreport" + ], + "properties": { + "raidreport": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRaidReport" + } + } + }, + "type": "object" + }, + "FactionWarfareDirtyBomb": { + "required": [ + "id", + "planted_at", + "detonated_at", + "faction", + "user" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/DirtyBombId" + }, + "planted_at": { + "type": "integer", + "format": "int32" + }, + "detonated_at": { + "type": "integer", + "format": "int32" + }, + "faction": { + "$ref": "#/components/schemas/FactionWarfareDirtyBombTargetFaction" + }, + "user": { + "oneOf": [ + { + "$ref": "#/components/schemas/FactionWarfareDirtyBombPlanter" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "FactionWarfareDirtyBombTargetFaction": { + "required": [ + "id", + "name", + "respect_lost" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "respect_lost": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "FactionWarfareDirtyBombPlanter": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "FactionRaidWarfare": { + "required": [ + "id", + "start", + "end", + "aggressor", + "defender" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/RaidWarId" + }, + "start": { + "type": "integer", + "format": "int32" + }, + "end": { + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "null" + } + ] + }, + "aggressor": { + "$ref": "#/components/schemas/FactionRaidWarfareFaction" + }, + "defender": { + "$ref": "#/components/schemas/FactionRaidWarfareFaction" + } + }, + "type": "object" + }, + "FactionRaidWarfareFaction": { + "description": "The field 'chain' exists only if the field 'end' is NOT populated in FactionRaidWarfare schema.", + "required": [ + "id", + "name", + "score" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "number", + "format": "float" + }, + "chain": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "FactionTerritoryWarfare": { + "required": [ + "id", + "territory", + "start", + "end", + "target", + "aggressor", + "defender", + "result" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/TerritoryWarId" + }, + "territory": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "start": { + "type": "integer", + "format": "int32" + }, + "end": { + "type": "integer", + "format": "int32" + }, + "target": { + "type": "integer", + "format": "int32" + }, + "aggressor": { + "$ref": "#/components/schemas/FactionTerritoryWarFaction" + }, + "defender": { + "$ref": "#/components/schemas/FactionTerritoryWarFaction" + }, + "result": { + "type": "string" + } + }, + "type": "object" + }, + "FactionTerritoryWarFactionWallPlayers": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "FactionTerritoryWarFaction": { + "description": "The fields 'chain' and 'players_on_wall' exist only for wars with the result 'in_progress'.", + "required": [ + "id", + "name", + "score" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "integer", + "format": "int32" + }, + "chain": { + "type": "integer", + "format": "int32" + }, + "players_on_wall": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarFactionWallPlayers" + } + } + }, + "type": "object" + }, "FactionTerritoryWarFinishedFaction": { "required": [ "id", @@ -17885,10 +19587,6 @@ "leader_id": { "$ref": "#/components/schemas/UserId" }, - "co-leader_id": { - "$ref": "#/components/schemas/UserId", - "description": "This is replaced with 'co_leader_id' field and will be removed on 1st June 2025." - }, "co_leader_id": { "$ref": "#/components/schemas/UserId" }, @@ -18290,6 +19988,24 @@ }, "type": "object" }, + "FactionRaidsResponse": { + "required": [ + "raids", + "_metadata" + ], + "properties": { + "raids": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRaidWarfare" + } + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, "FactionAttacksResponse": { "required": [ "attacks", @@ -18505,6 +20221,36 @@ }, "type": "object" }, + "FactionChainWarfare": { + "allOf": [ + { + "$ref": "#/components/schemas/FactionChain" + }, + { + "required": [ + "faction" + ], + "properties": { + "faction": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + ] + }, "FactionChainsResponse": { "required": [ "chains", @@ -18575,14 +20321,6 @@ "$ref": "#/components/schemas/FactionChainReportAttacker" } }, - "non-attackers": { - "description": "This is replaced with 'non_attackers' field and will be removed on 1st June 2025.", - "type": "array", - "items": { - "$ref": "#/components/schemas/UserId" - }, - "deprecated": true - }, "non_attackers": { "type": "array", "items": { @@ -19211,6 +20949,8 @@ "news", "positions", "rackets", + "raidreport", + "raids", "rankedwars", "rankedwarreport", "reports", @@ -19224,6 +20964,7 @@ "territorywars", "timestamp", "upgrades", + "warfare", "wars", "armor", "boosters", @@ -19341,6 +21082,52 @@ }, "type": "object" }, + "FactionWarfareResponse": { + "required": [ + "warfare", + "_metadata" + ], + "properties": { + "warfare": { + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRankedWarDetails" + } + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarfare" + } + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionChainWarfare" + } + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionRaidWarfare" + } + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionWarfareDirtyBomb" + } + } + ] + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, "FactionRankedWarReportResponse": { "required": [ "rankedwarreport" @@ -20188,6 +21975,437 @@ } ] }, + "BasicProperty": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/PropertyTypeId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "MarketRentalDetails": { + "required": [ + "listings", + "property" + ], + "properties": { + "listings": { + "type": "array", + "items": { + "required": [ + "happy", + "cost", + "cost_per_day", + "rental_period", + "market_price", + "upkeep", + "modifications" + ], + "properties": { + "happy": { + "type": "integer", + "format": "int32" + }, + "cost": { + "type": "integer", + "format": "int64" + }, + "cost_per_day": { + "type": "integer", + "format": "int64" + }, + "rental_period": { + "type": "integer", + "format": "int32" + }, + "market_price": { + "type": "integer", + "format": "int64" + }, + "upkeep": { + "type": "integer", + "format": "int32" + }, + "modifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyModificationEnum" + } + } + }, + "type": "object" + } + }, + "property": { + "$ref": "#/components/schemas/BasicProperty" + } + }, + "type": "object" + }, + "MarketRentalsResponse": { + "required": [ + "properties", + "_metadata" + ], + "properties": { + "properties": { + "$ref": "#/components/schemas/MarketRentalDetails" + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, + "MarketPropertyDetails": { + "required": [ + "listings", + "property" + ], + "properties": { + "listings": { + "type": "array", + "items": { + "required": [ + "happy", + "cost", + "market_price", + "upkeep", + "modifications" + ], + "properties": { + "happy": { + "type": "integer", + "format": "int32" + }, + "cost": { + "type": "integer", + "format": "int64" + }, + "market_price": { + "type": "integer", + "format": "int64" + }, + "upkeep": { + "type": "integer", + "format": "int32" + }, + "modifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyModificationEnum" + } + } + }, + "type": "object" + } + }, + "property": { + "$ref": "#/components/schemas/BasicProperty" + } + }, + "type": "object" + }, + "MarketPropertiesResponse": { + "required": [ + "properties", + "_metadata" + ], + "properties": { + "properties": { + "$ref": "#/components/schemas/MarketPropertyDetails" + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, + "BazaarWeekly": { + "required": [ + "busiest", + "most_popular", + "trending", + "top_grossing", + "bulk", + "advanced_item", + "bargain", + "dollar_sale" + ], + "properties": { + "busiest": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarWeeklyCustomers" + } + }, + "most_popular": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarTotalFavorites" + } + }, + "trending": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarRecentFavorites" + } + }, + "top_grossing": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarWeeklyIncome" + } + }, + "bulk": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarBulkSales" + } + }, + "advanced_item": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarAdvancedItemSales" + } + }, + "bargain": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarBargainSales" + } + }, + "dollar_sale": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarDollarSales" + } + } + }, + "type": "object" + }, + "BazaarSpecialized": { + "required": [ + "specialized" + ], + "properties": { + "specialized": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BazaarWeeklyCustomers" + } + } + }, + "type": "object" + }, + "BazaarResponse": { + "required": [ + "bazaar" + ], + "properties": { + "bazaar": { + "description": "If there's a specific item ID passed or a category chosen, the response will be of type 'BazaarSpecialized', otherwise it will be 'BazaarWeekly'.", + "oneOf": [ + { + "$ref": "#/components/schemas/BazaarWeekly" + }, + { + "$ref": "#/components/schemas/BazaarSpecialized" + } + ] + } + }, + "type": "object" + }, + "BazaarResponseSpecialized": { + "required": [ + "bazaar" + ], + "properties": { + "bazaar": { + "$ref": "#/components/schemas/BazaarSpecialized" + } + }, + "type": "object" + }, + "Bazaar": { + "required": [ + "id", + "name", + "is_open" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "name": { + "type": "string" + }, + "is_open": { + "type": "boolean" + } + }, + "type": "object" + }, + "BazaarWeeklyCustomers": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "weekly_customers" + ], + "properties": { + "weekly_customers": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarTotalFavorites": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "total_favorites" + ], + "properties": { + "total_favorites": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarRecentFavorites": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "recent_favorites" + ], + "properties": { + "recent_favorites": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarWeeklyIncome": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "weekly_income" + ], + "properties": { + "weekly_income": { + "type": "integer", + "format": "int64" + } + }, + "type": "object" + } + ] + }, + "BazaarBulkSales": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "bulk_sales" + ], + "properties": { + "bulk_sales": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarAdvancedItemSales": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "advanced_item_sales" + ], + "properties": { + "advanced_item_sales": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarBargainSales": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "bargain_sales" + ], + "properties": { + "bargain_sales": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, + "BazaarDollarSales": { + "allOf": [ + { + "$ref": "#/components/schemas/Bazaar" + }, + { + "required": [ + "dollar_sales" + ], + "properties": { + "dollar_sales": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + ] + }, "ItemMarketListingItemBonus": { "required": [ "id", @@ -20413,11 +22631,13 @@ "description": "The following selections will fallback to API v1 and may change at any time: 'pointsmarket'.", "type": "string", "enum": [ + "bazaar", "itemmarket", + "properties", + "rentals", "lookup", "timestamp", - "pointsmarket", - "bazaar" + "pointsmarket" ] }, { @@ -20439,6 +22659,64 @@ }, "type": "object" }, + "UserRacingRecordsResponse": { + "required": [ + "racingrecords" + ], + "properties": { + "racingrecords": { + "type": "array", + "items": { + "required": [ + "track", + "records" + ], + "properties": { + "track": { + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/RaceTrackId" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "records": { + "type": "array", + "items": { + "required": [ + "car_id", + "car_name", + "lap_time" + ], + "properties": { + "car_id": { + "$ref": "#/components/schemas/ItemId" + }, + "car_name": { + "type": "string" + }, + "lap_time": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + } + } + }, + "type": "object" + } + } + }, + "type": "object" + }, "RacingCarsResponse": { "required": [ "cars" @@ -20674,7 +22952,8 @@ "laps", "participants", "schedule", - "requirements" + "requirements", + "is_official" ], "properties": { "id": { @@ -20804,6 +23083,9 @@ } }, "type": "object" + }, + "is_official": { + "type": "boolean" } }, "type": "object" @@ -20945,6 +23227,7 @@ }, { "required": [ + "is_official", "results" ], "properties": { @@ -20953,6 +23236,9 @@ "items": { "$ref": "#/components/schemas/RacerDetails" } + }, + "is_official": { + "type": "boolean" } }, "type": "object" @@ -20996,6 +23282,87 @@ }, "type": "object" }, + "PropertySelectionName": { + "oneOf": [ + { + "type": "string", + "enum": [ + "property", + "lookup", + "timestamp" + ] + }, + { + "type": "string" + } + ] + }, + "PropertyLookupResponse": { + "required": [ + "selections" + ], + "properties": { + "selections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertySelectionName" + } + } + }, + "type": "object" + }, + "TornProperties": { + "properties": { + "properties": { + "type": "array", + "items": { + "required": [ + "id", + "name", + "cost", + "happy", + "upkeep", + "modifications", + "staff" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/PropertyTypeId" + }, + "name": { + "type": "string" + }, + "cost": { + "type": "integer", + "format": "int32" + }, + "happy": { + "type": "integer", + "format": "int32" + }, + "upkeep": { + "type": "integer", + "format": "int32" + }, + "modifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyModificationEnum" + } + }, + "staff": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyStaffEnum" + } + } + }, + "type": "object" + } + } + }, + "type": "object" + }, "TornEducationRewards": { "required": [ "working_stats", @@ -21465,7 +23832,20 @@ "format": "int32" }, "value": { - "description": "Value representing the chosen category. Traveltime is shown in seconds. If the chosen category is 'rank', the value is of type string. If the chosen category is 'racingskill', the value is of type float. Otherwise it is an integer." + "description": "Value representing the chosen category. Traveltime is shown in seconds. If the chosen category is 'rank', the value is of type string. If the chosen category is 'racingskill', the value is of type float. Otherwise it is an integer.", + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "string" + }, + { + "type": "number", + "format": "float" + } + ] }, "rank": { "type": "string" @@ -22416,7 +24796,7 @@ "TornSelectionName": { "oneOf": [ { - "description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','dirtybombs','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','properties','raidreport','raids','rockpaperscissors','searchforcash','shoplifting','stats','stocks'.\n * The following selections are not available in API v2: 'chainreport', 'rackets', 'rankedwarreport', 'rankedwars', 'territorynames', 'territorywarreport', 'territorywars'.", + "description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','rockpaperscissors','searchforcash','shoplifting','stats','stocks'.\n * The following selections are not available in API v2: 'dirtybombs','raidreport','raids', 'chainreport', 'rackets', 'rankedwarreport', 'rankedwars', 'territorynames', 'territorywarreport', 'territorywars'.", "type": "string", "enum": [ "attacklog", @@ -22433,6 +24813,7 @@ "logcategories", "logtypes", "lookup", + "properties", "subcrimes", "territory", "timestamp", @@ -22441,7 +24822,6 @@ "cityshops", "companies", "competition", - "dirtybombs", "gyms", "honors", "itemdetails", @@ -22450,9 +24830,6 @@ "organisedcrimes", "pawnshop", "pokertables", - "properties", - "raidreport", - "raids", "rockpaperscissors", "searchforcash", "shoplifting", @@ -22612,6 +24989,18 @@ "minimum": 1 } }, + "ApiLimit50Default20": { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20, + "maximum": 50, + "minimum": 1 + } + }, "ApiLimit100": { "name": "limit", "in": "query", @@ -22834,6 +25223,10 @@ "name": "Forum", "description": "Part of Forum section" }, + { + "name": "Property", + "description": "Part of Property section" + }, { "name": "Key", "description": "Part of Key section"