From 1855c37bc88217cf2564429652d2ecbd6872d587 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:09:50 +0200 Subject: [PATCH 1/8] Template Changes for https://github.com/vrchatapi/specification/pull/601 --- templates/model.mustache | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/templates/model.mustache b/templates/model.mustache index 4c6c4106..b9aa6112 100644 --- a/templates/model.mustache +++ b/templates/model.mustache @@ -123,9 +123,10 @@ impl Default for {{classname}} { {{!-- for non-enum schemas --}} {{^isEnum}} {{^discriminator}} -{{#vendorExtensions.x-rust-has-byte-array}}#[serde_as] -{{/vendorExtensions.x-rust-has-byte-array}}{{#oneOf.isEmpty}}#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +{{^composedSchemas.allOf}}{{#vendorExtensions.x-rust-has-byte-array}}#[serde_as] +{{/vendorExtensions.x-rust-has-byte-array}}{{/composedSchemas.allOf}}{{#oneOf.isEmpty}}#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct {{{classname}}} { +{{^composedSchemas.allOf}} {{#vars}} {{#description}} /// {{{.}}} @@ -150,8 +151,14 @@ pub struct {{{classname}}} { ### Option End (and trailing comma) }}{{#isNullable}}>{{/isNullable}}{{^required}}>{{/required}}, {{/vars}} +{{/composedSchemas.allOf}} +{{#composedSchemas.allOf}} + #[serde(flatten)] + pub {{^title.isEmpty}}{{{title}}}{{/title.isEmpty}}{{#title.isEmpty}}{{{name}}}{{/title.isEmpty}}: {{{dataType}}}, +{{/composedSchemas.allOf}} } +{{^composedSchemas.allOf}} impl {{{classname}}} { {{#description}} /// {{{.}}} @@ -174,6 +181,7 @@ impl {{{classname}}} { } } } +{{/composedSchemas.allOf}} {{/oneOf.isEmpty}} {{^oneOf.isEmpty}} {{! TODO: add other vars that are not part of the oneOf}} From 4b9bf38ed91e7909838be1a785c7bac3d12980b3 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:16:26 +0200 Subject: [PATCH 2/8] Fix examples --- examples/cookies_load.rs | 4 ++-- examples/cookies_store.rs | 8 ++++---- examples/example.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/cookies_load.rs b/examples/cookies_load.rs index 0dc9d5e7..dfedcc05 100644 --- a/examples/cookies_load.rs +++ b/examples/cookies_load.rs @@ -31,10 +31,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::RegisterUserAccount200Response::CurrentUser(user) => { + ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::RegisterUserAccount200Response::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } diff --git a/examples/cookies_store.rs b/examples/cookies_store.rs index 863077b0..48cb57fb 100644 --- a/examples/cookies_store.rs +++ b/examples/cookies_store.rs @@ -18,10 +18,10 @@ async fn main() { .await .unwrap() { - ::vrchatapi::models::RegisterUserAccount200Response::CurrentUser(me) => { + ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::RegisterUserAccount200Response::RequiresTwoFactorAuth( + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth( requires_auth, ) => { if requires_auth @@ -56,10 +56,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::RegisterUserAccount200Response::CurrentUser(user) => { + ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::RegisterUserAccount200Response::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } diff --git a/examples/example.rs b/examples/example.rs index 0eacae38..48414053 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -7,10 +7,10 @@ async fn main() { .await .unwrap() { - ::vrchatapi::models::RegisterUserAccount200Response::CurrentUser(me) => { + ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::RegisterUserAccount200Response::RequiresTwoFactorAuth( + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth( requires_auth, ) => { if requires_auth @@ -45,10 +45,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::RegisterUserAccount200Response::CurrentUser(user) => { + ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::RegisterUserAccount200Response::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } From 3c9866d0abc1d7909c14e925b1e60d963860ecda Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:40:50 +0200 Subject: [PATCH 3/8] fmt --- examples/cookies_store.rs | 4 +--- examples/example.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/cookies_store.rs b/examples/cookies_store.rs index 48cb57fb..59adb936 100644 --- a/examples/cookies_store.rs +++ b/examples/cookies_store.rs @@ -21,9 +21,7 @@ async fn main() { ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth( - requires_auth, - ) => { + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(requires_auth) => { if requires_auth .requires_two_factor_auth .contains(&::vrchatapi::models::TwoFactorAuthType::EmailOtp) diff --git a/examples/example.rs b/examples/example.rs index 48414053..b0d8ff1d 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -10,9 +10,7 @@ async fn main() { ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth( - requires_auth, - ) => { + ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(requires_auth) => { if requires_auth .requires_two_factor_auth .contains(&::vrchatapi::models::TwoFactorAuthType::EmailOtp) From bcb5bffa99dd05a9b15bb53c7483627a52e71f75 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 22 Sep 2026 17:41:21 +0200 Subject: [PATCH 4/8] More robust template --- templates/model.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/model.mustache b/templates/model.mustache index b9aa6112..2a75d2f5 100644 --- a/templates/model.mustache +++ b/templates/model.mustache @@ -154,7 +154,7 @@ pub struct {{{classname}}} { {{/composedSchemas.allOf}} {{#composedSchemas.allOf}} #[serde(flatten)] - pub {{^title.isEmpty}}{{{title}}}{{/title.isEmpty}}{{#title.isEmpty}}{{{name}}}{{/title.isEmpty}}: {{{dataType}}}, + pub {{#title}}{{{title}}}{{/title}}{{^title}}{{{name}}}{{/title}}: {{{dataType}}}, {{/composedSchemas.allOf}} } From 116adf299c3f1e10d81fbe3ce8afd3f423682472 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 23 Sep 2026 18:49:10 +0200 Subject: [PATCH 5/8] Implement/Use https://github.com/C0D3-M4513R/specification/commit/db4c9c313f81d38722c2efd060a8aceb83d5c7a2 --- templates/model.mustache | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/templates/model.mustache b/templates/model.mustache index 2a75d2f5..5b356ec0 100644 --- a/templates/model.mustache +++ b/templates/model.mustache @@ -123,8 +123,12 @@ impl Default for {{classname}} { {{!-- for non-enum schemas --}} {{^isEnum}} {{^discriminator}} -{{^composedSchemas.allOf}}{{#vendorExtensions.x-rust-has-byte-array}}#[serde_as] -{{/vendorExtensions.x-rust-has-byte-array}}{{/composedSchemas.allOf}}{{#oneOf.isEmpty}}#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +{{^composedSchemas.allOf}}{{! +}}{{#vendorExtensions.x-rust-has-byte-array}}#[serde_as] +{{/vendorExtensions.x-rust-has-byte-array}}{{^vendorExtensions.x-rust-has-byte-array}}{{#vendorExtensions.x-vrcapispecification-has-double-json-encoding}}#[serde_with::serde_as] +{{/vendorExtensions.x-vrcapispecification-has-double-json-encoding}}{{/vendorExtensions.x-rust-has-byte-array}}{{! +}}{{/composedSchemas.allOf}}{{! +}}{{#oneOf.isEmpty}}#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct {{{classname}}} { {{^composedSchemas.allOf}} {{#vars}} @@ -134,6 +138,8 @@ pub struct {{{classname}}} { {{#isByteArray}} {{#vendorExtensions.isMandatory}}#[serde_as(as = "serde_with::base64::Base64")]{{/vendorExtensions.isMandatory}}{{^vendorExtensions.isMandatory}}#[serde_as(as = "{{^serdeAsDoubleOption}}Option{{/serdeAsDoubleOption}}{{#serdeAsDoubleOption}}super::DoubleOption{{/serdeAsDoubleOption}}")]{{/vendorExtensions.isMandatory}} {{/isByteArray}} + {{#vendorExtensions.x-vrcapispecification-inner-json}}#[serde_as(as = "serde_with::json::JsonString")] + {{/vendorExtensions.x-vrcapispecification-inner-json}} #[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default{{^isByteArray}}, with = "::serde_with::rust::double_option"{{/isByteArray}}{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})] pub {{{name}}}: {{! ### Option Start @@ -145,7 +151,9 @@ pub struct {{{classname}}} { ### Models }}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{! ### Primative datatypes + }}{{^vendorExtensions.x-vrcapispecification-inner-json}}{{! }}{{^isModel}}{{#isByteArray}}Vec{{/isByteArray}}{{^isByteArray}}{{{dataType}}}{{/isByteArray}}{{/isModel}}{{! + }}{{/vendorExtensions.x-vrcapispecification-inner-json}}{{#vendorExtensions.x-vrcapispecification-inner-json}}models::{{{vendorExtensions.x-vrcapispecification-inner-json}}}{{/vendorExtensions.x-vrcapispecification-inner-json}}{{! ### Non-Enums End }}{{/isEnum}}{{! ### Option End (and trailing comma) From 4214c05a05f4848baa4fa448c8f4aed3c63078ae Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 23 Sep 2026 20:14:27 +0200 Subject: [PATCH 6/8] Fix examples --- examples/cookies_load.rs | 4 ++-- examples/cookies_store.rs | 8 ++++---- examples/example.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/cookies_load.rs b/examples/cookies_load.rs index dfedcc05..177733ad 100644 --- a/examples/cookies_load.rs +++ b/examples/cookies_load.rs @@ -31,10 +31,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { + ::vrchatapi::models::CurrentUserLoginResponse::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::CurrentUserLoginResponse::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } diff --git a/examples/cookies_store.rs b/examples/cookies_store.rs index 59adb936..0af8dd65 100644 --- a/examples/cookies_store.rs +++ b/examples/cookies_store.rs @@ -18,10 +18,10 @@ async fn main() { .await .unwrap() { - ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { + ::vrchatapi::models::CurrentUserLoginResponse::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(requires_auth) => { + ::vrchatapi::models::CurrentUserLoginResponse::RequiresTwoFactorAuth(requires_auth) => { if requires_auth .requires_two_factor_auth .contains(&::vrchatapi::models::TwoFactorAuthType::EmailOtp) @@ -54,10 +54,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { + ::vrchatapi::models::CurrentUserLoginResponse::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::CurrentUserLoginResponse::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } diff --git a/examples/example.rs b/examples/example.rs index b0d8ff1d..5264a536 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -7,10 +7,10 @@ async fn main() { .await .unwrap() { - ::vrchatapi::models::LoginOr2fa::CurrentUser(me) => { + ::vrchatapi::models::CurrentUserLoginResponse::CurrentUser(me) => { println!("Username: {}", me.username.unwrap()) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(requires_auth) => { + ::vrchatapi::models::CurrentUserLoginResponse::RequiresTwoFactorAuth(requires_auth) => { if requires_auth .requires_two_factor_auth .contains(&::vrchatapi::models::TwoFactorAuthType::EmailOtp) @@ -43,10 +43,10 @@ async fn main() { .unwrap(); match user { - ::vrchatapi::models::LoginOr2fa::CurrentUser(user) => { + ::vrchatapi::models::CurrentUserLoginResponse::CurrentUser(user) => { println!("Current user: {}", user.display_name) } - ::vrchatapi::models::LoginOr2fa::RequiresTwoFactorAuth(_) => { + ::vrchatapi::models::CurrentUserLoginResponse::RequiresTwoFactorAuth(_) => { println!("cookie invalid") } } From d13b2ef210d40aae7f3c156a240e503f432f9435 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 23 Sep 2026 20:24:08 +0200 Subject: [PATCH 7/8] Use openapi-3.1 spec --- .github/workflows/ci.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ccf7088d..cc9ed340 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,7 +28,7 @@ name: CI env: PASSED_VERSION: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload || fromJSON(inputs.json || '{}'))['version'] }} - URL: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload || fromJSON(inputs.json || '{}'))['artifacts']['openapi.json'] }} + URL: ${{ (github.event_name == 'repository_dispatch' && github.event.client_payload || fromJSON(inputs.json || '{}'))['artifacts']['openapi-3.1.json'] }} VERSION_POSTPEND: ${{ github.event_name == 'workflow_dispatch' && inputs.version_postfix || '' }} jobs: @@ -44,6 +44,7 @@ jobs: - uses: vrchatapi/specification/.github/actions/download@main with: + bundle: openapi-3.1.json url: ${{ env.URL }} - if: env.PASSED_VERSION != '' From 5493b0b76a1b74e344c642a89a0488ca9bed3b00 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 23 Sep 2026 20:37:09 +0200 Subject: [PATCH 8/8] Change vendor-specific namings --- templates/model.mustache | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/model.mustache b/templates/model.mustache index 5b356ec0..17adc162 100644 --- a/templates/model.mustache +++ b/templates/model.mustache @@ -138,8 +138,8 @@ pub struct {{{classname}}} { {{#isByteArray}} {{#vendorExtensions.isMandatory}}#[serde_as(as = "serde_with::base64::Base64")]{{/vendorExtensions.isMandatory}}{{^vendorExtensions.isMandatory}}#[serde_as(as = "{{^serdeAsDoubleOption}}Option{{/serdeAsDoubleOption}}{{#serdeAsDoubleOption}}super::DoubleOption{{/serdeAsDoubleOption}}")]{{/vendorExtensions.isMandatory}} {{/isByteArray}} - {{#vendorExtensions.x-vrcapispecification-inner-json}}#[serde_as(as = "serde_with::json::JsonString")] - {{/vendorExtensions.x-vrcapispecification-inner-json}} + {{#vendorExtensions.x-double-encoding}}#[serde_as(as = "serde_with::json::JsonString")] + {{/vendorExtensions.x-double-encoding}} #[serde(rename = "{{{baseName}}}"{{^required}}{{#isNullable}}, default{{^isByteArray}}, with = "::serde_with::rust::double_option"{{/isByteArray}}{{/isNullable}}{{/required}}{{^required}}, skip_serializing_if = "Option::is_none"{{/required}}{{#required}}{{#isNullable}}, deserialize_with = "Option::deserialize"{{/isNullable}}{{/required}})] pub {{{name}}}: {{! ### Option Start @@ -151,9 +151,9 @@ pub struct {{{classname}}} { ### Models }}{{#isModel}}{{^avoidBoxedModels}}Box<{{/avoidBoxedModels}}{{{dataType}}}{{^avoidBoxedModels}}>{{/avoidBoxedModels}}{{/isModel}}{{! ### Primative datatypes - }}{{^vendorExtensions.x-vrcapispecification-inner-json}}{{! + }}{{^vendorExtensions.x-vrchat-double-encoding-type}}{{! }}{{^isModel}}{{#isByteArray}}Vec{{/isByteArray}}{{^isByteArray}}{{{dataType}}}{{/isByteArray}}{{/isModel}}{{! - }}{{/vendorExtensions.x-vrcapispecification-inner-json}}{{#vendorExtensions.x-vrcapispecification-inner-json}}models::{{{vendorExtensions.x-vrcapispecification-inner-json}}}{{/vendorExtensions.x-vrcapispecification-inner-json}}{{! + }}{{/vendorExtensions.x-vrchat-double-encoding-type}}{{#vendorExtensions.x-vrchat-double-encoding-type}}models::{{{vendorExtensions.x-vrchat-double-encoding-type}}}{{/vendorExtensions.x-vrchat-double-encoding-type}}{{! ### Non-Enums End }}{{/isEnum}}{{! ### Option End (and trailing comma)