From e54664ad6f8c7455954123447573cf33594a7982 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 12 Jun 2025 15:43:55 +0200 Subject: [PATCH 001/296] Upgrade schemars to 0.9 --- Cargo.lock | 40 +- Cargo.toml | 8 +- crates/config/src/bin/schema.rs | 13 +- crates/config/src/schema.rs | 27 +- crates/config/src/sections/http.rs | 22 +- crates/config/src/sections/secrets.rs | 6 +- crates/config/src/sections/telemetry.rs | 22 +- crates/handlers/src/admin/mod.rs | 7 +- crates/handlers/src/admin/schema.rs | 74 +- .../handlers/src/admin/v1/policy_data/set.rs | 2 +- .../src/admin/v1/users/set_password.rs | 6 +- crates/iana-codegen/src/generation.rs | 44 +- crates/iana/src/jose.rs | 1238 ++++--------- crates/iana/src/oauth.rs | 302 ++-- crates/policy/src/bin/schema.rs | 14 +- deny.toml | 2 - docs/api/spec.json | 1558 +++++++++++------ docs/config.schema.json | 1509 ++++++++-------- .../schema/authorization_grant_input.json | 21 +- .../schema/client_registration_input.json | 14 +- policies/schema/email_input.json | 14 +- policies/schema/register_input.json | 19 +- 22 files changed, 2412 insertions(+), 2550 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6dd7c2c7e..36b3ea8c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,9 +85,9 @@ dependencies = [ [[package]] name = "aide" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2477554ebf38aea815a9c4729100cfc32f766876c45b9c9c38ef221b9d1a703" +checksum = "4d34f0f6ce85b460bf2f9e7eea6612f217ba700ae14e9e476805d2413480f64b" dependencies = [ "aide-macros", "axum", @@ -108,11 +108,12 @@ dependencies = [ [[package]] name = "aide-macros" -version = "0.8.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8e0d4af7cc08353807aaf80722125a229bf2d67be7fe0b89163c648db3d223" +checksum = "9f2a08f14808f3c46f3e3004b727bace64af44c3c5996d0480a14d3852b1b25a" dependencies = [ "darling", + "proc-macro2", "quote", "syn", ] @@ -2812,7 +2813,6 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" dependencies = [ - "schemars", "serde", ] @@ -4970,6 +4970,26 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regalloc2" version = "0.11.2" @@ -5344,14 +5364,14 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.22" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" dependencies = [ "chrono", "dyn-clone", - "indexmap 1.9.3", "indexmap 2.9.0", + "ref-cast", "schemars_derive", "serde", "serde_json", @@ -5360,9 +5380,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.22" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +checksum = "5016d94c77c6d32f0b8e08b781f7dc8a90c2007d4e77472cc2807bc10a8438fe" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 68f867595..958ba8e3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,7 @@ syn2mas = { path = "./crates/syn2mas", version = "=0.17.0-rc.0" } # OpenAPI schema generation and validation [workspace.dependencies.aide] -version = "0.14.2" +version = "0.15.0" features = ["axum", "axum-extra", "axum-json", "axum-query", "macros"] # An `Arc` that can be atomically updated @@ -330,7 +330,7 @@ features = ["yaml", "json"] # IP network address types [workspace.dependencies.ipnetwork] version = "0.20.0" -features = ["serde", "schemars"] +features = ["serde"] # Iterator utilities [workspace.dependencies.itertools] @@ -531,8 +531,8 @@ version = "0.4.5" # JSON Schema generation [workspace.dependencies.schemars] -version = "0.8.22" -features = ["url", "chrono", "preserve_order"] +version = "0.9.0" +features = ["url2", "chrono04", "preserve_order"] # SEC1 encoding format [workspace.dependencies.sec1] diff --git a/crates/config/src/bin/schema.rs b/crates/config/src/bin/schema.rs index 3f409d406..401d52baa 100644 --- a/crates/config/src/bin/schema.rs +++ b/crates/config/src/bin/schema.rs @@ -4,14 +4,15 @@ // SPDX-License-Identifier: AGPL-3.0-only // Please see LICENSE in the repository root for full details. -use schemars::r#gen::SchemaSettings; +use schemars::{ + generate::SchemaSettings, + transform::{AddNullable, RecursiveTransform}, +}; fn main() { - let settings = SchemaSettings::draft07().with(|s| { - s.option_nullable = false; - s.option_add_null_type = false; - }); - let generator = settings.into_generator(); + let generator = SchemaSettings::draft07() + .with_transform(RecursiveTransform(AddNullable::default())) + .into_generator(); let schema = generator.into_root_schema_for::(); serde_json::to_writer_pretty(std::io::stdout(), &schema).expect("Failed to serialize schema"); diff --git a/crates/config/src/schema.rs b/crates/config/src/schema.rs index 2a9aaa914..537c0ffb6 100644 --- a/crates/config/src/schema.rs +++ b/crates/config/src/schema.rs @@ -6,29 +6,22 @@ //! Useful JSON Schema definitions -use schemars::{ - JsonSchema, - r#gen::SchemaGenerator, - schema::{InstanceType, Schema, SchemaObject}, -}; +use std::borrow::Cow; + +use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema}; /// A network hostname pub struct Hostname; impl JsonSchema for Hostname { - fn schema_name() -> String { - "Hostname".to_string() + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("Hostname") } - fn json_schema(generator: &mut SchemaGenerator) -> Schema { - hostname(generator) + fn json_schema(_generator: &mut SchemaGenerator) -> Schema { + json_schema!({ + "type": "string", + "format": "hostname", + }) } } - -fn hostname(_gen: &mut SchemaGenerator) -> Schema { - Schema::Object(SchemaObject { - instance_type: Some(InstanceType::String.into()), - format: Some("hostname".to_owned()), - ..SchemaObject::default() - }) -} diff --git a/crates/config/src/sections/http.rs b/crates/config/src/sections/http.rs index 8bf4a7588..1c11a8cbc 100644 --- a/crates/config/src/sections/http.rs +++ b/crates/config/src/sections/http.rs @@ -23,19 +23,6 @@ fn default_public_base() -> Url { "http://[::]:8080".parse().unwrap() } -fn http_address_example_1() -> &'static str { - "[::1]:8080" -} -fn http_address_example_2() -> &'static str { - "[::]:8080" -} -fn http_address_example_3() -> &'static str { - "127.0.0.1:8080" -} -fn http_address_example_4() -> &'static str { - "0.0.0.0:8080" -} - #[cfg(not(any(feature = "docker", feature = "dist")))] fn http_listener_assets_path_default() -> Utf8PathBuf { "./frontend/dist/".into() @@ -111,10 +98,10 @@ pub enum BindConfig { Address { /// Host and port on which to listen #[schemars( - example = "http_address_example_1", - example = "http_address_example_2", - example = "http_address_example_3", - example = "http_address_example_4" + example = &"[::1]:8080", + example = &"[::]:8080", + example = &"127.0.0.1:8080", + example = &"0.0.0.0:8080", )] address: String, }, @@ -354,6 +341,7 @@ pub struct HttpConfig { /// List of trusted reverse proxies that can set the `X-Forwarded-For` /// header #[serde(default = "default_trusted_proxies")] + #[schemars(with = "Vec", inner(ip))] pub trusted_proxies: Vec, /// Public URL base from where the authentication service is reachable diff --git a/crates/config/src/sections/secrets.rs b/crates/config/src/sections/secrets.rs index e93817b68..a28be9121 100644 --- a/crates/config/src/sections/secrets.rs +++ b/crates/config/src/sections/secrets.rs @@ -24,10 +24,6 @@ use tracing::info; use super::ConfigurationSection; -fn example_secret() -> &'static str { - "0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff" -} - /// Password config option. /// /// It either holds the password value directly or references a file where the @@ -204,7 +200,7 @@ struct EncryptionRaw { #[schemars( with = "Option", regex(pattern = r"[0-9a-fA-F]{64}"), - example = "example_secret" + example = &"0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff" )] #[serde_as(as = "Option")] #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/config/src/sections/telemetry.rs b/crates/config/src/sections/telemetry.rs index 0c11e0285..5b71b330e 100644 --- a/crates/config/src/sections/telemetry.rs +++ b/crates/config/src/sections/telemetry.rs @@ -11,10 +11,6 @@ use url::Url; use super::ConfigurationSection; -fn sample_rate_example() -> f64 { - 0.5 -} - /// Propagation format for incoming and outgoing requests #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "lowercase")] @@ -70,7 +66,7 @@ pub struct TracingConfig { /// /// Defaults to `1.0` if not set. #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))] + #[schemars(example = 0.5, range(min = 0.0, max = 1.0))] pub sample_rate: Option, } @@ -123,26 +119,18 @@ impl MetricsConfig { } } -fn sentry_dsn_example() -> &'static str { - "https://public@host:port/1" -} - -fn sentry_environment_example() -> &'static str { - "production" -} - /// Configuration related to the Sentry integration #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] pub struct SentryConfig { /// Sentry DSN - #[schemars(url, example = "sentry_dsn_example")] + #[schemars(url, example = &"https://public@host:port/1")] #[serde(skip_serializing_if = "Option::is_none")] pub dsn: Option, /// Environment to use when sending events to Sentry /// /// Defaults to `production` if not set. - #[schemars(example = "sentry_environment_example")] + #[schemars(example = &"production")] #[serde(skip_serializing_if = "Option::is_none")] pub environment: Option, @@ -150,14 +138,14 @@ pub struct SentryConfig { /// /// Defaults to `1.0` if not set. #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))] + #[schemars(example = 0.5, range(min = 0.0, max = 1.0))] pub sample_rate: Option, /// Sample rate for tracing transactions /// /// Defaults to `0.0` if not set. #[serde(skip_serializing_if = "Option::is_none")] - #[schemars(example = "sample_rate_example", range(min = 0.0, max = 1.0))] + #[schemars(example = 0.5, range(min = 0.0, max = 1.0))] pub traces_sample_rate: Option, } diff --git a/crates/handlers/src/admin/mod.rs b/crates/handlers/src/admin/mod.rs index 6890848ac..1938980dd 100644 --- a/crates/handlers/src/admin/mod.rs +++ b/crates/handlers/src/admin/mod.rs @@ -29,6 +29,7 @@ use mas_router::{ }; use mas_storage::BoxRng; use mas_templates::{ApiDocContext, Templates}; +use schemars::transform::{AddNullable, RecursiveTransform}; use tower_http::cors::{Any, CorsLayer}; mod call_context; @@ -159,8 +160,10 @@ where aide::generate::infer_responses(false); aide::generate::in_context(|ctx| { - ctx.schema = - schemars::r#gen::SchemaGenerator::new(schemars::r#gen::SchemaSettings::openapi3()); + ctx.schema = schemars::generate::SchemaGenerator::new( + schemars::generate::SchemaSettings::openapi3() + .with_transform(RecursiveTransform(AddNullable::default())), + ); }); let mut api = OpenApi::default(); diff --git a/crates/handlers/src/admin/schema.rs b/crates/handlers/src/admin/schema.rs index 99f1c20b7..2c50dcd26 100644 --- a/crates/handlers/src/admin/schema.rs +++ b/crates/handlers/src/admin/schema.rs @@ -6,11 +6,9 @@ //! Common schema definitions -use schemars::{ - JsonSchema, - r#gen::SchemaGenerator, - schema::{InstanceType, Metadata, Schema, SchemaObject, StringValidation}, -}; +use std::borrow::Cow; + +use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema}; /// A type to use for schema definitions of ULIDs /// @@ -18,32 +16,21 @@ use schemars::{ pub struct Ulid; impl JsonSchema for Ulid { - fn schema_name() -> String { - "ULID".to_owned() + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("ULID") } fn json_schema(_gen: &mut SchemaGenerator) -> Schema { - SchemaObject { - instance_type: Some(InstanceType::String.into()), - - metadata: Some(Box::new(Metadata { - title: Some("ULID".into()), - description: Some("A ULID as per https://github.com/ulid/spec".into()), - examples: vec![ - "01ARZ3NDEKTSV4RRFFQ69G5FAV".into(), - "01J41912SC8VGAQDD50F6APK91".into(), - ], - ..Metadata::default() - })), - - string: Some(Box::new(StringValidation { - pattern: Some(r"^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$".into()), - ..StringValidation::default() - })), - - ..SchemaObject::default() - } - .into() + json_schema!({ + "type": "string", + "title": "ULID", + "description": "A ULID as per https://github.com/ulid/spec", + "examples": [ + "01ARZ3NDEKTSV4RRFFQ69G5FAV", + "01J41912SC8VGAQDD50F6APK91", + ], + "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$", + }) } } @@ -53,27 +40,20 @@ impl JsonSchema for Ulid { pub struct Device; impl JsonSchema for Device { - fn schema_name() -> String { - "DeviceID".to_owned() + fn schema_name() -> Cow<'static, str> { + Cow::Borrowed("DeviceID") } fn json_schema(_gen: &mut SchemaGenerator) -> Schema { - SchemaObject { - instance_type: Some(InstanceType::String.into()), - - metadata: Some(Box::new(Metadata { - title: Some("Device ID".into()), - examples: vec!["AABBCCDDEE".into(), "FFGGHHIIJJ".into()], - ..Metadata::default() - })), - - string: Some(Box::new(StringValidation { - pattern: Some(r"^[A-Za-z0-9._~!$&'()*+,;=:&/-]+$".into()), - ..StringValidation::default() - })), - - ..SchemaObject::default() - } - .into() + json_schema!({ + "type": "string", + "title": "Device ID", + "description": "A device ID as per https://matrix.org/docs/spec/client_server/r0.6.0#device-ids", + "examples": [ + "AABBCCDDEE", + "FFGGHHIIJJ", + ], + "pattern": "^[A-Za-z0-9._~!$&'()*+,;=:&/-]+$", + }) } } diff --git a/crates/handlers/src/admin/v1/policy_data/set.rs b/crates/handlers/src/admin/v1/policy_data/set.rs index bc28e96e3..73dce7307 100644 --- a/crates/handlers/src/admin/v1/policy_data/set.rs +++ b/crates/handlers/src/admin/v1/policy_data/set.rs @@ -58,7 +58,7 @@ fn data_example() -> serde_json::Value { #[derive(Deserialize, JsonSchema)] #[serde(rename = "SetPolicyDataRequest")] pub struct SetPolicyDataRequest { - #[schemars(example = "data_example")] + #[schemars(example = data_example())] pub data: serde_json::Value, } diff --git a/crates/handlers/src/admin/v1/users/set_password.rs b/crates/handlers/src/admin/v1/users/set_password.rs index 06797c3f8..4de8acd73 100644 --- a/crates/handlers/src/admin/v1/users/set_password.rs +++ b/crates/handlers/src/admin/v1/users/set_password.rs @@ -55,16 +55,12 @@ impl IntoResponse for RouteError { } } -fn password_example() -> String { - "hunter2".to_owned() -} - /// # JSON payload for the `POST /api/admin/v1/users/:id/set-password` endpoint #[derive(Deserialize, JsonSchema)] #[schemars(rename = "SetUserPasswordRequest")] pub struct Request { /// The password to set for the user - #[schemars(example = "password_example")] + #[schemars(example = &"hunter2")] password: String, /// Skip the password complexity check diff --git a/crates/iana-codegen/src/generation.rs b/crates/iana-codegen/src/generation.rs index 82f67b05b..8558ef389 100644 --- a/crates/iana-codegen/src/generation.rs +++ b/crates/iana-codegen/src/generation.rs @@ -165,12 +165,12 @@ pub fn json_schema_impl( write!( f, r#"impl schemars::JsonSchema for {} {{ - fn schema_name() -> String {{ - "{}".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> {{ + std::borrow::Cow::Borrowed("{}") }} #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {{ + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema {{ let enums = vec!["#, section.key, section.key, )?; @@ -180,20 +180,14 @@ pub fn json_schema_impl( f, r" // --- - schemars::schema::SchemaObject {{", + schemars::json_schema!({{", )?; if let Some(description) = &member.description { write!( f, - r" - metadata: Some(Box::new(schemars::schema::Metadata {{ - description: Some( - // --- - {}.to_owned(), - ), - ..Default::default() - }})),", + r#" + "description": {},"#, raw_string(description), )?; } @@ -201,34 +195,24 @@ pub fn json_schema_impl( write!( f, r#" - const_value: Some("{}".into()), - ..Default::default() - }} - .into(),"#, + "const": "{}", + }}),"#, member.value )?; } writeln!( f, - r" + r#" ]; let description = {}; - schemars::schema::SchemaObject {{ - metadata: Some(Box::new(schemars::schema::Metadata {{ - description: Some(description.to_owned()), - ..Default::default() - }})), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation {{ - any_of: Some(enums), - ..Default::default() - }})), - ..Default::default() - }} - .into() + schemars::json_schema!({{ + "description": description, + "anyOf": enums, + }}) }} -}}", +}}"#, raw_string(section.doc), ) } diff --git a/crates/iana/src/jose.rs b/crates/iana/src/jose.rs index 8ffc395ca..5f9a84ce4 100644 --- a/crates/iana/src/jose.rs +++ b/crates/iana/src/jose.rs @@ -144,249 +144,105 @@ impl serde::Serialize for JsonWebSignatureAlg { } impl schemars::JsonSchema for JsonWebSignatureAlg { - fn schema_name() -> String { - "JsonWebSignatureAlg".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebSignatureAlg") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"HMAC using SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("HS256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"HMAC using SHA-256", + "const": "HS256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"HMAC using SHA-384".to_owned(), - ), - ..Default::default() - })), - const_value: Some("HS384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"HMAC using SHA-384", + "const": "HS384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"HMAC using SHA-512".to_owned(), - ), - ..Default::default() - })), - const_value: Some("HS512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"HMAC using SHA-512", + "const": "HS512", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PKCS1-v1_5 using SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RS256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PKCS1-v1_5 using SHA-256", + "const": "RS256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PKCS1-v1_5 using SHA-384".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RS384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PKCS1-v1_5 using SHA-384", + "const": "RS384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PKCS1-v1_5 using SHA-512".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RS512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PKCS1-v1_5 using SHA-512", + "const": "RS512", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"ECDSA using P-256 and SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("ES256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"ECDSA using P-256 and SHA-256", + "const": "ES256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"ECDSA using P-384 and SHA-384".to_owned(), - ), - ..Default::default() - })), - const_value: Some("ES384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"ECDSA using P-384 and SHA-384", + "const": "ES384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"ECDSA using P-521 and SHA-512".to_owned(), - ), - ..Default::default() - })), - const_value: Some("ES512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"ECDSA using P-521 and SHA-512", + "const": "ES512", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PSS using SHA-256 and MGF1 with SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("PS256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PSS using SHA-256 and MGF1 with SHA-256", + "const": "PS256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PSS using SHA-384 and MGF1 with SHA-384".to_owned(), - ), - ..Default::default() - })), - const_value: Some("PS384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PSS using SHA-384 and MGF1 with SHA-384", + "const": "PS384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSASSA-PSS using SHA-512 and MGF1 with SHA-512".to_owned(), - ), - ..Default::default() - })), - const_value: Some("PS512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSASSA-PSS using SHA-512 and MGF1 with SHA-512", + "const": "PS512", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"No digital signature or MAC performed".to_owned(), - ), - ..Default::default() - })), - const_value: Some("none".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"No digital signature or MAC performed", + "const": "none", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"EdDSA signature algorithms".to_owned(), - ), - ..Default::default() - })), - const_value: Some("EdDSA".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"EdDSA signature algorithms", + "const": "EdDSA", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"ECDSA using secp256k1 curve and SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("ES256K".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"ECDSA using secp256k1 curve and SHA-256", + "const": "ES256K", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"EdDSA using Ed25519 curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("Ed25519".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"EdDSA using Ed25519 curve", + "const": "Ed25519", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"EdDSA using Ed448 curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("Ed448".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"EdDSA using Ed448 curve", + "const": "Ed448", + }), ]; let description = r#"JSON Web Signature "alg" parameter"#; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -533,275 +389,115 @@ impl serde::Serialize for JsonWebEncryptionAlg { } impl schemars::JsonSchema for JsonWebEncryptionAlg { - fn schema_name() -> String { - "JsonWebEncryptionAlg".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebEncryptionAlg") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSAES-PKCS1-v1_5".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA1_5".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSAES-PKCS1-v1_5", + "const": "RSA1_5", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSAES OAEP using default parameters".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA-OAEP".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSAES OAEP using default parameters", + "const": "RSA-OAEP", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSAES OAEP using SHA-256 and MGF1 with SHA-256".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA-OAEP-256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSAES OAEP using SHA-256 and MGF1 with SHA-256", + "const": "RSA-OAEP-256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES Key Wrap using 128-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A128KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES Key Wrap using 128-bit key", + "const": "A128KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES Key Wrap using 192-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A192KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES Key Wrap using 192-bit key", + "const": "A192KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES Key Wrap using 256-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A256KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES Key Wrap using 256-bit key", + "const": "A256KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Direct use of a shared symmetric key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("dir".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Direct use of a shared symmetric key", + "const": "dir", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"ECDH-ES using Concat KDF".to_owned(), - ), - ..Default::default() - })), - const_value: Some("ECDH-ES".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"ECDH-ES using Concat KDF", + "const": "ECDH-ES", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"ECDH-ES using Concat KDF and "A128KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("ECDH-ES+A128KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"ECDH-ES using Concat KDF and "A128KW" wrapping"#, + "const": "ECDH-ES+A128KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"ECDH-ES using Concat KDF and "A192KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("ECDH-ES+A192KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"ECDH-ES using Concat KDF and "A192KW" wrapping"#, + "const": "ECDH-ES+A192KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"ECDH-ES using Concat KDF and "A256KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("ECDH-ES+A256KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"ECDH-ES using Concat KDF and "A256KW" wrapping"#, + "const": "ECDH-ES+A256KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Key wrapping with AES GCM using 128-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A128GCMKW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Key wrapping with AES GCM using 128-bit key", + "const": "A128GCMKW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Key wrapping with AES GCM using 192-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A192GCMKW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Key wrapping with AES GCM using 192-bit key", + "const": "A192GCMKW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Key wrapping with AES GCM using 256-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A256GCMKW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Key wrapping with AES GCM using 256-bit key", + "const": "A256GCMKW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"PBES2 with HMAC SHA-256 and "A128KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("PBES2-HS256+A128KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"PBES2 with HMAC SHA-256 and "A128KW" wrapping"#, + "const": "PBES2-HS256+A128KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"PBES2 with HMAC SHA-384 and "A192KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("PBES2-HS384+A192KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"PBES2 with HMAC SHA-384 and "A192KW" wrapping"#, + "const": "PBES2-HS384+A192KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r#"PBES2 with HMAC SHA-512 and "A256KW" wrapping"#.to_owned(), - ), - ..Default::default() - })), - const_value: Some("PBES2-HS512+A256KW".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r#"PBES2 with HMAC SHA-512 and "A256KW" wrapping"#, + "const": "PBES2-HS512+A256KW", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSA-OAEP using SHA-384 and MGF1 with SHA-384".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA-OAEP-384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSA-OAEP using SHA-384 and MGF1 with SHA-384", + "const": "RSA-OAEP-384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSA-OAEP using SHA-512 and MGF1 with SHA-512".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA-OAEP-512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSA-OAEP using SHA-512 and MGF1 with SHA-512", + "const": "RSA-OAEP-512", + }), ]; let description = r#"JSON Web Encryption "alg" parameter"#; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -883,106 +579,50 @@ impl serde::Serialize for JsonWebEncryptionEnc { } impl schemars::JsonSchema for JsonWebEncryptionEnc { - fn schema_name() -> String { - "JsonWebEncryptionEnc".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebEncryptionEnc") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A128CBC-HS256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES_128_CBC_HMAC_SHA_256 authenticated encryption algorithm", + "const": "A128CBC-HS256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A192CBC-HS384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES_192_CBC_HMAC_SHA_384 authenticated encryption algorithm", + "const": "A192CBC-HS384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A256CBC-HS512".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES_256_CBC_HMAC_SHA_512 authenticated encryption algorithm", + "const": "A256CBC-HS512", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES GCM using 128-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A128GCM".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES GCM using 128-bit key", + "const": "A128GCM", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES GCM using 192-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A192GCM".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES GCM using 192-bit key", + "const": "A192GCM", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"AES GCM using 256-bit key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("A256GCM".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"AES GCM using 256-bit key", + "const": "A256GCM", + }), ]; let description = r#"JSON Web Encryption "enc" parameter"#; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1039,41 +679,25 @@ impl serde::Serialize for JsonWebEncryptionCompressionAlgorithm { } impl schemars::JsonSchema for JsonWebEncryptionCompressionAlgorithm { - fn schema_name() -> String { - "JsonWebEncryptionCompressionAlgorithm".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebEncryptionCompressionAlgorithm") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"DEFLATE".to_owned(), - ), - ..Default::default() - })), - const_value: Some("DEF".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"DEFLATE", + "const": "DEF", + }), ]; let description = r"JSON Web Encryption Compression Algorithm"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1145,80 +769,40 @@ impl serde::Serialize for JsonWebKeyType { } impl schemars::JsonSchema for JsonWebKeyType { - fn schema_name() -> String { - "JsonWebKeyType".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebKeyType") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Elliptic Curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("EC".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Elliptic Curve", + "const": "EC", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"RSA".to_owned(), - ), - ..Default::default() - })), - const_value: Some("RSA".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"RSA", + "const": "RSA", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Octet sequence".to_owned(), - ), - ..Default::default() - })), - const_value: Some("oct".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Octet sequence", + "const": "oct", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Octet string key pairs".to_owned(), - ), - ..Default::default() - })), - const_value: Some("OKP".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Octet string key pairs", + "const": "OKP", + }), ]; let description = r"JSON Web Key Type"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1290,80 +874,40 @@ impl serde::Serialize for JsonWebKeyEcEllipticCurve { } impl schemars::JsonSchema for JsonWebKeyEcEllipticCurve { - fn schema_name() -> String { - "JsonWebKeyEcEllipticCurve".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebKeyEcEllipticCurve") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"P-256 Curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("P-256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"P-256 Curve", + "const": "P-256", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"P-384 Curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("P-384".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"P-384 Curve", + "const": "P-384", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"P-521 Curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("P-521".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"P-521 Curve", + "const": "P-521", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"SECG secp256k1 curve".to_owned(), - ), - ..Default::default() - })), - const_value: Some("secp256k1".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"SECG secp256k1 curve", + "const": "secp256k1", + }), ]; let description = r"JSON Web Key EC Elliptic Curve"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1435,80 +979,40 @@ impl serde::Serialize for JsonWebKeyOkpEllipticCurve { } impl schemars::JsonSchema for JsonWebKeyOkpEllipticCurve { - fn schema_name() -> String { - "JsonWebKeyOkpEllipticCurve".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebKeyOkpEllipticCurve") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Ed25519 signature algorithm key pairs".to_owned(), - ), - ..Default::default() - })), - const_value: Some("Ed25519".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Ed25519 signature algorithm key pairs", + "const": "Ed25519", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Ed448 signature algorithm key pairs".to_owned(), - ), - ..Default::default() - })), - const_value: Some("Ed448".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Ed448 signature algorithm key pairs", + "const": "Ed448", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"X25519 function key pairs".to_owned(), - ), - ..Default::default() - })), - const_value: Some("X25519".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"X25519 function key pairs", + "const": "X25519", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"X448 function key pairs".to_owned(), - ), - ..Default::default() - })), - const_value: Some("X448".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"X448 function key pairs", + "const": "X448", + }), ]; let description = r"JSON Web Key OKP Elliptic Curve"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1570,54 +1074,30 @@ impl serde::Serialize for JsonWebKeyUse { } impl schemars::JsonSchema for JsonWebKeyUse { - fn schema_name() -> String { - "JsonWebKeyUse".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebKeyUse") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Digital Signature or MAC".to_owned(), - ), - ..Default::default() - })), - const_value: Some("sig".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Digital Signature or MAC", + "const": "sig", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Encryption".to_owned(), - ), - ..Default::default() - })), - const_value: Some("enc".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Encryption", + "const": "enc", + }), ]; let description = r"JSON Web Key Use"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -1709,131 +1189,59 @@ impl serde::Serialize for JsonWebKeyOperation { } impl schemars::JsonSchema for JsonWebKeyOperation { - fn schema_name() -> String { - "JsonWebKeyOperation".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("JsonWebKeyOperation") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Compute digital signature or MAC".to_owned(), - ), - ..Default::default() - })), - const_value: Some("sign".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Compute digital signature or MAC", + "const": "sign", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Verify digital signature or MAC".to_owned(), - ), - ..Default::default() - })), - const_value: Some("verify".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Verify digital signature or MAC", + "const": "verify", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Encrypt content".to_owned(), - ), - ..Default::default() - })), - const_value: Some("encrypt".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Encrypt content", + "const": "encrypt", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Decrypt content and validate decryption, if applicable".to_owned(), - ), - ..Default::default() - })), - const_value: Some("decrypt".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Decrypt content and validate decryption, if applicable", + "const": "decrypt", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Encrypt key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("wrapKey".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Encrypt key", + "const": "wrapKey", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Decrypt key and validate decryption, if applicable".to_owned(), - ), - ..Default::default() - })), - const_value: Some("unwrapKey".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Decrypt key and validate decryption, if applicable", + "const": "unwrapKey", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Derive key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("deriveKey".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Derive key", + "const": "deriveKey", + }), // --- - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some( - // --- - r"Derive bits not to be used as a key".to_owned(), - ), - ..Default::default() - })), - const_value: Some("deriveBits".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "description": r"Derive bits not to be used as a key", + "const": "deriveBits", + }), ]; let description = r"JSON Web Key Operation"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } diff --git a/crates/iana/src/oauth.rs b/crates/iana/src/oauth.rs index 530e4bd7b..e1835e16c 100644 --- a/crates/iana/src/oauth.rs +++ b/crates/iana/src/oauth.rs @@ -79,52 +79,36 @@ impl serde::Serialize for OAuthAccessTokenType { } impl schemars::JsonSchema for OAuthAccessTokenType { - fn schema_name() -> String { - "OAuthAccessTokenType".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("OAuthAccessTokenType") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - const_value: Some("Bearer".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "Bearer", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("N_A".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "N_A", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("PoP".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "PoP", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("DPoP".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "DPoP", + }), ]; let description = r"OAuth Access Token Type"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -211,76 +195,52 @@ impl serde::Serialize for OAuthAuthorizationEndpointResponseType { } impl schemars::JsonSchema for OAuthAuthorizationEndpointResponseType { - fn schema_name() -> String { - "OAuthAuthorizationEndpointResponseType".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("OAuthAuthorizationEndpointResponseType") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - const_value: Some("code".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "code", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("code id_token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "code id_token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("code id_token token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "code id_token token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("code token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "code token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("id_token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "id_token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("id_token token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "id_token token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("none".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "none", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "token", + }), ]; let description = r"OAuth Authorization Endpoint Response Type"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -347,46 +307,32 @@ impl serde::Serialize for OAuthTokenTypeHint { } impl schemars::JsonSchema for OAuthTokenTypeHint { - fn schema_name() -> String { - "OAuthTokenTypeHint".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("OAuthTokenTypeHint") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - const_value: Some("access_token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "access_token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("refresh_token".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "refresh_token", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("pct".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "pct", + }), ]; let description = r"OAuth Token Type Hint"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -473,70 +419,48 @@ impl serde::Serialize for OAuthClientAuthenticationMethod { } impl schemars::JsonSchema for OAuthClientAuthenticationMethod { - fn schema_name() -> String { - "OAuthClientAuthenticationMethod".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("OAuthClientAuthenticationMethod") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - const_value: Some("none".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "none", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("client_secret_post".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "client_secret_post", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("client_secret_basic".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "client_secret_basic", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("client_secret_jwt".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "client_secret_jwt", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("private_key_jwt".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "private_key_jwt", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("tls_client_auth".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "tls_client_auth", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("self_signed_tls_client_auth".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "self_signed_tls_client_auth", + }), ]; let description = r"OAuth Token Endpoint Authentication Method"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } @@ -598,39 +522,27 @@ impl serde::Serialize for PkceCodeChallengeMethod { } impl schemars::JsonSchema for PkceCodeChallengeMethod { - fn schema_name() -> String { - "PkceCodeChallengeMethod".to_owned() + fn schema_name() -> std::borrow::Cow<'static, str> { + std::borrow::Cow::Borrowed("PkceCodeChallengeMethod") } #[allow(clippy::too_many_lines)] - fn json_schema(_gen: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema { + fn json_schema(_gen: &mut schemars::SchemaGenerator) -> schemars::Schema { let enums = vec![ // --- - schemars::schema::SchemaObject { - const_value: Some("plain".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "plain", + }), // --- - schemars::schema::SchemaObject { - const_value: Some("S256".into()), - ..Default::default() - } - .into(), + schemars::json_schema!({ + "const": "S256", + }), ]; let description = r"PKCE Code Challenge Method"; - schemars::schema::SchemaObject { - metadata: Some(Box::new(schemars::schema::Metadata { - description: Some(description.to_owned()), - ..Default::default() - })), - subschemas: Some(Box::new(schemars::schema::SubschemaValidation { - any_of: Some(enums), - ..Default::default() - })), - ..Default::default() - } - .into() + schemars::json_schema!({ + "description": description, + "anyOf": enums, + }) } } diff --git a/crates/policy/src/bin/schema.rs b/crates/policy/src/bin/schema.rs index 3fbe09adb..a07919276 100644 --- a/crates/policy/src/bin/schema.rs +++ b/crates/policy/src/bin/schema.rs @@ -14,7 +14,11 @@ use std::path::{Path, PathBuf}; use mas_policy::model::{ AuthorizationGrantInput, ClientRegistrationInput, EmailInput, RegisterInput, }; -use schemars::{JsonSchema, r#gen::SchemaSettings}; +use schemars::{ + JsonSchema, + generate::SchemaSettings, + transform::{AddNullable, RecursiveTransform}, +}; fn write_schema(out_dir: Option<&Path>, file: &str) { let mut writer: Box = if let Some(out_dir) = out_dir { @@ -27,11 +31,9 @@ fn write_schema(out_dir: Option<&Path>, file: &str) { Box::new(std::io::stdout()) }; - let settings = SchemaSettings::draft07().with(|s| { - s.option_nullable = false; - s.option_add_null_type = false; - }); - let generator = settings.into_generator(); + let generator = SchemaSettings::draft07() + .with_transform(RecursiveTransform(AddNullable::default())) + .into_generator(); let schema = generator.into_root_schema_for::(); serde_json::to_writer_pretty(&mut writer, &schema).expect("Failed to serialize schema"); writer.flush().expect("Failed to flush writer"); diff --git a/deny.toml b/deny.toml index 152c525e5..6d69a4b38 100644 --- a/deny.toml +++ b/deny.toml @@ -60,8 +60,6 @@ skip = [ { name = "regex-syntax", version = "0.6.29" }, # tracing-subscriber[env-filter] -> matchers depends on the old version { name = "regex-automata", version = "0.1.10" }, # ^ { name = "itertools", version = "0.13.0" }, # zxcvbn depends on this old version - { name = "indexmap", version = "1.9.3" }, # schemars depends on this old version - { name = "hashbrown", version = "0.12.3" }, # schemars -> indexmap depends on this old version { name = "hashbrown", version = "0.14.5" }, # a few crates depend on this old version # a few dependencies depend on the 1.x version of thiserror { name = "thiserror", version = "1.0.69" }, diff --git a/docs/api/spec.json b/docs/api/spec.json index 0082ea37c..c5d6c6fbd 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -31,8 +31,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -42,8 +48,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -53,10 +65,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -66,10 +80,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -79,8 +95,14 @@ "description": "Retrieve the items for the given user", "schema": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -90,19 +112,31 @@ "description": "Retrieve the items started from the given browser session", "schema": { "description": "Retrieve the items started from the given browser session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, { "in": "query", "name": "filter[status]", - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", "schema": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/CompatSessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/CompatSessionStatus" + }, + { + "type": "null" + } + ] }, "style": "form" } @@ -297,8 +331,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -308,8 +348,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -319,10 +365,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -332,10 +380,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -345,8 +395,14 @@ "description": "Retrieve the items for the given user", "schema": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -356,8 +412,14 @@ "description": "Retrieve the items for the given client", "schema": { "description": "Retrieve the items for the given client", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -367,8 +429,14 @@ "description": "Retrieve the items only for a specific client kind", "schema": { "description": "Retrieve the items only for a specific client kind", - "$ref": "#/components/schemas/OAuth2ClientKind", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/OAuth2ClientKind" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -378,8 +446,14 @@ "description": "Retrieve the items started from the given browser session", "schema": { "description": "Retrieve the items started from the given browser session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -389,22 +463,28 @@ "description": "Retrieve the items with the given scope", "schema": { "description": "Retrieve the items with the given scope", - "default": [], "type": "array", "items": { "type": "string" - } + }, + "default": [] }, "style": "form" }, { "in": "query", "name": "filter[status]", - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", "schema": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/OAuth2SessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/OAuth2SessionStatus" + }, + { + "type": "null" + } + ] }, "style": "form" } @@ -817,8 +897,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -828,8 +914,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -839,10 +931,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -852,10 +946,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -865,19 +961,27 @@ "description": "Retrieve users with (or without) the `admin` flag set", "schema": { "description": "Retrieve users with (or without) the `admin` flag set", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "style": "form" }, { "in": "query", "name": "filter[status]", - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users (includes deactivated users)\n\n* `deactivated`: Only retrieve deactivated users", + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all users, including locked ones.\n\n * `active`: Only retrieve active users\n\n * `locked`: Only retrieve locked users (includes deactivated users)\n\n * `deactivated`: Only retrieve deactivated users", "schema": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users (includes deactivated users)\n\n* `deactivated`: Only retrieve deactivated users", - "$ref": "#/components/schemas/UserStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all users, including locked ones.\n\n * `active`: Only retrieve active users\n\n * `locked`: Only retrieve locked users (includes deactivated users)\n\n * `deactivated`: Only retrieve deactivated users", + "anyOf": [ + { + "$ref": "#/components/schemas/UserStatus" + }, + { + "type": "null" + } + ] }, "style": "form" } @@ -1563,8 +1667,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -1574,8 +1684,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -1585,10 +1701,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -1598,10 +1716,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -1611,8 +1731,14 @@ "description": "Retrieve the items for the given user", "schema": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -1622,8 +1748,10 @@ "description": "Retrieve the user email with the given email address", "schema": { "description": "Retrieve the user email with the given email address", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "style": "form" } @@ -1908,8 +2036,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -1919,8 +2053,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -1930,10 +2070,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -1943,10 +2085,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -1956,19 +2100,31 @@ "description": "Retrieve the items for the given user", "schema": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, { "in": "query", "name": "filter[status]", - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", "schema": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/UserSessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/UserSessionStatus" + }, + { + "type": "null" + } + ] }, "style": "form" } @@ -2146,8 +2302,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2157,8 +2319,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2168,10 +2336,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -2181,10 +2351,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -2194,8 +2366,10 @@ "description": "Retrieve tokens that have (or have not) been used at least once", "schema": { "description": "Retrieve tokens that have (or have not) been used at least once", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "style": "form" }, @@ -2205,8 +2379,10 @@ "description": "Retrieve tokens that are (or are not) revoked", "schema": { "description": "Retrieve tokens that are (or are not) revoked", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "style": "form" }, @@ -2216,19 +2392,23 @@ "description": "Retrieve tokens that are (or are not) expired", "schema": { "description": "Retrieve tokens that are (or are not) expired", - "type": "boolean", - "nullable": true + "type": [ + "boolean", + "null" + ] }, "style": "form" }, { "in": "query", "name": "filter[valid]", - "description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.", + "description": "Retrieve tokens that are (or are not) valid\n\n Valid means that the token has not expired, is not revoked, and has not\n reached its usage limit.", "schema": { - "description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.", - "type": "boolean", - "nullable": true + "description": "Retrieve tokens that are (or are not) valid\n\n Valid means that the token has not expired, is not revoked, and has not\n reached its usage limit.", + "type": [ + "boolean", + "null" + ] }, "style": "form" } @@ -2693,8 +2873,14 @@ "description": "Retrieve the items before the given ID", "schema": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2704,8 +2890,14 @@ "description": "Retrieve the items after the given ID", "schema": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2715,10 +2907,12 @@ "description": "Retrieve the first N items", "schema": { "description": "Retrieve the first N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -2728,10 +2922,12 @@ "description": "Retrieve the last N items", "schema": { "description": "Retrieve the last N items", - "type": "integer", + "type": [ + "integer", + "null" + ], "format": "uint", - "minimum": 1.0, - "nullable": true + "minimum": 1 }, "style": "form" }, @@ -2741,8 +2937,14 @@ "description": "Retrieve the items for the given user", "schema": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2752,8 +2954,14 @@ "description": "Retrieve the items for the given provider", "schema": { "description": "Retrieve the items for the given provider", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "type": "null" + } + ] }, "style": "form" }, @@ -2763,8 +2971,10 @@ "description": "Retrieve the items with the given subject", "schema": { "description": "Retrieve the items with the given subject", - "type": "string", - "nullable": true + "type": [ + "string", + "null" + ] }, "style": "form" } @@ -3111,26 +3321,44 @@ "properties": { "page[before]": { "description": "Retrieve the items before the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "page[after]": { "description": "Retrieve the items after the given ID", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "page[first]": { "description": "Retrieve the first N items", "type": "integer", "format": "uint", - "minimum": 1.0, + "minimum": 1, "nullable": true }, "page[last]": { "description": "Retrieve the last N items", "type": "integer", "format": "uint", - "minimum": 1.0, + "minimum": 1, "nullable": true } } @@ -3138,30 +3366,54 @@ "ULID": { "title": "ULID", "description": "A ULID as per https://github.com/ulid/spec", - "examples": [ - "01ARZ3NDEKTSV4RRFFQ69G5FAV", - "01J41912SC8VGAQDD50F6APK91" - ], "type": "string", - "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$" + "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$", + "example": "01ARZ3NDEKTSV4RRFFQ69G5FAV" }, "CompatSessionFilter": { "type": "object", "properties": { "filter[user]": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[user-session]": { "description": "Retrieve the items started from the given browser session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[status]": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/CompatSessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/CompatSessionStatus" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] } } }, @@ -3175,15 +3427,14 @@ "PaginatedResponse_for_CompatSession": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -3194,33 +3445,36 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "PaginationMeta": { "type": "object", - "required": [ - "count" - ], "properties": { "count": { "description": "The total number of results", "type": "integer", "format": "uint", - "minimum": 0.0 + "minimum": 0 } - } + }, + "required": [ + "count" + ] }, "SingleResource_for_CompatSession": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -3228,39 +3482,63 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/CompatSession" + "allOf": [ + { + "$ref": "#/components/schemas/CompatSession" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "CompatSession": { "description": "A compatibility session for legacy clients", "type": "object", - "required": [ - "created_at", - "device_id", - "user_id", - "user_session_id" - ], "properties": { "user_id": { "description": "The ID of the user that owns this session", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "device_id": { "description": "The Matrix device ID of this session", - "$ref": "#/components/schemas/DeviceID" + "allOf": [ + { + "$ref": "#/components/schemas/DeviceID" + } + ] }, "user_session_id": { "description": "The ID of the user session that started this session, if any", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "redirect_uri": { "description": "The redirect URI used to login in the client, if it was an SSO login", @@ -3301,38 +3579,37 @@ "type": "string", "nullable": true } - } + }, + "required": [ + "user_id", + "device_id", + "user_session_id", + "created_at" + ] }, "DeviceID": { "title": "Device ID", - "examples": [ - "AABBCCDDEE", - "FFGGHHIIJJ" - ], + "description": "A device ID as per https://matrix.org/docs/spec/client_server/r0.6.0#device-ids", "type": "string", - "pattern": "^[A-Za-z0-9._~!$&'()*+,;=:&/-]+$" + "pattern": "^[A-Za-z0-9._~!$&'()*+,;=:&/-]+$", + "example": "AABBCCDDEE" }, "SelfLinks": { "description": "Related links", "type": "object", - "required": [ - "self" - ], "properties": { "self": { "description": "The canonical link to the current resource", "type": "string" } - } + }, + "required": [ + "self" + ] }, "PaginationLinks": { "description": "Related links", "type": "object", - "required": [ - "first", - "last", - "self" - ], "properties": { "self": { "description": "The canonical link to the current page", @@ -3347,23 +3624,25 @@ "type": "string" }, "next": { - "description": "The link to the next page of results\n\nOnly present if there is a next page", + "description": "The link to the next page of results\n\n Only present if there is a next page", "type": "string", "nullable": true }, "prev": { - "description": "The link to the previous page of results\n\nOnly present if there is a previous page", + "description": "The link to the previous page of results\n\n Only present if there is a previous page", "type": "string", "nullable": true } - } + }, + "required": [ + "self", + "first", + "last" + ] }, "ErrorResponse": { "description": "A top-level response with a list of errors", "type": "object", - "required": [ - "errors" - ], "properties": { "errors": { "description": "The list of errors", @@ -3372,40 +3651,43 @@ "$ref": "#/components/schemas/Error" } } - } + }, + "required": [ + "errors" + ] }, "Error": { "description": "A single error", "type": "object", - "required": [ - "title" - ], "properties": { "title": { "description": "A human-readable title for the error", "type": "string" } - } + }, + "required": [ + "title" + ] }, "UlidInPath": { "type": "object", - "required": [ - "id" - ], "properties": { "id": { "title": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] } - } + }, + "required": [ + "id" + ] }, "SingleResponse_for_CompatSession": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_CompatSession" @@ -3413,43 +3695,92 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "OAuth2SessionFilter": { "type": "object", "properties": { "filter[user]": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[client]": { "description": "Retrieve the items for the given client", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[client-kind]": { "description": "Retrieve the items only for a specific client kind", - "$ref": "#/components/schemas/OAuth2ClientKind", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/OAuth2ClientKind" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[user-session]": { "description": "Retrieve the items started from the given browser session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[scope]": { "description": "Retrieve the items with the given scope", - "default": [], "type": "array", "items": { "type": "string" - } + }, + "default": [] }, "filter[status]": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/OAuth2SessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/OAuth2SessionStatus" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] } } }, @@ -3470,15 +3801,14 @@ "PaginatedResponse_for_OAuth2Session": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -3489,19 +3819,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_OAuth2Session": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -3509,26 +3842,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/OAuth2Session" + "allOf": [ + { + "$ref": "#/components/schemas/OAuth2Session" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "OAuth2Session": { "description": "A OAuth 2.0 session", "type": "object", - "required": [ - "client_id", - "created_at", - "scope" - ], "properties": { "created_at": { "description": "When the object was created", @@ -3543,17 +3889,39 @@ }, "user_id": { "description": "The ID of the user who owns the session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "user_session_id": { "description": "The ID of the browser session which started this session", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "client_id": { "description": "The ID of the client which requested this session", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "scope": { "description": "The scope granted for this session", @@ -3581,15 +3949,16 @@ "type": "string", "nullable": true } - } + }, + "required": [ + "created_at", + "client_id", + "scope" + ] }, "SingleResponse_for_OAuth2Session": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_OAuth2Session" @@ -3597,33 +3966,31 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "SetPolicyDataRequest": { "title": "JSON payload for the `POST /api/admin/v1/policy-data`", "type": "object", - "required": [ - "data" - ], "properties": { "data": { - "examples": [ - { - "hello": "world", - "foo": 42, - "bar": true - } - ] + "example": { + "hello": "world", + "foo": 42, + "bar": true + } } - } + }, + "required": [ + "data" + ] }, "SingleResponse_for_PolicyData": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_PolicyData" @@ -3631,17 +3998,15 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "SingleResource_for_PolicyData": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -3649,25 +4014,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/PolicyData" + "allOf": [ + { + "$ref": "#/components/schemas/PolicyData" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "PolicyData": { "description": "The policy data", "type": "object", - "required": [ - "created_at", - "data" - ], "properties": { "created_at": { "description": "The creation date of the policy data", @@ -3677,7 +4056,11 @@ "data": { "description": "The policy data content" } - } + }, + "required": [ + "created_at", + "data" + ] }, "UserFilter": { "type": "object", @@ -3688,9 +4071,18 @@ "nullable": true }, "filter[status]": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users (includes deactivated users)\n\n* `deactivated`: Only retrieve deactivated users", - "$ref": "#/components/schemas/UserStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all users, including locked ones.\n\n * `active`: Only retrieve active users\n\n * `locked`: Only retrieve locked users (includes deactivated users)\n\n * `deactivated`: Only retrieve deactivated users", + "anyOf": [ + { + "$ref": "#/components/schemas/UserStatus" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] } } }, @@ -3705,15 +4097,14 @@ "PaginatedResponse_for_User": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -3724,19 +4115,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_User": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -3744,26 +4138,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/User" + "allOf": [ + { + "$ref": "#/components/schemas/User" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "User": { "description": "A user", "type": "object", - "required": [ - "admin", - "created_at", - "username" - ], "properties": { "username": { "description": "The username (localpart) of the user", @@ -3790,33 +4197,34 @@ "description": "Whether the user can request admin privileges.", "type": "boolean" } - } + }, + "required": [ + "username", + "created_at", + "admin" + ] }, "AddUserRequest": { "title": "JSON payload for the `POST /api/admin/v1/users` endpoint", "type": "object", - "required": [ - "username" - ], "properties": { "username": { "description": "The username of the user to add.", "type": "string" }, "skip_homeserver_check": { - "description": "Skip checking with the homeserver whether the username is available.\n\nUse this with caution! The main reason to use this, is when a user used by an application service needs to exist in MAS to craft special tokens (like with admin access) for them", - "default": false, - "type": "boolean" + "description": "Skip checking with the homeserver whether the username is available.\n\n Use this with caution! The main reason to use this, is when a user used\n by an application service needs to exist in MAS to craft special\n tokens (like with admin access) for them", + "type": "boolean", + "default": false } - } + }, + "required": [ + "username" + ] }, "SingleResponse_for_User": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_User" @@ -3824,61 +4232,72 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "SetUserPasswordRequest": { "title": "JSON payload for the `POST /api/admin/v1/users/:id/set-password` endpoint", "type": "object", - "required": [ - "password" - ], "properties": { "password": { "description": "The password to set for the user", - "examples": [ - "hunter2" - ], - "type": "string" + "type": "string", + "example": "hunter2" }, "skip_password_check": { "description": "Skip the password complexity check", "type": "boolean", "nullable": true } - } + }, + "required": [ + "password" + ] }, "UsernamePathParam": { "type": "object", - "required": [ - "username" - ], "properties": { "username": { "description": "The username (localpart) of the user to get", "type": "string" } - } + }, + "required": [ + "username" + ] }, "UserSetAdminRequest": { "title": "JSON payload for the `POST /api/admin/v1/users/:id/set-admin` endpoint", "type": "object", - "required": [ - "admin" - ], "properties": { "admin": { "description": "Whether the user can request admin privileges.", "type": "boolean" } - } + }, + "required": [ + "admin" + ] }, "UserEmailFilter": { "type": "object", "properties": { "filter[user]": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[email]": { "description": "Retrieve the user email with the given email address", @@ -3890,15 +4309,14 @@ "PaginatedResponse_for_UserEmail": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -3909,19 +4327,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_UserEmail": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -3929,26 +4350,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/UserEmail" + "allOf": [ + { + "$ref": "#/components/schemas/UserEmail" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "UserEmail": { "description": "An email address for a user", "type": "object", - "required": [ - "created_at", - "email", - "user_id" - ], "properties": { "created_at": { "description": "When the object was created", @@ -3957,40 +4391,49 @@ }, "user_id": { "description": "The ID of the user who owns this email address", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "email": { "description": "The email address", "type": "string" } - } + }, + "required": [ + "created_at", + "user_id", + "email" + ] }, "AddUserEmailRequest": { "title": "JSON payload for the `POST /api/admin/v1/user-emails`", "type": "object", - "required": [ - "email", - "user_id" - ], "properties": { "user_id": { "description": "The ID of the user to which the email should be added.", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "email": { "description": "The email address of the user to add.", "type": "string", "format": "email" } - } + }, + "required": [ + "user_id", + "email" + ] }, "SingleResponse_for_UserEmail": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_UserEmail" @@ -3998,20 +4441,42 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "UserSessionFilter": { "type": "object", "properties": { "filter[user]": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[status]": { - "description": "Retrieve the items with the given status\n\nDefaults to retrieve all sessions, including finished ones.\n\n* `active`: Only retrieve active sessions\n\n* `finished`: Only retrieve finished sessions", - "$ref": "#/components/schemas/UserSessionStatus", - "nullable": true + "description": "Retrieve the items with the given status\n\n Defaults to retrieve all sessions, including finished ones.\n\n * `active`: Only retrieve active sessions\n\n * `finished`: Only retrieve finished sessions", + "anyOf": [ + { + "$ref": "#/components/schemas/UserSessionStatus" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] } } }, @@ -4025,15 +4490,14 @@ "PaginatedResponse_for_UserSession": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -4044,19 +4508,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_UserSession": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -4064,25 +4531,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/UserSession" + "allOf": [ + { + "$ref": "#/components/schemas/UserSession" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "UserSession": { "description": "The browser (cookie) session for a user", "type": "object", - "required": [ - "created_at", - "user_id" - ], "properties": { "created_at": { "description": "When the object was created", @@ -4097,7 +4578,11 @@ }, "user_id": { "description": "The ID of the user who owns the session", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "user_agent": { "description": "The user agent string of the client which started this session", @@ -4116,15 +4601,15 @@ "format": "ip", "nullable": true } - } + }, + "required": [ + "created_at", + "user_id" + ] }, "SingleResponse_for_UserSession": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_UserSession" @@ -4132,7 +4617,11 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "RegistrationTokenFilter": { "type": "object", @@ -4153,7 +4642,7 @@ "nullable": true }, "filter[valid]": { - "description": "Retrieve tokens that are (or are not) valid\n\nValid means that the token has not expired, is not revoked, and has not reached its usage limit.", + "description": "Retrieve tokens that are (or are not) valid\n\n Valid means that the token has not expired, is not revoked, and has not\n reached its usage limit.", "type": "boolean", "nullable": true } @@ -4162,15 +4651,14 @@ "PaginatedResponse_for_UserRegistrationToken": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -4181,19 +4669,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_UserRegistrationToken": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -4201,27 +4692,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/UserRegistrationToken" + "allOf": [ + { + "$ref": "#/components/schemas/UserRegistrationToken" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "UserRegistrationToken": { "description": "A registration token", "type": "object", - "required": [ - "created_at", - "times_used", - "token", - "valid" - ], "properties": { "token": { "description": "The token string", @@ -4235,14 +4738,14 @@ "description": "Maximum number of times this token can be used", "type": "integer", "format": "uint32", - "minimum": 0.0, + "minimum": 0, "nullable": true }, "times_used": { "description": "Number of times this token has been used", "type": "integer", "format": "uint32", - "minimum": 0.0 + "minimum": 0 }, "created_at": { "description": "When the token was created", @@ -4267,7 +4770,13 @@ "format": "date-time", "nullable": true } - } + }, + "required": [ + "token", + "valid", + "times_used", + "created_at" + ] }, "AddUserRegistrationTokenRequest": { "title": "JSON payload for the `POST /api/admin/v1/user-registration-tokens`", @@ -4279,10 +4788,10 @@ "nullable": true }, "usage_limit": { - "description": "Maximum number of times this token can be used. If not provided, the token can be used an unlimited number of times.", + "description": "Maximum number of times this token can be used. If not provided, the\n token can be used an unlimited number of times.", "type": "integer", "format": "uint32", - "minimum": 0.0, + "minimum": 0, "nullable": true }, "expires_at": { @@ -4296,10 +4805,6 @@ "SingleResponse_for_UserRegistrationToken": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_UserRegistrationToken" @@ -4307,7 +4812,11 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] }, "EditUserRegistrationTokenRequest": { "title": "JSON payload for the `PUT /api/admin/v1/user-registration-tokens/{id}` endpoint", @@ -4323,7 +4832,7 @@ "description": "New usage limit for the token, or null to remove the limit", "type": "integer", "format": "uint32", - "minimum": 0.0, + "minimum": 0, "nullable": true } } @@ -4333,13 +4842,31 @@ "properties": { "filter[user]": { "description": "Retrieve the items for the given user", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[provider]": { "description": "Retrieve the items for the given provider", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "filter[subject]": { "description": "Retrieve the items with the given subject", @@ -4351,15 +4878,14 @@ "PaginatedResponse_for_UpstreamOAuthLink": { "description": "A top-level response with a page of resources", "type": "object", - "required": [ - "data", - "links", - "meta" - ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationMeta" + } + ] }, "data": { "description": "The list of resources", @@ -4370,19 +4896,22 @@ }, "links": { "description": "Related links", - "$ref": "#/components/schemas/PaginationLinks" + "allOf": [ + { + "$ref": "#/components/schemas/PaginationLinks" + } + ] } - } + }, + "required": [ + "meta", + "data", + "links" + ] }, "SingleResource_for_UpstreamOAuthLink": { "description": "A single resource, with its type, ID, attributes and related links", "type": "object", - "required": [ - "attributes", - "id", - "links", - "type" - ], "properties": { "type": { "description": "The type of the resource", @@ -4390,26 +4919,39 @@ }, "id": { "description": "The ID of the resource", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "attributes": { "description": "The attributes of the resource", - "$ref": "#/components/schemas/UpstreamOAuthLink" + "allOf": [ + { + "$ref": "#/components/schemas/UpstreamOAuthLink" + } + ] }, "links": { "description": "Related links", - "$ref": "#/components/schemas/SelfLinks" + "allOf": [ + { + "$ref": "#/components/schemas/SelfLinks" + } + ] } - } + }, + "required": [ + "type", + "id", + "attributes", + "links" + ] }, "UpstreamOAuthLink": { "description": "An upstream OAuth 2.0 link", "type": "object", - "required": [ - "created_at", - "provider_id", - "subject" - ], "properties": { "created_at": { "description": "When the object was created", @@ -4418,7 +4960,11 @@ }, "provider_id": { "description": "The ID of the provider", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "subject": { "description": "The subject of the upstream account, unique per provider", @@ -4426,32 +4972,49 @@ }, "user_id": { "description": "The ID of the user who owns this link, if any", - "$ref": "#/components/schemas/ULID", - "nullable": true + "anyOf": [ + { + "$ref": "#/components/schemas/ULID" + }, + { + "nullable": true, + "enum": [ + null + ] + } + ] }, "human_account_name": { "description": "A human-readable name of the upstream account", "type": "string", "nullable": true } - } + }, + "required": [ + "created_at", + "provider_id", + "subject" + ] }, "AddUpstreamOauthLinkRequest": { "title": "JSON payload for the `POST /api/admin/v1/upstream-oauth-links`", "type": "object", - "required": [ - "provider_id", - "subject", - "user_id" - ], "properties": { "user_id": { "description": "The ID of the user to which the link should be added.", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "provider_id": { "description": "The ID of the upstream provider to which the link is for.", - "$ref": "#/components/schemas/ULID" + "allOf": [ + { + "$ref": "#/components/schemas/ULID" + } + ] }, "subject": { "description": "The subject (sub) claim of the user on the provider.", @@ -4462,15 +5025,16 @@ "type": "string", "nullable": true } - } + }, + "required": [ + "user_id", + "provider_id", + "subject" + ] }, "SingleResponse_for_UpstreamOAuthLink": { "description": "A top-level response with a single resource", "type": "object", - "required": [ - "data", - "links" - ], "properties": { "data": { "$ref": "#/components/schemas/SingleResource_for_UpstreamOAuthLink" @@ -4478,7 +5042,11 @@ "links": { "$ref": "#/components/schemas/SelfLinks" } - } + }, + "required": [ + "data", + "links" + ] } } }, diff --git a/docs/config.schema.json b/docs/config.schema.json index 534165920..d69168bc8 100644 --- a/docs/config.schema.json +++ b/docs/config.schema.json @@ -3,10 +3,6 @@ "title": "RootConfig", "description": "Application configuration root", "type": "object", - "required": [ - "matrix", - "secrets" - ], "properties": { "clients": { "description": "List of OAuth 2.0/OIDC clients config", @@ -169,7 +165,7 @@ ] }, "rate_limiting": { - "description": "Configuration related to limiting the rate of user actions to prevent abuse", + "description": "Configuration related to limiting the rate of user actions to prevent\n abuse", "allOf": [ { "$ref": "#/definitions/RateLimitingConfig" @@ -201,7 +197,7 @@ ] }, "account": { - "description": "Configuration section to configure features related to account management", + "description": "Configuration section to configure features related to account\n management", "allOf": [ { "$ref": "#/definitions/AccountConfig" @@ -217,14 +213,14 @@ ] } }, + "required": [ + "secrets", + "matrix" + ], "definitions": { "ClientConfig": { "description": "An OAuth 2.0 client configuration", "type": "object", - "required": [ - "client_auth_method", - "client_id" - ], "properties": { "client_id": { "description": "A ULID as per https://github.com/ulid/spec", @@ -241,24 +237,31 @@ }, "client_name": { "description": "Name of the `OAuth2` client", - "type": "string" + "type": "string", + "nullable": true }, "client_secret": { - "description": "The client secret, used by the `client_secret_basic`, `client_secret_post` and `client_secret_jwt` authentication methods", - "type": "string" + "description": "The client secret, used by the `client_secret_basic`,\n `client_secret_post` and `client_secret_jwt` authentication methods", + "type": "string", + "nullable": true }, "jwks": { - "description": "The JSON Web Key Set (JWKS) used by the `private_key_jwt` authentication method. Mutually exclusive with `jwks_uri`", - "allOf": [ + "description": "The JSON Web Key Set (JWKS) used by the `private_key_jwt` authentication\n method. Mutually exclusive with `jwks_uri`", + "anyOf": [ { "$ref": "#/definitions/JsonWebKeySet_for_JsonWebKeyPublicParameters" + }, + { + "const": null, + "nullable": true } ] }, "jwks_uri": { - "description": "The URL of the JSON Web Key Set (JWKS) used by the `private_key_jwt` authentication method. Mutually exclusive with `jwks`", + "description": "The URL of the JSON Web Key Set (JWKS) used by the `private_key_jwt`\n authentication method. Mutually exclusive with `jwks`", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "redirect_uris": { "description": "List of allowed redirect URIs", @@ -268,7 +271,11 @@ "format": "uri" } } - } + }, + "required": [ + "client_id", + "client_auth_method" + ] }, "ClientAuthMethodConfig": { "description": "Authentication method used by clients", @@ -276,45 +283,32 @@ { "description": "`none`: No authentication", "type": "string", - "enum": [ - "none" - ] + "const": "none" }, { - "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic authorization credentials", + "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic\n authorization credentials", "type": "string", - "enum": [ - "client_secret_basic" - ] + "const": "client_secret_basic" }, { - "description": "`client_secret_post`: `client_id` and `client_secret` sent in the request body", + "description": "`client_secret_post`: `client_id` and `client_secret` sent in the\n request body", "type": "string", - "enum": [ - "client_secret_post" - ] + "const": "client_secret_post" }, { - "description": "`client_secret_basic`: a `client_assertion` sent in the request body and signed using the `client_secret`", + "description": "`client_secret_basic`: a `client_assertion` sent in the request body and\n signed using the `client_secret`", "type": "string", - "enum": [ - "client_secret_jwt" - ] + "const": "client_secret_jwt" }, { - "description": "`client_secret_basic`: a `client_assertion` sent in the request body and signed by an asymmetric key", + "description": "`client_secret_basic`: a `client_assertion` sent in the request body and\n signed by an asymmetric key", "type": "string", - "enum": [ - "private_key_jwt" - ] + "const": "private_key_jwt" } ] }, "JsonWebKeySet_for_JsonWebKeyPublicParameters": { "type": "object", - "required": [ - "keys" - ], "properties": { "keys": { "type": "array", @@ -322,100 +316,50 @@ "$ref": "#/definitions/JsonWebKey_for_JsonWebKeyPublicParameters" } } - } + }, + "required": [ + "keys" + ] }, "JsonWebKey_for_JsonWebKeyPublicParameters": { "type": "object", - "oneOf": [ - { - "type": "object", - "required": [ - "e", - "kty", - "n" - ], - "properties": { - "kty": { - "type": "string", - "enum": [ - "RSA" - ] - }, - "n": { - "type": "string" - }, - "e": { - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "crv", - "kty", - "x", - "y" - ], - "properties": { - "kty": { - "type": "string", - "enum": [ - "EC" - ] - }, - "crv": { - "$ref": "#/definitions/JsonWebKeyEcEllipticCurve" - }, - "x": { - "type": "string" - }, - "y": { - "type": "string" - } - } - }, - { - "type": "object", - "required": [ - "crv", - "kty", - "x" - ], - "properties": { - "kty": { - "type": "string", - "enum": [ - "OKP" - ] - }, - "crv": { - "$ref": "#/definitions/JsonWebKeyOkpEllipticCurve" - }, - "x": { - "type": "string" - } - } - } - ], "properties": { "use": { - "$ref": "#/definitions/JsonWebKeyUse" + "anyOf": [ + { + "$ref": "#/definitions/JsonWebKeyUse" + }, + { + "const": null, + "nullable": true + } + ] }, "key_ops": { "type": "array", "items": { "$ref": "#/definitions/JsonWebKeyOperation" - } + }, + "nullable": true }, "alg": { - "$ref": "#/definitions/JsonWebSignatureAlg" + "anyOf": [ + { + "$ref": "#/definitions/JsonWebSignatureAlg" + }, + { + "const": null, + "nullable": true + } + ] }, "kid": { - "type": "string" + "type": "string", + "nullable": true }, "x5u": { - "type": "string" + "type": "string", + "nullable": true }, "x5c": { "type": "array", @@ -424,12 +368,158 @@ } }, "x5t": { - "type": "string" + "type": "string", + "nullable": true }, "x5t#S256": { + "type": "string", + "nullable": true + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "kty": { + "type": "string", + "const": "RSA" + } + }, + "required": [ + "kty" + ], + "allOf": [ + { + "$ref": "#/definitions/RsaPublicParameters" + } + ] + }, + { + "type": "object", + "properties": { + "kty": { + "type": "string", + "const": "EC" + } + }, + "required": [ + "kty" + ], + "allOf": [ + { + "$ref": "#/definitions/EcPublicParameters" + } + ] + }, + { + "type": "object", + "properties": { + "kty": { + "type": "string", + "const": "OKP" + } + }, + "required": [ + "kty" + ], + "allOf": [ + { + "$ref": "#/definitions/OkpPublicParameters" + } + ] + } + ] + }, + "RsaPublicParameters": { + "type": "object", + "properties": { + "n": { + "type": "string" + }, + "e": { "type": "string" } - } + }, + "required": [ + "n", + "e" + ] + }, + "JsonWebKeyEcEllipticCurve": { + "description": "JSON Web Key EC Elliptic Curve", + "anyOf": [ + { + "description": "P-256 Curve", + "const": "P-256" + }, + { + "description": "P-384 Curve", + "const": "P-384" + }, + { + "description": "P-521 Curve", + "const": "P-521" + }, + { + "description": "SECG secp256k1 curve", + "const": "secp256k1" + } + ] + }, + "EcPublicParameters": { + "type": "object", + "properties": { + "crv": { + "$ref": "#/definitions/JsonWebKeyEcEllipticCurve" + }, + "x": { + "type": "string" + }, + "y": { + "type": "string" + } + }, + "required": [ + "crv", + "x", + "y" + ] + }, + "JsonWebKeyOkpEllipticCurve": { + "description": "JSON Web Key OKP Elliptic Curve", + "anyOf": [ + { + "description": "Ed25519 signature algorithm key pairs", + "const": "Ed25519" + }, + { + "description": "Ed448 signature algorithm key pairs", + "const": "Ed448" + }, + { + "description": "X25519 function key pairs", + "const": "X25519" + }, + { + "description": "X448 function key pairs", + "const": "X448" + } + ] + }, + "OkpPublicParameters": { + "type": "object", + "properties": { + "crv": { + "$ref": "#/definitions/JsonWebKeyOkpEllipticCurve" + }, + "x": { + "type": "string" + } + }, + "required": [ + "crv", + "x" + ] }, "JsonWebKeyUse": { "description": "JSON Web Key Use", @@ -554,65 +644,25 @@ } ] }, - "JsonWebKeyEcEllipticCurve": { - "description": "JSON Web Key EC Elliptic Curve", - "anyOf": [ - { - "description": "P-256 Curve", - "const": "P-256" - }, - { - "description": "P-384 Curve", - "const": "P-384" - }, - { - "description": "P-521 Curve", - "const": "P-521" - }, - { - "description": "SECG secp256k1 curve", - "const": "secp256k1" - } - ] - }, - "JsonWebKeyOkpEllipticCurve": { - "description": "JSON Web Key OKP Elliptic Curve", - "anyOf": [ - { - "description": "Ed25519 signature algorithm key pairs", - "const": "Ed25519" - }, - { - "description": "Ed448 signature algorithm key pairs", - "const": "Ed448" - }, - { - "description": "X25519 function key pairs", - "const": "X25519" - }, - { - "description": "X448 function key pairs", - "const": "X448" - } - ] - }, "HttpConfig": { "description": "Configuration related to the web server", "type": "object", - "required": [ - "public_base" - ], "properties": { "listeners": { "description": "List of listeners to run", - "default": [], "type": "array", "items": { "$ref": "#/definitions/ListenerConfig" - } + }, + "default": [] }, "trusted_proxies": { - "description": "List of trusted reverse proxies that can set the `X-Forwarded-For` header", + "description": "List of trusted reverse proxies that can set the `X-Forwarded-For`\n header", + "type": "array", + "items": { + "type": "string", + "format": "ip" + }, "default": [ "192.168.0.0/16", "172.16.0.0/12", @@ -620,11 +670,7 @@ "127.0.0.1/8", "fd00::/8", "::1/128" - ], - "type": "array", - "items": { - "$ref": "#/definitions/IpNetwork" - } + ] }, "public_base": { "description": "Public URL base from where the authentication service is reachable", @@ -634,21 +680,22 @@ "issuer": { "description": "OIDC issuer URL. Defaults to `public_base` if not set.", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true } - } + }, + "required": [ + "public_base" + ] }, "ListenerConfig": { "description": "Configuration of a listener", "type": "object", - "required": [ - "binds", - "resources" - ], "properties": { "name": { - "description": "A unique name for this listener which will be shown in traces and in metrics labels", - "type": "string" + "description": "A unique name for this listener which will be shown in traces and in\n metrics labels", + "type": "string", + "nullable": true }, "resources": { "description": "List of resources to mount", @@ -659,7 +706,8 @@ }, "prefix": { "description": "HTTP prefix to mount the resources on", - "type": "string" + "type": "string", + "nullable": true }, "binds": { "description": "List of sockets to bind", @@ -670,18 +718,26 @@ }, "proxy_protocol": { "description": "Accept `HAProxy`'s Proxy Protocol V1", - "default": false, - "type": "boolean" + "type": "boolean", + "default": false }, "tls": { "description": "If set, makes the listener use TLS with the provided certificate and key", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/TlsConfig" + }, + { + "const": null, + "nullable": true } ] } - } + }, + "required": [ + "resources", + "binds" + ] }, "Resource": { "description": "HTTP resources to mount", @@ -689,76 +745,59 @@ { "description": "Healthcheck endpoint (/health)", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "health" - ] + "const": "health" } - } + }, + "required": [ + "name" + ] }, { "description": "Prometheus metrics endpoint (/metrics)", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "prometheus" - ] + "const": "prometheus" } - } + }, + "required": [ + "name" + ] }, { "description": "OIDC discovery endpoints", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "discovery" - ] + "const": "discovery" } - } + }, + "required": [ + "name" + ] }, { "description": "Pages destined to be viewed by humans", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "human" - ] + "const": "human" } - } + }, + "required": [ + "name" + ] }, { "description": "GraphQL endpoint", "type": "object", - "required": [ - "name" - ], "properties": { - "name": { - "type": "string", - "enum": [ - "graphql" - ] - }, "playground": { "description": "Enabled the GraphQL playground", "type": "boolean" @@ -766,87 +805,84 @@ "undocumented_oauth2_access": { "description": "Allow access for OAuth 2.0 clients (undocumented)", "type": "boolean" + }, + "name": { + "type": "string", + "const": "graphql" } - } + }, + "required": [ + "name" + ] }, { "description": "OAuth-related APIs", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "oauth" - ] + "const": "oauth" } - } + }, + "required": [ + "name" + ] }, { "description": "Matrix compatibility API", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "compat" - ] + "const": "compat" } - } + }, + "required": [ + "name" + ] }, { "description": "Static files", "type": "object", - "required": [ - "name" - ], "properties": { - "name": { - "type": "string", - "enum": [ - "assets" - ] - }, "path": { "description": "Path to the directory to serve.", "type": "string" + }, + "name": { + "type": "string", + "const": "assets" } - } + }, + "required": [ + "name" + ] }, { "description": "Admin API, served at `/api/admin/v1`", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "adminapi" - ] + "const": "adminapi" } - } + }, + "required": [ + "name" + ] }, { - "description": "Mount a \"/connection-info\" handler which helps debugging informations on the upstream connection", + "description": "Mount a \"/connection-info\" handler which helps debugging informations on\n the upstream connection", "type": "object", - "required": [ - "name" - ], "properties": { "name": { "type": "string", - "enum": [ - "connection-info" - ] + "const": "connection-info" } - } + }, + "required": [ + "name" + ] } ] }, @@ -856,67 +892,69 @@ { "description": "Listen on the specified host and port", "type": "object", - "required": [ - "port" - ], "properties": { "host": { - "description": "Host on which to listen.\n\nDefaults to listening on all addresses", - "type": "string" + "description": "Host on which to listen.\n\n Defaults to listening on all addresses", + "type": "string", + "nullable": true }, "port": { "description": "Port on which to listen.", "type": "integer", "format": "uint16", - "minimum": 0.0 + "minimum": 0, + "maximum": 65535 } - } + }, + "required": [ + "port" + ] }, { "description": "Listen on the specified address", "type": "object", - "required": [ - "address" - ], "properties": { "address": { "description": "Host and port on which to listen", + "type": "string", "examples": [ "[::1]:8080", "[::]:8080", "127.0.0.1:8080", "0.0.0.0:8080" - ], - "type": "string" + ] } - } + }, + "required": [ + "address" + ] }, { "description": "Listen on a UNIX domain socket", "type": "object", - "required": [ - "socket" - ], "properties": { "socket": { "description": "Path to the socket", "type": "string" } - } + }, + "required": [ + "socket" + ] }, { - "description": "Accept connections on file descriptors passed by the parent process.\n\nThis is useful for grabbing sockets passed by systemd.\n\nSee ", + "description": "Accept connections on file descriptors passed by the parent process.\n\n This is useful for grabbing sockets passed by systemd.\n\n See ", "type": "object", "properties": { "fd": { - "description": "Index of the file descriptor. Note that this is offseted by 3 because of the standard input/output sockets, so setting here a value of `0` will grab the file descriptor `3`", - "default": 0, + "description": "Index of the file descriptor. Note that this is offseted by 3\n because of the standard input/output sockets, so setting\n here a value of `0` will grab the file descriptor `3`", "type": "integer", "format": "uint", - "minimum": 0.0 + "minimum": 0, + "default": 0 }, "kind": { - "description": "Whether the socket is a TCP socket or a UNIX domain socket. Defaults to TCP.", + "description": "Whether the socket is a TCP socket or a UNIX domain socket. Defaults\n to TCP.", "default": "tcp", "allOf": [ { @@ -934,16 +972,12 @@ { "description": "UNIX domain socket", "type": "string", - "enum": [ - "unix" - ] + "const": "unix" }, { "description": "TCP socket", "type": "string", - "enum": [ - "tcp" - ] + "const": "tcp" } ] }, @@ -952,169 +986,165 @@ "type": "object", "properties": { "certificate": { - "description": "PEM-encoded X509 certificate chain\n\nExactly one of `certificate` or `certificate_file` must be set.", - "type": "string" + "description": "PEM-encoded X509 certificate chain\n\n Exactly one of `certificate` or `certificate_file` must be set.", + "type": "string", + "nullable": true }, "certificate_file": { - "description": "File containing the PEM-encoded X509 certificate chain\n\nExactly one of `certificate` or `certificate_file` must be set.", - "type": "string" + "description": "File containing the PEM-encoded X509 certificate chain\n\n Exactly one of `certificate` or `certificate_file` must be set.", + "type": "string", + "nullable": true }, "key": { - "description": "PEM-encoded private key\n\nExactly one of `key` or `key_file` must be set.", - "type": "string" + "description": "PEM-encoded private key\n\n Exactly one of `key` or `key_file` must be set.", + "type": "string", + "nullable": true }, "key_file": { - "description": "File containing a PEM or DER-encoded private key\n\nExactly one of `key` or `key_file` must be set.", - "type": "string" + "description": "File containing a PEM or DER-encoded private key\n\n Exactly one of `key` or `key_file` must be set.", + "type": "string", + "nullable": true }, "password": { - "description": "Password used to decode the private key\n\nOne of `password` or `password_file` must be set if the key is encrypted.", - "type": "string" + "description": "Password used to decode the private key\n\n One of `password` or `password_file` must be set if the key is\n encrypted.", + "type": "string", + "nullable": true }, "password_file": { - "description": "Password file used to decode the private key\n\nOne of `password` or `password_file` must be set if the key is encrypted.", - "type": "string" + "description": "Password file used to decode the private key\n\n One of `password` or `password_file` must be set if the key is\n encrypted.", + "type": "string", + "nullable": true } } }, - "IpNetwork": { - "oneOf": [ - { - "title": "v4", - "allOf": [ - { - "$ref": "#/definitions/Ipv4Network" - } - ] - }, - { - "title": "v6", - "allOf": [ - { - "$ref": "#/definitions/Ipv6Network" - } - ] - } - ], - "x-rust-type": "ipnetwork::IpNetwork" - }, - "Ipv4Network": { - "type": "string", - "pattern": "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\/(3[0-2]|[0-2]?[0-9])$", - "x-rust-type": "ipnetwork::Ipv4Network" - }, - "Ipv6Network": { - "type": "string", - "pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\")[/](12[0-8]|1[0-1][0-9]|[0-9]?[0-9])$", - "x-rust-type": "ipnetwork::Ipv6Network" - }, "DatabaseConfig": { "description": "Database connection configuration", "type": "object", "properties": { "uri": { - "description": "Connection URI\n\nThis must not be specified if `host`, `port`, `socket`, `username`, `password`, or `database` are specified.", - "default": "postgresql://", + "description": "Connection URI\n\n This must not be specified if `host`, `port`, `socket`, `username`,\n `password`, or `database` are specified.", "type": "string", - "format": "uri" + "format": "uri", + "default": "postgresql://", + "nullable": true }, "host": { - "description": "Name of host to connect to\n\nThis must not be specified if `uri` is specified.", - "allOf": [ + "description": "Name of host to connect to\n\n This must not be specified if `uri` is specified.", + "anyOf": [ { "$ref": "#/definitions/Hostname" + }, + { + "const": null, + "nullable": true } ] }, "port": { - "description": "Port number to connect at the server host\n\nThis must not be specified if `uri` is specified.", + "description": "Port number to connect at the server host\n\n This must not be specified if `uri` is specified.", "type": "integer", "format": "uint16", - "maximum": 65535.0, - "minimum": 1.0 + "minimum": 1, + "maximum": 65535, + "nullable": true }, "socket": { - "description": "Directory containing the UNIX socket to connect to\n\nThis must not be specified if `uri` is specified.", - "type": "string" + "description": "Directory containing the UNIX socket to connect to\n\n This must not be specified if `uri` is specified.", + "type": "string", + "nullable": true }, "username": { - "description": "PostgreSQL user name to connect as\n\nThis must not be specified if `uri` is specified.", - "type": "string" + "description": "PostgreSQL user name to connect as\n\n This must not be specified if `uri` is specified.", + "type": "string", + "nullable": true }, "password": { - "description": "Password to be used if the server demands password authentication\n\nThis must not be specified if `uri` is specified.", - "type": "string" + "description": "Password to be used if the server demands password authentication\n\n This must not be specified if `uri` is specified.", + "type": "string", + "nullable": true }, "database": { - "description": "The database name\n\nThis must not be specified if `uri` is specified.", - "type": "string" + "description": "The database name\n\n This must not be specified if `uri` is specified.", + "type": "string", + "nullable": true }, "ssl_mode": { "description": "How to handle SSL connections", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/PgSslMode" + }, + { + "const": null, + "nullable": true } ] }, "ssl_ca": { - "description": "The PEM-encoded root certificate for SSL connections\n\nThis must not be specified if the `ssl_ca_file` option is specified.", - "type": "string" + "description": "The PEM-encoded root certificate for SSL connections\n\n This must not be specified if the `ssl_ca_file` option is specified.", + "type": "string", + "nullable": true }, "ssl_ca_file": { - "description": "Path to the root certificate for SSL connections\n\nThis must not be specified if the `ssl_ca` option is specified.", - "type": "string" + "description": "Path to the root certificate for SSL connections\n\n This must not be specified if the `ssl_ca` option is specified.", + "type": "string", + "nullable": true }, "ssl_certificate": { - "description": "The PEM-encoded client certificate for SSL connections\n\nThis must not be specified if the `ssl_certificate_file` option is specified.", - "type": "string" + "description": "The PEM-encoded client certificate for SSL connections\n\n This must not be specified if the `ssl_certificate_file` option is\n specified.", + "type": "string", + "nullable": true }, "ssl_certificate_file": { - "description": "Path to the client certificate for SSL connections\n\nThis must not be specified if the `ssl_certificate` option is specified.", - "type": "string" + "description": "Path to the client certificate for SSL connections\n\n This must not be specified if the `ssl_certificate` option is specified.", + "type": "string", + "nullable": true }, "ssl_key": { - "description": "The PEM-encoded client key for SSL connections\n\nThis must not be specified if the `ssl_key_file` option is specified.", - "type": "string" + "description": "The PEM-encoded client key for SSL connections\n\n This must not be specified if the `ssl_key_file` option is specified.", + "type": "string", + "nullable": true }, "ssl_key_file": { - "description": "Path to the client key for SSL connections\n\nThis must not be specified if the `ssl_key` option is specified.", - "type": "string" + "description": "Path to the client key for SSL connections\n\n This must not be specified if the `ssl_key` option is specified.", + "type": "string", + "nullable": true }, "max_connections": { "description": "Set the maximum number of connections the pool should maintain", - "default": 10, "type": "integer", "format": "uint32", - "minimum": 1.0 + "minimum": 1, + "default": 10 }, "min_connections": { "description": "Set the minimum number of connections the pool should maintain", - "default": 0, "type": "integer", "format": "uint32", - "minimum": 0.0 + "minimum": 0, + "default": 0 }, "connect_timeout": { "description": "Set the amount of time to attempt connecting to the database", - "default": 30, "type": "integer", "format": "uint64", - "minimum": 0.0 + "minimum": 0, + "default": 30 }, "idle_timeout": { "description": "Set a maximum idle duration for individual connections", - "default": 600, "type": "integer", "format": "uint64", - "minimum": 0.0 + "minimum": 0, + "default": 600, + "nullable": true }, "max_lifetime": { "description": "Set the maximum lifetime of individual connections", - "default": 1800, "type": "integer", "format": "uint64", - "minimum": 0.0 + "minimum": 0, + "default": 1800 } } }, @@ -1123,49 +1153,37 @@ "format": "hostname" }, "PgSslMode": { - "description": "Options for controlling the level of protection provided for PostgreSQL SSL connections.", + "description": "Options for controlling the level of protection provided for PostgreSQL SSL\n connections.", "oneOf": [ { "description": "Only try a non-SSL connection.", "type": "string", - "enum": [ - "disable" - ] + "const": "disable" }, { "description": "First try a non-SSL connection; if that fails, try an SSL connection.", "type": "string", - "enum": [ - "allow" - ] + "const": "allow" }, { "description": "First try an SSL connection; if that fails, try a non-SSL connection.", "type": "string", - "enum": [ - "prefer" - ] + "const": "prefer" }, { - "description": "Only try an SSL connection. If a root CA file is present, verify the connection in the same way as if `VerifyCa` was specified.", + "description": "Only try an SSL connection. If a root CA file is present, verify the\n connection in the same way as if `VerifyCa` was specified.", "type": "string", - "enum": [ - "require" - ] + "const": "require" }, { - "description": "Only try an SSL connection, and verify that the server certificate is issued by a trusted certificate authority (CA).", + "description": "Only try an SSL connection, and verify that the server certificate is\n issued by a trusted certificate authority (CA).", "type": "string", - "enum": [ - "verify-ca" - ] + "const": "verify-ca" }, { - "description": "Only try an SSL connection; verify that the server certificate is issued by a trusted CA and that the requested server host name matches that in the certificate.", + "description": "Only try an SSL connection; verify that the server certificate is issued\n by a trusted CA and that the requested server host name matches that\n in the certificate.", "type": "string", - "enum": [ - "verify-full" - ] + "const": "verify-full" } ] }, @@ -1214,27 +1232,29 @@ }, "endpoint": { "description": "OTLP exporter: OTLP over HTTP compatible endpoint", - "default": "https://localhost:4318", "type": "string", - "format": "uri" + "format": "uri", + "default": "https://localhost:4318", + "nullable": true }, "propagators": { "description": "List of propagation formats to use for incoming and outgoing requests", - "default": [], "type": "array", "items": { "$ref": "#/definitions/Propagator" - } + }, + "default": [] }, "sample_rate": { - "description": "Sample rate for traces\n\nDefaults to `1.0` if not set.", + "description": "Sample rate for traces\n\n Defaults to `1.0` if not set.", + "type": "number", + "format": "double", "examples": [ 0.5 ], - "type": "number", - "format": "double", + "minimum": 0.0, "maximum": 1.0, - "minimum": 0.0 + "nullable": true } } }, @@ -1244,23 +1264,17 @@ { "description": "Don't export traces", "type": "string", - "enum": [ - "none" - ] + "const": "none" }, { "description": "Export traces to the standard output. Only useful for debugging", "type": "string", - "enum": [ - "stdout" - ] + "const": "stdout" }, { "description": "Export traces to an OpenTelemetry protocol compatible endpoint", "type": "string", - "enum": [ - "otlp" - ] + "const": "otlp" } ] }, @@ -1270,23 +1284,17 @@ { "description": "Propagate according to the W3C Trace Context specification", "type": "string", - "enum": [ - "tracecontext" - ] + "const": "tracecontext" }, { "description": "Propagate according to the W3C Baggage specification", "type": "string", - "enum": [ - "baggage" - ] + "const": "baggage" }, { "description": "Propagate trace context with Jaeger compatible headers", "type": "string", - "enum": [ - "jaeger" - ] + "const": "jaeger" } ] }, @@ -1305,9 +1313,10 @@ }, "endpoint": { "description": "OTLP exporter: OTLP over HTTP compatible endpoint", - "default": "https://localhost:4318", "type": "string", - "format": "uri" + "format": "uri", + "default": "https://localhost:4318", + "nullable": true } } }, @@ -1317,30 +1326,22 @@ { "description": "Don't export metrics", "type": "string", - "enum": [ - "none" - ] + "const": "none" }, { "description": "Export metrics to stdout. Only useful for debugging", "type": "string", - "enum": [ - "stdout" - ] + "const": "stdout" }, { "description": "Export metrics to an OpenTelemetry protocol compatible endpoint", "type": "string", - "enum": [ - "otlp" - ] + "const": "otlp" }, { - "description": "Export metrics via Prometheus. An HTTP listener with the `prometheus` resource must be setup to expose the Promethes metrics.", + "description": "Export metrics via Prometheus. An HTTP listener with the `prometheus`\n resource must be setup to expose the Promethes metrics.", "type": "string", - "enum": [ - "prometheus" - ] + "const": "prometheus" } ] }, @@ -1350,38 +1351,42 @@ "properties": { "dsn": { "description": "Sentry DSN", + "type": "string", + "format": "uri", "examples": [ "https://public@host:port/1" ], - "type": "string", - "format": "uri" + "nullable": true }, "environment": { - "description": "Environment to use when sending events to Sentry\n\nDefaults to `production` if not set.", + "description": "Environment to use when sending events to Sentry\n\n Defaults to `production` if not set.", + "type": "string", "examples": [ "production" ], - "type": "string" + "nullable": true }, "sample_rate": { - "description": "Sample rate for event submissions\n\nDefaults to `1.0` if not set.", + "description": "Sample rate for event submissions\n\n Defaults to `1.0` if not set.", + "type": "number", + "format": "float", "examples": [ 0.5 ], - "type": "number", - "format": "float", + "minimum": 0.0, "maximum": 1.0, - "minimum": 0.0 + "nullable": true }, "traces_sample_rate": { - "description": "Sample rate for tracing transactions\n\nDefaults to `0.0` if not set.", + "description": "Sample rate for tracing transactions\n\n Defaults to `0.0` if not set.", + "type": "number", + "format": "float", "examples": [ 0.5 ], - "type": "number", - "format": "float", + "minimum": 0.0, "maximum": 1.0, - "minimum": 0.0 + "nullable": true } } }, @@ -1391,36 +1396,36 @@ "properties": { "path": { "description": "Path to the folder which holds the templates", - "type": "string" + "type": "string", + "nullable": true }, "assets_manifest": { "description": "Path to the assets manifest", - "type": "string" + "type": "string", + "nullable": true }, "translations_path": { "description": "Path to the translations", - "type": "string" + "type": "string", + "nullable": true } } }, "EmailConfig": { "description": "Configuration related to sending emails", "type": "object", - "required": [ - "transport" - ], "properties": { "from": { "description": "Email address to use as From when sending emails", - "default": "\"Authentication Service\" ", "type": "string", - "format": "email" + "format": "email", + "default": "\"Authentication Service\" " }, "reply_to": { "description": "Email address to use as Reply-To when sending emails", - "default": "\"Authentication Service\" ", "type": "string", - "format": "email" + "format": "email", + "default": "\"Authentication Service\" " }, "transport": { "description": "What backend should be used when sending emails", @@ -1432,41 +1437,56 @@ }, "mode": { "description": "SMTP transport: Connection mode to the relay", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/EmailSmtpMode" + }, + { + "const": null, + "nullable": true } ] }, "hostname": { "description": "SMTP transport: Hostname to connect to", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/Hostname" + }, + { + "const": null, + "nullable": true } ] }, "port": { - "description": "SMTP transport: Port to connect to. Default is 25 for plain, 465 for TLS and 587 for `StartTLS`", + "description": "SMTP transport: Port to connect to. Default is 25 for plain, 465 for TLS\n and 587 for `StartTLS`", "type": "integer", "format": "uint16", - "maximum": 65535.0, - "minimum": 1.0 + "minimum": 1, + "maximum": 65535, + "nullable": true }, "username": { - "description": "SMTP transport: Username for use to authenticate when connecting to the SMTP server\n\nMust be set if the `password` field is set", - "type": "string" + "description": "SMTP transport: Username for use to authenticate when connecting to the\n SMTP server\n\n Must be set if the `password` field is set", + "type": "string", + "nullable": true }, "password": { - "description": "SMTP transport: Password for use to authenticate when connecting to the SMTP server\n\nMust be set if the `username` field is set", - "type": "string" + "description": "SMTP transport: Password for use to authenticate when connecting to the\n SMTP server\n\n Must be set if the `username` field is set", + "type": "string", + "nullable": true }, "command": { "description": "Sendmail transport: Command to use to send emails", + "type": "string", "default": "sendmail", - "type": "string" + "nullable": true } - } + }, + "required": [ + "transport" + ] }, "EmailTransportKind": { "description": "What backend should be used when sending emails", @@ -1474,23 +1494,17 @@ { "description": "Don't send emails anywhere", "type": "string", - "enum": [ - "blackhole" - ] + "const": "blackhole" }, { "description": "Send emails via an SMTP relay", "type": "string", - "enum": [ - "smtp" - ] + "const": "smtp" }, { "description": "Send emails by calling sendmail", "type": "string", - "enum": [ - "sendmail" - ] + "const": "sendmail" } ] }, @@ -1500,23 +1514,17 @@ { "description": "Plain text", "type": "string", - "enum": [ - "plain" - ] + "const": "plain" }, { "description": "`StartTLS` (starts as plain text then upgrade to TLS)", "type": "string", - "enum": [ - "starttls" - ] + "const": "starttls" }, { "description": "TLS", "type": "string", - "enum": [ - "tls" - ] + "const": "tls" } ] }, @@ -1524,51 +1532,57 @@ "description": "Application secrets", "type": "object", "properties": { - "keys": { - "description": "List of private keys to use for signing and encrypting payloads", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/KeyConfig" - } - }, "encryption_file": { "description": "File containing the encryption key for secure cookies.", - "type": "string" + "type": "string", + "nullable": true }, "encryption": { "description": "Encryption key for secure cookies.", + "type": "string", "examples": [ "0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff" ], - "type": "string", - "pattern": "[0-9a-fA-F]{64}" + "pattern": "[0-9a-fA-F]{64}", + "nullable": true + }, + "keys": { + "description": "List of private keys to use for signing and encrypting payloads", + "type": "array", + "items": { + "$ref": "#/definitions/KeyConfig" + }, + "default": [] } } }, "KeyConfig": { "description": "A single key with its key ID and optional password.", "type": "object", - "required": [ - "kid" - ], "properties": { "kid": { "type": "string" }, "password_file": { - "type": "string" + "type": "string", + "nullable": true }, "password": { - "type": "string" + "type": "string", + "nullable": true }, "key_file": { - "type": "string" + "type": "string", + "nullable": true }, "key": { - "type": "string" + "type": "string", + "nullable": true } - } + }, + "required": [ + "kid" + ] }, "PasswordsConfig": { "description": "User password hashing config", @@ -1576,44 +1590,42 @@ "properties": { "enabled": { "description": "Whether password-based authentication is enabled", - "default": true, - "type": "boolean" + "type": "boolean", + "default": true }, "schemes": { - "description": "The hashing schemes to use for hashing and validating passwords\n\nThe hashing scheme with the highest version number will be used for hashing new passwords.", + "description": "The hashing schemes to use for hashing and validating passwords\n\n The hashing scheme with the highest version number will be used for\n hashing new passwords.", + "type": "array", + "items": { + "$ref": "#/definitions/HashingScheme" + }, "default": [ { "version": 1, "algorithm": "argon2id" } - ], - "type": "array", - "items": { - "$ref": "#/definitions/HashingScheme" - } + ] }, "minimum_complexity": { - "description": "Score between 0 and 4 determining the minimum allowed password complexity. Scores are based on the ESTIMATED number of guesses needed to guess the password.\n\n- 0: less than 10^2 (100) - 1: less than 10^4 (10'000) - 2: less than 10^6 (1'000'000) - 3: less than 10^8 (100'000'000) - 4: any more than that", - "default": 3, + "description": "Score between 0 and 4 determining the minimum allowed password\n complexity. Scores are based on the ESTIMATED number of guesses\n needed to guess the password.\n\n - 0: less than 10^2 (100)\n - 1: less than 10^4 (10'000)\n - 2: less than 10^6 (1'000'000)\n - 3: less than 10^8 (100'000'000)\n - 4: any more than that", "type": "integer", "format": "uint8", - "minimum": 0.0 + "minimum": 0, + "maximum": 255, + "default": 3 } } }, "HashingScheme": { "description": "Parameters for a password hashing scheme", "type": "object", - "required": [ - "algorithm", - "version" - ], "properties": { "version": { - "description": "The version of the hashing scheme. They must be unique, and the highest version will be used for hashing new passwords.", + "description": "The version of the hashing scheme. They must be unique, and the highest\n version will be used for hashing new passwords.", "type": "integer", "format": "uint16", - "minimum": 0.0 + "minimum": 0, + "maximum": 65535 }, "algorithm": { "description": "The hashing algorithm to use", @@ -1624,25 +1636,32 @@ ] }, "unicode_normalization": { - "description": "Whether to apply Unicode normalization to the password before hashing\n\nDefaults to `false`, and generally recommended to stay false. This is although recommended when importing password hashs from Synapse, as it applies an NFKC normalization to the password before hashing it.", + "description": "Whether to apply Unicode normalization to the password before hashing\n\n Defaults to `false`, and generally recommended to stay false. This is\n although recommended when importing password hashs from Synapse, as it\n applies an NFKC normalization to the password before hashing it.", "type": "boolean" }, "cost": { "description": "Cost for the bcrypt algorithm", - "default": 12, "type": "integer", "format": "uint32", - "minimum": 0.0 + "minimum": 0, + "default": 12, + "nullable": true }, "secret": { - "description": "An optional secret to use when hashing passwords. This makes it harder to brute-force the passwords in case of a database leak.", - "type": "string" + "description": "An optional secret to use when hashing passwords. This makes it harder\n to brute-force the passwords in case of a database leak.", + "type": "string", + "nullable": true }, "secret_file": { "description": "Same as `secret`, but read from a file.", - "type": "string" + "type": "string", + "nullable": true } - } + }, + "required": [ + "version", + "algorithm" + ] }, "Algorithm": { "description": "A hashing algorithm", @@ -1650,32 +1669,23 @@ { "description": "bcrypt", "type": "string", - "enum": [ - "bcrypt" - ] + "const": "bcrypt" }, { "description": "argon2id", "type": "string", - "enum": [ - "argon2id" - ] + "const": "argon2id" }, { "description": "PBKDF2", "type": "string", - "enum": [ - "pbkdf2" - ] + "const": "pbkdf2" } ] }, "MatrixConfig": { "description": "Configuration related to the Matrix homeserver", "type": "object", - "required": [ - "secret" - ], "properties": { "kind": { "description": "The kind of homeserver it is.", @@ -1688,8 +1698,8 @@ }, "homeserver": { "description": "The server name of the homeserver.", - "default": "localhost:8008", - "type": "string" + "type": "string", + "default": "localhost:8008" }, "secret": { "description": "Shared secret to use for calls to the admin API", @@ -1697,11 +1707,14 @@ }, "endpoint": { "description": "The base URL of the homeserver's client API", - "default": "http://localhost:8008/", "type": "string", - "format": "uri" + "format": "uri", + "default": "http://localhost:8008/" } - } + }, + "required": [ + "secret" + ] }, "HomeserverKind": { "description": "The kind of homeserver it is.", @@ -1709,16 +1722,12 @@ { "description": "Homeserver is Synapse", "type": "string", - "enum": [ - "synapse" - ] + "const": "synapse" }, { - "description": "Homeserver is Synapse, in read-only mode\n\nThis is meant for testing rolling out Matrix Authentication Service with no risk of writing data to the homeserver.", + "description": "Homeserver is Synapse, in read-only mode\n\n This is meant for testing rolling out Matrix Authentication Service with\n no risk of writing data to the homeserver.", "type": "string", - "enum": [ - "synapse_read_only" - ] + "const": "synapse_read_only" } ] }, @@ -1796,7 +1805,7 @@ ] }, "registration": { - "description": "Controls how many registrations attempts are permitted based on source address.", + "description": "Controls how many registrations attempts are permitted\n based on source address.", "default": { "burst": 3, "per_second": 0.0008333333333333334 @@ -1839,7 +1848,7 @@ "type": "object", "properties": { "per_ip": { - "description": "Controls how many account recovery attempts are permitted based on source IP address. This can protect against causing e-mail spam to many targets.\n\nNote: this limit also applies to re-sends.", + "description": "Controls how many account recovery attempts are permitted\n based on source IP address.\n This can protect against causing e-mail spam to many targets.\n\n Note: this limit also applies to re-sends.", "default": { "burst": 3, "per_second": 0.0008333333333333334 @@ -1851,7 +1860,7 @@ ] }, "per_address": { - "description": "Controls how many account recovery attempts are permitted based on the e-mail address entered into the recovery form. This can protect against causing e-mail spam to one target.\n\nNote: this limit also applies to re-sends.", + "description": "Controls how many account recovery attempts are permitted\n based on the e-mail address entered into the recovery form.\n This can protect against causing e-mail spam to one target.\n\n Note: this limit also applies to re-sends.", "default": { "burst": 3, "per_second": 0.0002777777777777778 @@ -1866,29 +1875,29 @@ }, "RateLimiterConfiguration": { "type": "object", - "required": [ - "burst", - "per_second" - ], "properties": { "burst": { - "description": "A one-off burst of actions that the user can perform in one go without waiting.", + "description": "A one-off burst of actions that the user can perform\n in one go without waiting.", "type": "integer", "format": "uint32", - "minimum": 1.0 + "minimum": 1 }, "per_second": { - "description": "How quickly the allowance replenishes, in number of actions per second. Can be fractional to replenish slower.", + "description": "How quickly the allowance replenishes, in number of actions per second.\n Can be fractional to replenish slower.", "type": "number", "format": "double" } - } + }, + "required": [ + "burst", + "per_second" + ] }, "LoginRateLimitingConfig": { "type": "object", "properties": { "per_ip": { - "description": "Controls how many login attempts are permitted based on source IP address. This can protect against brute force login attempts.\n\nNote: this limit also applies to password checks when a user attempts to change their own password.", + "description": "Controls how many login attempts are permitted\n based on source IP address.\n This can protect against brute force login attempts.\n\n Note: this limit also applies to password checks when a user attempts to\n change their own password.", "default": { "burst": 3, "per_second": 0.05 @@ -1900,7 +1909,7 @@ ] }, "per_account": { - "description": "Controls how many login attempts are permitted based on the account that is being attempted to be logged into. This can protect against a distributed brute force attack but should be set high enough to prevent someone's account being casually locked out.\n\nNote: this limit also applies to password checks when a user attempts to change their own password.", + "description": "Controls how many login attempts are permitted\n based on the account that is being attempted to be logged into.\n This can protect against a distributed brute force attack\n but should be set high enough to prevent someone's account being\n casually locked out.\n\n Note: this limit also applies to password checks when a user attempts to\n change their own password.", "default": { "burst": 1800, "per_second": 0.5 @@ -1917,7 +1926,7 @@ "type": "object", "properties": { "per_ip": { - "description": "Controls how many email authentication attempts are permitted based on the source IP address. This can protect against causing e-mail spam to many targets.", + "description": "Controls how many email authentication attempts are permitted\n based on the source IP address.\n This can protect against causing e-mail spam to many targets.", "default": { "burst": 5, "per_second": 0.016666666666666666 @@ -1929,7 +1938,7 @@ ] }, "per_address": { - "description": "Controls how many email authentication attempts are permitted based on the e-mail address entered into the authentication form. This can protect against causing e-mail spam to one target.\n\nNote: this limit also applies to re-sends.", + "description": "Controls how many email authentication attempts are permitted\n based on the e-mail address entered into the authentication form.\n This can protect against causing e-mail spam to one target.\n\n Note: this limit also applies to re-sends.", "default": { "burst": 3, "per_second": 0.0002777777777777778 @@ -1941,7 +1950,7 @@ ] }, "emails_per_session": { - "description": "Controls how many authentication emails are permitted to be sent per authentication session. This ensures not too many authentication codes are created for the same authentication session.", + "description": "Controls how many authentication emails are permitted to be sent per\n authentication session. This ensures not too many authentication codes\n are created for the same authentication session.", "default": { "burst": 2, "per_second": 0.0033333333333333335 @@ -1953,7 +1962,7 @@ ] }, "attempt_per_session": { - "description": "Controls how many code authentication attempts are permitted per authentication session. This can protect against brute-forcing the code.", + "description": "Controls how many code authentication attempts are permitted per\n authentication session. This can protect against brute-forcing the\n code.", "default": { "burst": 10, "per_second": 0.016666666666666666 @@ -1969,9 +1978,6 @@ "UpstreamOAuth2Config": { "description": "Upstream OAuth 2.0 providers configuration", "type": "object", - "required": [ - "providers" - ], "properties": { "providers": { "description": "List of OAuth 2.0 providers", @@ -1980,19 +1986,17 @@ "$ref": "#/definitions/Provider" } } - } + }, + "required": [ + "providers" + ] }, "Provider": { "description": "Configuration for one upstream OAuth 2 provider.", "type": "object", - "required": [ - "client_id", - "id", - "token_endpoint_auth_method" - ], "properties": { "enabled": { - "description": "Whether this provider is enabled.\n\nDefaults to `true`", + "description": "Whether this provider is enabled.\n\n Defaults to `true`", "type": "boolean" }, "id": { @@ -2001,28 +2005,33 @@ "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$" }, "synapse_idp_id": { - "description": "The ID of the provider that was used by Synapse. In order to perform a Synapse-to-MAS migration, this must be specified.\n\n## For providers that used OAuth 2.0 or OpenID Connect in Synapse\n\n### For `oidc_providers`: This should be specified as `oidc-` followed by the ID that was configured as `idp_id` in one of the `oidc_providers` in the Synapse configuration. For example, if Synapse's configuration contained `idp_id: wombat` for this provider, then specify `oidc-wombat` here.\n\n### For `oidc_config` (legacy): Specify `oidc` here.", - "type": "string" + "description": "The ID of the provider that was used by Synapse.\n In order to perform a Synapse-to-MAS migration, this must be specified.\n\n ## For providers that used OAuth 2.0 or OpenID Connect in Synapse\n\n ### For `oidc_providers`:\n This should be specified as `oidc-` followed by the ID that was\n configured as `idp_id` in one of the `oidc_providers` in the Synapse\n configuration.\n For example, if Synapse's configuration contained `idp_id: wombat` for\n this provider, then specify `oidc-wombat` here.\n\n ### For `oidc_config` (legacy):\n Specify `oidc` here.", + "type": "string", + "nullable": true }, "issuer": { - "description": "The OIDC issuer URL\n\nThis is required if OIDC discovery is enabled (which is the default)", - "type": "string" + "description": "The OIDC issuer URL\n\n This is required if OIDC discovery is enabled (which is the default)", + "type": "string", + "nullable": true }, "human_name": { "description": "A human-readable name for the provider, that will be shown to users", - "type": "string" + "type": "string", + "nullable": true }, "brand_name": { - "description": "A brand identifier used to customise the UI, e.g. `apple`, `google`, `github`, etc.\n\nValues supported by the default template are:\n\n- `apple` - `google` - `facebook` - `github` - `gitlab` - `twitter` - `discord`", - "type": "string" + "description": "A brand identifier used to customise the UI, e.g. `apple`, `google`,\n `github`, etc.\n\n Values supported by the default template are:\n\n - `apple`\n - `google`\n - `facebook`\n - `github`\n - `gitlab`\n - `twitter`\n - `discord`", + "type": "string", + "nullable": true }, "client_id": { "description": "The client ID to use when authenticating with the provider", "type": "string" }, "client_secret": { - "description": "The client secret to use when authenticating with the provider\n\nUsed by the `client_secret_basic`, `client_secret_post`, and `client_secret_jwt` methods", - "type": "string" + "description": "The client secret to use when authenticating with the provider\n\n Used by the `client_secret_basic`, `client_secret_post`, and\n `client_secret_jwt` methods", + "type": "string", + "nullable": true }, "token_endpoint_auth_method": { "description": "The method to authenticate the client with the provider", @@ -2034,22 +2043,30 @@ }, "sign_in_with_apple": { "description": "Additional parameters for the `sign_in_with_apple` method", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/SignInWithApple" + }, + { + "const": null, + "nullable": true } ] }, "token_endpoint_auth_signing_alg": { - "description": "The JWS algorithm to use when authenticating the client with the provider\n\nUsed by the `client_secret_jwt` and `private_key_jwt` methods", - "allOf": [ + "description": "The JWS algorithm to use when authenticating the client with the\n provider\n\n Used by the `client_secret_jwt` and `private_key_jwt` methods", + "anyOf": [ { "$ref": "#/definitions/JsonWebSignatureAlg" + }, + { + "const": null, + "nullable": true } ] }, "id_token_signed_response_alg": { - "description": "Expected signature for the JWT payload returned by the token authentication endpoint.\n\nDefaults to `RS256`.", + "description": "Expected signature for the JWT payload returned by the token\n authentication endpoint.\n\n Defaults to `RS256`.", "allOf": [ { "$ref": "#/definitions/JsonWebSignatureAlg" @@ -2057,11 +2074,11 @@ ] }, "scope": { - "description": "The scopes to request from the provider\n\nDefaults to `openid`.", + "description": "The scopes to request from the provider\n\n Defaults to `openid`.", "type": "string" }, "discovery_mode": { - "description": "How to discover the provider's configuration\n\nDefaults to `oidc`, which uses OIDC discovery with strict metadata verification", + "description": "How to discover the provider's configuration\n\n Defaults to `oidc`, which uses OIDC discovery with strict metadata\n verification", "allOf": [ { "$ref": "#/definitions/DiscoveryMode" @@ -2069,7 +2086,7 @@ ] }, "pkce_method": { - "description": "Whether to use proof key for code exchange (PKCE) when requesting and exchanging the token.\n\nDefaults to `auto`, which uses PKCE if the provider supports it.", + "description": "Whether to use proof key for code exchange (PKCE) when requesting and\n exchanging the token.\n\n Defaults to `auto`, which uses PKCE if the provider supports it.", "allOf": [ { "$ref": "#/definitions/PkceMethod" @@ -2077,48 +2094,60 @@ ] }, "fetch_userinfo": { - "description": "Whether to fetch the user profile from the userinfo endpoint, or to rely on the data returned in the `id_token` from the `token_endpoint`.\n\nDefaults to `false`.", - "default": false, - "type": "boolean" + "description": "Whether to fetch the user profile from the userinfo endpoint,\n or to rely on the data returned in the `id_token` from the\n `token_endpoint`.\n\n Defaults to `false`.", + "type": "boolean", + "default": false }, "userinfo_signed_response_alg": { - "description": "Expected signature for the JWT payload returned by the userinfo endpoint.\n\nIf not specified, the response is expected to be an unsigned JSON payload.", - "allOf": [ + "description": "Expected signature for the JWT payload returned by the userinfo\n endpoint.\n\n If not specified, the response is expected to be an unsigned JSON\n payload.", + "anyOf": [ { "$ref": "#/definitions/JsonWebSignatureAlg" + }, + { + "const": null, + "nullable": true } ] }, "authorization_endpoint": { - "description": "The URL to use for the provider's authorization endpoint\n\nDefaults to the `authorization_endpoint` provided through discovery", + "description": "The URL to use for the provider's authorization endpoint\n\n Defaults to the `authorization_endpoint` provided through discovery", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "userinfo_endpoint": { - "description": "The URL to use for the provider's userinfo endpoint\n\nDefaults to the `userinfo_endpoint` provided through discovery", + "description": "The URL to use for the provider's userinfo endpoint\n\n Defaults to the `userinfo_endpoint` provided through discovery", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "token_endpoint": { - "description": "The URL to use for the provider's token endpoint\n\nDefaults to the `token_endpoint` provided through discovery", + "description": "The URL to use for the provider's token endpoint\n\n Defaults to the `token_endpoint` provided through discovery", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "jwks_uri": { - "description": "The URL to use for getting the provider's public keys\n\nDefaults to the `jwks_uri` provided through discovery", + "description": "The URL to use for getting the provider's public keys\n\n Defaults to the `jwks_uri` provided through discovery", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "response_mode": { "description": "The response mode we ask the provider to use for the callback", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/ResponseMode" + }, + { + "const": null, + "nullable": true } ] }, "claims_imports": { - "description": "How claims should be imported from the `id_token` provided by the provider", + "description": "How claims should be imported from the `id_token` provided by the\n provider", "allOf": [ { "$ref": "#/definitions/ClaimsImports" @@ -2126,18 +2155,23 @@ ] }, "additional_authorization_parameters": { - "description": "Additional parameters to include in the authorization request\n\nOrders of the keys are not preserved.", + "description": "Additional parameters to include in the authorization request\n\n Orders of the keys are not preserved.", "type": "object", "additionalProperties": { "type": "string" } }, "forward_login_hint": { - "description": "Whether the `login_hint` should be forwarded to the provider in the authorization request.\n\nDefaults to `false`.", - "default": false, - "type": "boolean" + "description": "Whether the `login_hint` should be forwarded to the provider in the\n authorization request.\n\n Defaults to `false`.", + "type": "boolean", + "default": false } - } + }, + "required": [ + "id", + "client_id", + "token_endpoint_auth_method" + ] }, "TokenAuthMethod": { "description": "Authentication methods used against the OAuth 2.0 provider", @@ -2145,61 +2179,47 @@ { "description": "`none`: No authentication", "type": "string", - "enum": [ - "none" - ] + "const": "none" }, { - "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic authorization credentials", + "description": "`client_secret_basic`: `client_id` and `client_secret` used as basic\n authorization credentials", "type": "string", - "enum": [ - "client_secret_basic" - ] + "const": "client_secret_basic" }, { - "description": "`client_secret_post`: `client_id` and `client_secret` sent in the request body", + "description": "`client_secret_post`: `client_id` and `client_secret` sent in the\n request body", "type": "string", - "enum": [ - "client_secret_post" - ] + "const": "client_secret_post" }, { - "description": "`client_secret_jwt`: a `client_assertion` sent in the request body and signed using the `client_secret`", + "description": "`client_secret_jwt`: a `client_assertion` sent in the request body and\n signed using the `client_secret`", "type": "string", - "enum": [ - "client_secret_jwt" - ] + "const": "client_secret_jwt" }, { - "description": "`private_key_jwt`: a `client_assertion` sent in the request body and signed by an asymmetric key", + "description": "`private_key_jwt`: a `client_assertion` sent in the request body and\n signed by an asymmetric key", "type": "string", - "enum": [ - "private_key_jwt" - ] + "const": "private_key_jwt" }, { "description": "`sign_in_with_apple`: a special method for Signin with Apple", "type": "string", - "enum": [ - "sign_in_with_apple" - ] + "const": "sign_in_with_apple" } ] }, "SignInWithApple": { "type": "object", - "required": [ - "key_id", - "team_id" - ], "properties": { "private_key_file": { "description": "The private key file used to sign the `id_token`", - "type": "string" + "type": "string", + "nullable": true }, "private_key": { "description": "The private key used to sign the `id_token`", - "type": "string" + "type": "string", + "nullable": true }, "team_id": { "description": "The Team ID of the Apple Developer Portal", @@ -2209,7 +2229,11 @@ "description": "The key ID of the Apple Developer Portal", "type": "string" } - } + }, + "required": [ + "team_id", + "key_id" + ] }, "DiscoveryMode": { "description": "How to discover the provider's configuration", @@ -2217,49 +2241,37 @@ { "description": "Use OIDC discovery with strict metadata verification", "type": "string", - "enum": [ - "oidc" - ] + "const": "oidc" }, { "description": "Use OIDC discovery with relaxed metadata verification", "type": "string", - "enum": [ - "insecure" - ] + "const": "insecure" }, { "description": "Use a static configuration", "type": "string", - "enum": [ - "disabled" - ] + "const": "disabled" } ] }, "PkceMethod": { - "description": "Whether to use proof key for code exchange (PKCE) when requesting and exchanging the token.", + "description": "Whether to use proof key for code exchange (PKCE) when requesting and\n exchanging the token.", "oneOf": [ { - "description": "Use PKCE if the provider supports it\n\nDefaults to no PKCE if provider discovery is disabled", + "description": "Use PKCE if the provider supports it\n\n Defaults to no PKCE if provider discovery is disabled", "type": "string", - "enum": [ - "auto" - ] + "const": "auto" }, { "description": "Always use PKCE with the S256 challenge method", "type": "string", - "enum": [ - "always" - ] + "const": "always" }, { "description": "Never use PKCE", "type": "string", - "enum": [ - "never" - ] + "const": "never" } ] }, @@ -2267,18 +2279,14 @@ "description": "The response mode we ask the provider to use for the callback", "oneOf": [ { - "description": "`query`: The provider will send the response as a query string in the URL search parameters", + "description": "`query`: The provider will send the response as a query string in the\n URL search parameters", "type": "string", - "enum": [ - "query" - ] + "const": "query" }, { - "description": "`form_post`: The provider will send the response as a POST request with the response parameters in the request body\n\n", + "description": "`form_post`: The provider will send the response as a POST request with\n the response parameters in the request body\n\n ", "type": "string", - "enum": [ - "form_post" - ] + "const": "form_post" } ] }, @@ -2311,7 +2319,7 @@ ] }, "email": { - "description": "Import the email address of the user based on the `email` and `email_verified` claims", + "description": "Import the email address of the user based on the `email` and\n `email_verified` claims", "allOf": [ { "$ref": "#/definitions/EmailImportPreference" @@ -2333,8 +2341,9 @@ "type": "object", "properties": { "template": { - "description": "The Jinja2 template to use for the subject attribute\n\nIf not provided, the default template is `{{ user.sub }}`", - "type": "string" + "description": "The Jinja2 template to use for the subject attribute\n\n If not provided, the default template is `{{ user.sub }}`", + "type": "string", + "nullable": true } } }, @@ -2351,8 +2360,9 @@ ] }, "template": { - "description": "The Jinja2 template to use for the localpart attribute\n\nIf not provided, the default template is `{{ user.preferred_username }}`", - "type": "string" + "description": "The Jinja2 template to use for the localpart attribute\n\n If not provided, the default template is `{{ user.preferred_username }}`", + "type": "string", + "nullable": true } } }, @@ -2362,30 +2372,22 @@ { "description": "Ignore the claim", "type": "string", - "enum": [ - "ignore" - ] + "const": "ignore" }, { "description": "Suggest the claim value, but allow the user to change it", "type": "string", - "enum": [ - "suggest" - ] + "const": "suggest" }, { "description": "Force the claim value, but don't fail if it is missing", "type": "string", - "enum": [ - "force" - ] + "const": "force" }, { "description": "Force the claim value, and fail if it is missing", "type": "string", - "enum": [ - "require" - ] + "const": "require" } ] }, @@ -2402,8 +2404,9 @@ ] }, "template": { - "description": "The Jinja2 template to use for the displayname attribute\n\nIf not provided, the default template is `{{ user.name }}`", - "type": "string" + "description": "The Jinja2 template to use for the displayname attribute\n\n If not provided, the default template is `{{ user.name }}`", + "type": "string", + "nullable": true } } }, @@ -2420,8 +2423,9 @@ ] }, "template": { - "description": "The Jinja2 template to use for the email address attribute\n\nIf not provided, the default template is `{{ user.email }}`", - "type": "string" + "description": "The Jinja2 template to use for the email address attribute\n\n If not provided, the default template is `{{ user.email }}`", + "type": "string", + "nullable": true } } }, @@ -2430,8 +2434,9 @@ "type": "object", "properties": { "template": { - "description": "The Jinja2 template to use for the account name. This name is only used for display purposes.\n\nIf not provided, it will be ignored.", - "type": "string" + "description": "The Jinja2 template to use for the account name. This name is only used\n for display purposes.\n\n If not provided, it will be ignored.", + "type": "string", + "nullable": true } } }, @@ -2441,26 +2446,31 @@ "properties": { "service_name": { "description": "A human-readable name. Defaults to the server's address.", - "type": "string" + "type": "string", + "nullable": true }, "policy_uri": { - "description": "Link to a privacy policy, displayed in the footer of web pages and emails. It is also advertised to clients through the `op_policy_uri` OIDC provider metadata.", + "description": "Link to a privacy policy, displayed in the footer of web pages and\n emails. It is also advertised to clients through the `op_policy_uri`\n OIDC provider metadata.", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "tos_uri": { - "description": "Link to a terms of service document, displayed in the footer of web pages and emails. It is also advertised to clients through the `op_tos_uri` OIDC provider metadata.", + "description": "Link to a terms of service document, displayed in the footer of web\n pages and emails. It is also advertised to clients through the\n `op_tos_uri` OIDC provider metadata.", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true }, "imprint": { - "description": "Legal imprint, displayed in the footer in the footer of web pages and emails.", - "type": "string" + "description": "Legal imprint, displayed in the footer in the footer of web pages and\n emails.", + "type": "string", + "nullable": true }, "logo_uri": { "description": "Logo displayed in some web pages.", "type": "string", - "format": "uri" + "format": "uri", + "nullable": true } } }, @@ -2470,19 +2480,25 @@ "properties": { "service": { "description": "Which service should be used for CAPTCHA protection", - "allOf": [ + "anyOf": [ { "$ref": "#/definitions/CaptchaServiceKind" + }, + { + "const": null, + "nullable": true } ] }, "site_key": { "description": "The site key to use", - "type": "string" + "type": "string", + "nullable": true }, "secret_key": { "description": "The secret key to use", - "type": "string" + "type": "string", + "nullable": true } } }, @@ -2492,23 +2508,17 @@ { "description": "Use Google's reCAPTCHA v2 API", "type": "string", - "enum": [ - "recaptcha_v2" - ] + "const": "recaptcha_v2" }, { "description": "Use Cloudflare Turnstile", "type": "string", - "enum": [ - "cloudflare_turnstile" - ] + "const": "cloudflare_turnstile" }, { "description": "Use ``HCaptcha``", "type": "string", - "enum": [ - "hcaptcha" - ] + "const": "hcaptcha" } ] }, @@ -2517,101 +2527,106 @@ "type": "object", "properties": { "email_change_allowed": { - "description": "Whether users are allowed to change their email addresses. Defaults to `true`.", + "description": "Whether users are allowed to change their email addresses. Defaults to\n `true`.", "type": "boolean" }, "displayname_change_allowed": { - "description": "Whether users are allowed to change their display names. Defaults to `true`.\n\nThis should be in sync with the policy in the homeserver configuration.", + "description": "Whether users are allowed to change their display names. Defaults to\n `true`.\n\n This should be in sync with the policy in the homeserver configuration.", "type": "boolean" }, "password_registration_enabled": { - "description": "Whether to enable self-service password registration. Defaults to `false` if password authentication is enabled.\n\nThis has no effect if password login is disabled.", + "description": "Whether to enable self-service password registration. Defaults to\n `false` if password authentication is enabled.\n\n This has no effect if password login is disabled.", "type": "boolean" }, "password_change_allowed": { - "description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\nThis has no effect if password login is disabled.", + "description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\n This has no effect if password login is disabled.", "type": "boolean" }, "password_recovery_enabled": { - "description": "Whether email-based password recovery is enabled. Defaults to `false`.\n\nThis has no effect if password login is disabled.", + "description": "Whether email-based password recovery is enabled. Defaults to `false`.\n\n This has no effect if password login is disabled.", "type": "boolean" }, "account_deactivation_allowed": { - "description": "Whether users are allowed to delete their own account. Defaults to `true`.", + "description": "Whether users are allowed to delete their own account. Defaults to\n `true`.", "type": "boolean" }, "login_with_email_allowed": { - "description": "Whether users can log in with their email address. Defaults to `false`.\n\nThis has no effect if password login is disabled.", + "description": "Whether users can log in with their email address. Defaults to `false`.\n\n This has no effect if password login is disabled.", "type": "boolean" }, "registration_token_required": { - "description": "Whether registration tokens are required for password registrations. Defaults to `false`.\n\nWhen enabled, users must provide a valid registration token during password registration. This has no effect if password registration is disabled.", + "description": "Whether registration tokens are required for password registrations.\n Defaults to `false`.\n\n When enabled, users must provide a valid registration token during\n password registration. This has no effect if password registration\n is disabled.", "type": "boolean" } } }, "ExperimentalConfig": { - "description": "Configuration sections for experimental options\n\nDo not change these options unless you know what you are doing.", + "description": "Configuration sections for experimental options\n\n Do not change these options unless you know what you are doing.", "type": "object", "properties": { "access_token_ttl": { "description": "Time-to-live of access tokens in seconds. Defaults to 5 minutes.", "type": "integer", "format": "uint64", - "maximum": 86400.0, - "minimum": 60.0 + "minimum": 60, + "maximum": 86400 }, "compat_token_ttl": { - "description": "Time-to-live of compatibility access tokens in seconds. Defaults to 5 minutes.", + "description": "Time-to-live of compatibility access tokens in seconds. Defaults to 5\n minutes.", "type": "integer", "format": "uint64", - "maximum": 86400.0, - "minimum": 60.0 + "minimum": 60, + "maximum": 86400 }, "inactive_session_expiration": { - "description": "Experimetal feature to automatically expire inactive sessions\n\nDisabled by default", - "allOf": [ + "description": "Experimetal feature to automatically expire inactive sessions\n\n Disabled by default", + "anyOf": [ { "$ref": "#/definitions/InactiveSessionExpirationConfig" + }, + { + "const": null, + "nullable": true } ] }, "plan_management_iframe_uri": { - "description": "Experimental feature to show a plan management tab and iframe. This value is passed through \"as is\" to the client without any validation.", - "type": "string" + "description": "Experimental feature to show a plan management tab and iframe.\n This value is passed through \"as is\" to the client without any\n validation.", + "type": "string", + "nullable": true } } }, "InactiveSessionExpirationConfig": { "description": "Configuration options for the inactive session expiration feature", "type": "object", - "required": [ - "ttl" - ], "properties": { "ttl": { "description": "Time after which an inactive session is automatically finished", "type": "integer", "format": "uint64", - "maximum": 7776000.0, - "minimum": 600.0 + "minimum": 600, + "maximum": 7776000 }, "expire_compat_sessions": { "description": "Should compatibility sessions expire after inactivity", - "default": true, - "type": "boolean" + "type": "boolean", + "default": true }, "expire_oauth_sessions": { "description": "Should OAuth 2.0 sessions expire after inactivity", - "default": true, - "type": "boolean" + "type": "boolean", + "default": true }, "expire_user_sessions": { "description": "Should user sessions expire after inactivity", - "default": true, - "type": "boolean" + "type": "boolean", + "default": true } - } + }, + "required": [ + "ttl" + ] } } } \ No newline at end of file diff --git a/policies/schema/authorization_grant_input.json b/policies/schema/authorization_grant_input.json index f23bf7a73..501c46b92 100644 --- a/policies/schema/authorization_grant_input.json +++ b/policies/schema/authorization_grant_input.json @@ -3,16 +3,11 @@ "title": "AuthorizationGrantInput", "description": "Input for the authorization grant policy.", "type": "object", - "required": [ - "client", - "grant_type", - "requester", - "scope" - ], "properties": { "user": { "type": "object", - "additionalProperties": true + "additionalProperties": true, + "nullable": true }, "client": { "type": "object", @@ -28,6 +23,12 @@ "$ref": "#/definitions/Requester" } }, + "required": [ + "client", + "scope", + "grant_type", + "requester" + ], "definitions": { "GrantType": { "type": "string", @@ -44,11 +45,13 @@ "ip_address": { "description": "IP address of the entity making the request", "type": "string", - "format": "ip" + "format": "ip", + "nullable": true }, "user_agent": { "description": "User agent of the entity making the request", - "type": "string" + "type": "string", + "nullable": true } } } diff --git a/policies/schema/client_registration_input.json b/policies/schema/client_registration_input.json index 461645126..d4ffe366f 100644 --- a/policies/schema/client_registration_input.json +++ b/policies/schema/client_registration_input.json @@ -3,10 +3,6 @@ "title": "ClientRegistrationInput", "description": "Input for the client registration policy.", "type": "object", - "required": [ - "client_metadata", - "requester" - ], "properties": { "client_metadata": { "type": "object", @@ -16,6 +12,10 @@ "$ref": "#/definitions/Requester" } }, + "required": [ + "client_metadata", + "requester" + ], "definitions": { "Requester": { "description": "Identity of the requester", @@ -24,11 +24,13 @@ "ip_address": { "description": "IP address of the entity making the request", "type": "string", - "format": "ip" + "format": "ip", + "nullable": true }, "user_agent": { "description": "User agent of the entity making the request", - "type": "string" + "type": "string", + "nullable": true } } } diff --git a/policies/schema/email_input.json b/policies/schema/email_input.json index d97f291be..df6bd91fc 100644 --- a/policies/schema/email_input.json +++ b/policies/schema/email_input.json @@ -3,10 +3,6 @@ "title": "EmailInput", "description": "Input for the email add policy.", "type": "object", - "required": [ - "email", - "requester" - ], "properties": { "email": { "type": "string" @@ -15,6 +11,10 @@ "$ref": "#/definitions/Requester" } }, + "required": [ + "email", + "requester" + ], "definitions": { "Requester": { "description": "Identity of the requester", @@ -23,11 +23,13 @@ "ip_address": { "description": "IP address of the entity making the request", "type": "string", - "format": "ip" + "format": "ip", + "nullable": true }, "user_agent": { "description": "User agent of the entity making the request", - "type": "string" + "type": "string", + "nullable": true } } } diff --git a/policies/schema/register_input.json b/policies/schema/register_input.json index cd8868cd4..17b7c2f0a 100644 --- a/policies/schema/register_input.json +++ b/policies/schema/register_input.json @@ -3,11 +3,6 @@ "title": "RegisterInput", "description": "Input for the user registration policy.", "type": "object", - "required": [ - "registration_method", - "requester", - "username" - ], "properties": { "registration_method": { "$ref": "#/definitions/RegistrationMethod" @@ -16,12 +11,18 @@ "type": "string" }, "email": { - "type": "string" + "type": "string", + "nullable": true }, "requester": { "$ref": "#/definitions/Requester" } }, + "required": [ + "registration_method", + "username", + "requester" + ], "definitions": { "RegistrationMethod": { "type": "string", @@ -37,11 +38,13 @@ "ip_address": { "description": "IP address of the entity making the request", "type": "string", - "format": "ip" + "format": "ip", + "nullable": true }, "user_agent": { "description": "User agent of the entity making the request", - "type": "string" + "type": "string", + "nullable": true } } } From 4578debdc22b0e82fb54a4a3d26210e71eb5e253 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 18 Aug 2025 11:28:55 +0200 Subject: [PATCH 002/296] Switch to opentelemetry-prometheus-text-exporter --- Cargo.lock | 60 +++++++++++-------------------------- Cargo.toml | 10 ++----- crates/cli/Cargo.toml | 3 +- crates/cli/src/telemetry.rs | 55 ++++++++++++++++++---------------- deny.toml | 5 ---- 5 files changed, 49 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9879d6b8..5079ba802 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3191,12 +3191,11 @@ dependencies = [ "opentelemetry-http", "opentelemetry-jaeger-propagator", "opentelemetry-otlp", - "opentelemetry-prometheus", + "opentelemetry-prometheus-text-exporter", "opentelemetry-resource-detectors", "opentelemetry-semantic-conventions", "opentelemetry-stdout", "opentelemetry_sdk", - "prometheus", "rand 0.8.5", "rand_chacha 0.3.1", "reqwest", @@ -4172,15 +4171,14 @@ dependencies = [ ] [[package]] -name = "opentelemetry-prometheus" -version = "0.29.1" -source = "git+https://github.com/sandhose/opentelemetry-rust.git?branch=otel-prometheus-0.30#193906c7577b4f8ee642aa771191c7d80b14a297" +name = "opentelemetry-prometheus-text-exporter" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddbb5743c13741bd9207de7c449f9797c0e513ac07551eac807da94056c530d9" dependencies = [ - "once_cell", "opentelemetry", "opentelemetry_sdk", - "prometheus", - "tracing", + "smartstring", ] [[package]] @@ -4671,21 +4669,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prometheus" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" -dependencies = [ - "cfg-if", - "fnv", - "lazy_static", - "memchr", - "parking_lot", - "protobuf", - "thiserror 2.0.12", -] - [[package]] name = "prost" version = "0.13.5" @@ -4709,26 +4692,6 @@ dependencies = [ "syn", ] -[[package]] -name = "protobuf" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" -dependencies = [ - "once_cell", - "protobuf-support", - "thiserror 1.0.69", -] - -[[package]] -name = "protobuf-support" -version = "3.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" -dependencies = [ - "thiserror 1.0.69", -] - [[package]] name = "psl" version = "2.1.128" @@ -5830,6 +5793,17 @@ dependencies = [ "serde", ] +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "static_assertions", + "version_check", +] + [[package]] name = "socket2" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index b19077253..56e6388dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -407,10 +407,8 @@ version = "0.30.0" version = "0.30.0" default-features = false features = ["trace", "metrics", "http-proto"] -[workspace.dependencies.opentelemetry-prometheus] -# https://github.com/open-telemetry/opentelemetry-rust/pull/3076 -git = "https://github.com/sandhose/opentelemetry-rust.git" -branch = "otel-prometheus-0.30" +[workspace.dependencies.opentelemetry-prometheus-text-exporter] +version = "0.2.0" [workspace.dependencies.opentelemetry-resource-detectors] version = "0.9.0" [workspace.dependencies.opentelemetry-semantic-conventions] @@ -480,10 +478,6 @@ features = ["std", "pkcs5", "encryption"] [workspace.dependencies.psl] version = "2.1.128" -# Prometheus metrics -[workspace.dependencies.prometheus] -version = "0.14.0" - # High-precision clock [workspace.dependencies.quanta] version = "0.12.6" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 22def30c7..1baebd12c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -59,12 +59,11 @@ opentelemetry.workspace = true opentelemetry-http.workspace = true opentelemetry-jaeger-propagator.workspace = true opentelemetry-otlp.workspace = true -opentelemetry-prometheus.workspace = true +opentelemetry-prometheus-text-exporter.workspace = true opentelemetry-resource-detectors.workspace = true opentelemetry-semantic-conventions.workspace = true opentelemetry-stdout.workspace = true opentelemetry_sdk.workspace = true -prometheus.workspace = true sentry.workspace = true sentry-tracing.workspace = true sentry-tower.workspace = true diff --git a/crates/cli/src/telemetry.rs b/crates/cli/src/telemetry.rs index 630dcbfca..274ae770e 100644 --- a/crates/cli/src/telemetry.rs +++ b/crates/cli/src/telemetry.rs @@ -23,7 +23,7 @@ use opentelemetry::{ trace::TracerProvider as _, }; use opentelemetry_otlp::{WithExportConfig, WithHttpConfig}; -use opentelemetry_prometheus::PrometheusExporter; +use opentelemetry_prometheus_text_exporter::PrometheusExporter; use opentelemetry_sdk::{ Resource, metrics::{ManualReader, SdkMeterProvider, periodic_reader_with_async_runtime::PeriodicReader}, @@ -33,7 +33,6 @@ use opentelemetry_sdk::{ }, }; use opentelemetry_semantic_conventions as semcov; -use prometheus::Registry; use url::Url; static SCOPE: LazyLock = LazyLock::new(|| { @@ -49,7 +48,7 @@ pub static METER: LazyLock = pub static TRACER: OnceLock = OnceLock::new(); static METER_PROVIDER: OnceLock = OnceLock::new(); static TRACER_PROVIDER: OnceLock = OnceLock::new(); -static PROMETHEUS_REGISTRY: OnceLock = OnceLock::new(); +static PROMETHEUS_EXPORTER: OnceLock = OnceLock::new(); pub fn setup(config: &TelemetryConfig) -> anyhow::Result<()> { let propagator = propagator(&config.tracing.propagators); @@ -180,21 +179,30 @@ type PromServiceFuture = #[allow(clippy::needless_pass_by_value)] fn prometheus_service_fn(_req: T) -> PromServiceFuture { - use prometheus::{Encoder, TextEncoder}; + let response = if let Some(exporter) = PROMETHEUS_EXPORTER.get() { + // We'll need some space for this, so we preallocate a bit + let mut buffer = Vec::with_capacity(1024); - let response = if let Some(registry) = PROMETHEUS_REGISTRY.get() { - let mut buffer = Vec::new(); - let encoder = TextEncoder::new(); - let metric_families = registry.gather(); + if let Err(err) = exporter.export(&mut buffer) { + tracing::error!( + error = &err as &dyn std::error::Error, + "Failed to export Prometheus metrics" + ); - // That shouldn't panic, unless we're constructing invalid labels - encoder.encode(&metric_families, &mut buffer).unwrap(); - - Response::builder() - .status(200) - .header(CONTENT_TYPE, encoder.format_type()) - .body(Full::new(Bytes::from(buffer))) - .unwrap() + Response::builder() + .status(500) + .header(CONTENT_TYPE, "text/plain") + .body(Full::new(Bytes::from_static( + b"Failed to export Prometheus metrics, see logs for details", + ))) + .unwrap() + } else { + Response::builder() + .status(200) + .header(CONTENT_TYPE, "text/plain;version=1.0.0") + .body(Full::new(Bytes::from(buffer))) + .unwrap() + } } else { Response::builder() .status(500) @@ -209,7 +217,7 @@ fn prometheus_service_fn(_req: T) -> PromServiceFuture { } pub fn prometheus_service() -> tower::util::ServiceFn PromServiceFuture> { - if PROMETHEUS_REGISTRY.get().is_none() { + if PROMETHEUS_EXPORTER.get().is_none() { tracing::warn!( "A Prometheus resource was mounted on a listener, but the Prometheus exporter was not setup in the config" ); @@ -219,16 +227,11 @@ pub fn prometheus_service() -> tower::util::ServiceFn PromServiceFut } fn prometheus_metric_reader() -> anyhow::Result { - let registry = Registry::new(); + let exporter = PrometheusExporter::builder().without_scope_info().build(); - PROMETHEUS_REGISTRY - .set(registry.clone()) - .map_err(|_| anyhow::anyhow!("PROMETHEUS_REGISTRY was set twice"))?; - - let exporter = opentelemetry_prometheus::exporter() - .with_registry(registry) - .without_scope_info() - .build()?; + PROMETHEUS_EXPORTER + .set(exporter.clone()) + .map_err(|_| anyhow::anyhow!("PROMETHEUS_EXPORTER was set twice"))?; Ok(exporter) } diff --git a/deny.toml b/deny.toml index 508816d14..0d09c790f 100644 --- a/deny.toml +++ b/deny.toml @@ -98,8 +98,3 @@ deny = ["oldtime"] unknown-registry = "warn" unknown-git = "warn" allow-registry = ["https://github.com/rust-lang/crates.io-index"] - -allow-git = [ - # https://github.com/open-telemetry/opentelemetry-rust/pull/3076 - "https://github.com/sandhose/opentelemetry-rust", -] From 683fcb8eb03b406930aa4cf98dabf63db16bd719 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Sat, 30 Aug 2025 18:01:22 +0200 Subject: [PATCH 003/296] Trim matrix secret when read from file Treat the secret the same as synapse when read from file a file, so that the same secret file can be reused between mas and synapse. https://github.com/element-hq/synapse/blob/v1.137.0/synapse/config/experimental.py#L50 --- crates/config/src/sections/matrix.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/config/src/sections/matrix.rs b/crates/config/src/sections/matrix.rs index e2330a7a5..1b08c1a07 100644 --- a/crates/config/src/sections/matrix.rs +++ b/crates/config/src/sections/matrix.rs @@ -131,7 +131,11 @@ impl MatrixConfig { /// Returns an error when the shared secret could not be read from file. pub async fn secret(&self) -> anyhow::Result { Ok(match &self.secret { - Secret::File(path) => tokio::fs::read_to_string(path).await?, + Secret::File(path) => { + let raw = tokio::fs::read_to_string(path).await?; + // Trim the secret when read from file to match Synapse's behaviour + raw.trim().to_string() + } Secret::Value(secret) => secret.clone(), }) } From 73f4002cccaf08dbe4bfeb83cae3489bfc6ee66c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 08:47:27 +0000 Subject: [PATCH 004/296] build(deps): bump bitflags from 2.9.3 to 2.9.4 Bumps [bitflags](https://github.com/bitflags/bitflags) from 2.9.3 to 2.9.4. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/2.9.3...2.9.4) --- updated-dependencies: - dependency-name: bitflags dependency-version: 2.9.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81e19a7cd..e38736e5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -732,9 +732,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index bcf597178..183d28e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -129,7 +129,7 @@ default-features = true # Packed bitfields [workspace.dependencies.bitflags] -version = "2.9.3" +version = "2.9.4" # Bytes [workspace.dependencies.bytes] From bb2093ea322bd6bc9740e846a1b55ee93f9681ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 09:43:15 +0000 Subject: [PATCH 005/296] build(deps): bump uuid from 1.18.0 to 1.18.1 Bumps [uuid](https://github.com/uuid-rs/uuid) from 1.18.0 to 1.18.1. - [Release notes](https://github.com/uuid-rs/uuid/releases) - [Commits](https://github.com/uuid-rs/uuid/compare/v1.18.0...v1.18.1) --- updated-dependencies: - dependency-name: uuid dependency-version: 1.18.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81e19a7cd..6c87cbd37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6827,9 +6827,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "js-sys", "serde", diff --git a/Cargo.toml b/Cargo.toml index bcf597178..adf6e588e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -712,7 +712,7 @@ features = ["serde", "uuid"] # UUID support [workspace.dependencies.uuid] -version = "1.18.0" +version = "1.18.1" # HTML escaping [workspace.dependencies.v_htmlescape] From da4c45c6b4f9d32f433dfbb07952625309be0e28 Mon Sep 17 00:00:00 2001 From: Twilight Sparkle Date: Wed, 3 Sep 2025 14:27:54 +0000 Subject: [PATCH 006/296] Request a refresh token in device-code-grant.sh --- misc/device-code-grant.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/device-code-grant.sh b/misc/device-code-grant.sh index c77101cb5..a89c26fd2 100755 --- a/misc/device-code-grant.sh +++ b/misc/device-code-grant.sh @@ -45,7 +45,7 @@ RESP="$( { "client_name": "CLI tool", "client_uri": "https://github.com/element-hq/matrix-authentication-service/", - "grant_types": ["urn:ietf:params:oauth:grant-type:device_code"], + "grant_types": ["urn:ietf:params:oauth:grant-type:device_code","refresh_token"], "application_type": "native", "token_endpoint_auth_method": "none" } From 0d2246d172299c12b777dd84064b3abe6b864448 Mon Sep 17 00:00:00 2001 From: Twilight Sparkle Date: Wed, 3 Sep 2025 14:34:26 +0000 Subject: [PATCH 007/296] Mention the refresh token in the docs --- docs/topics/access-token.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/access-token.md b/docs/topics/access-token.md index 1d898cd89..16acc4a10 100644 --- a/docs/topics/access-token.md +++ b/docs/topics/access-token.md @@ -8,7 +8,7 @@ This can be run from anywhere, not necessarily from the host where MAS is runnin sh ./misc/device-code-grant.sh [synapse-url] ... ``` -This will prompt you to open a URL in your browser, finish the authentication flow, and print the access token. +This will prompt you to open a URL in your browser, finish the authentication flow, and print the access and refresh tokens. This can be used to get access to the MAS admin API: From ac5db76e71a10518c69802a34f08572159a41027 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Wed, 3 Sep 2025 11:29:49 -0400 Subject: [PATCH 008/296] Allow more characters in redirect URI paths Allow all unreserved characters permitted in URI paths according to https://www.rfc-editor.org/rfc/rfc3986#section-3.3 --- policies/client_registration/client_registration.rego | 2 +- policies/client_registration/client_registration_test.rego | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/policies/client_registration/client_registration.rego b/policies/client_registration/client_registration.rego index a257bd599..544a9126c 100644 --- a/policies/client_registration/client_registration.rego +++ b/policies/client_registration/client_registration.rego @@ -18,7 +18,7 @@ allow if { parse_uri(url) := obj if { is_string(url) - url_regex := `^(?P[a-z][a-z0-9+.-]*):(?://(?P((?:(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])|127.0.0.1|0.0.0.0|\[::1\])(?::(?P[0-9]+))?))?(?P/[A-Za-z0-9/.-]*)?(?P\?[-a-zA-Z0-9()@:%_+.~#?&/=]*)?$` + url_regex := `^(?P[a-z][a-z0-9+.-]*):(?://(?P((?:(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])|127.0.0.1|0.0.0.0|\[::1\])(?::(?P[0-9]+))?))?(?P/[A-Za-z0-9/.-_~]*)?(?P\?[-a-zA-Z0-9()@:%_+.~#?&/=]*)?$` [matches] := regex.find_all_string_submatch_n(url_regex, url, 1) obj := {"scheme": matches[1], "authority": matches[2], "host": matches[3], "port": matches[4], "path": matches[5], "query": matches[6]} } diff --git a/policies/client_registration/client_registration_test.rego b/policies/client_registration/client_registration_test.rego index 60df994c6..b0c66104e 100644 --- a/policies/client_registration/client_registration_test.rego +++ b/policies/client_registration/client_registration_test.rego @@ -217,7 +217,7 @@ test_web_redirect_uri if { client_registration.allow with input.client_metadata as { "application_type": "web", "client_uri": "https://example.com/", - "redirect_uris": ["https://example.com/second/callback", "https://example.com/callback", "https://example.com/callback?query=value"], + "redirect_uris": ["https://example.com/second/callback", "https://example.com/callback", "https://example.com/callback?query=value", "https://example.com/callback~path_with_extra_chars"], } client_registration.allow with input.client_metadata as { From b2d7e2d83514ea34b92b304b6b768aa1187b7070 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Wed, 3 Sep 2025 12:56:21 -0400 Subject: [PATCH 009/296] Don't mistakenly invoke a regex range expression --- policies/client_registration/client_registration.rego | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policies/client_registration/client_registration.rego b/policies/client_registration/client_registration.rego index 544a9126c..48ffc0c27 100644 --- a/policies/client_registration/client_registration.rego +++ b/policies/client_registration/client_registration.rego @@ -18,7 +18,7 @@ allow if { parse_uri(url) := obj if { is_string(url) - url_regex := `^(?P[a-z][a-z0-9+.-]*):(?://(?P((?:(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])|127.0.0.1|0.0.0.0|\[::1\])(?::(?P[0-9]+))?))?(?P/[A-Za-z0-9/.-_~]*)?(?P\?[-a-zA-Z0-9()@:%_+.~#?&/=]*)?$` + url_regex := `^(?P[a-z][a-z0-9+.-]*):(?://(?P((?:(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])|127.0.0.1|0.0.0.0|\[::1\])(?::(?P[0-9]+))?))?(?P/[A-Za-z0-9/._~-]*)?(?P\?[-a-zA-Z0-9()@:%_+.~#?&/=]*)?$` [matches] := regex.find_all_string_submatch_n(url_regex, url, 1) obj := {"scheme": matches[1], "authority": matches[2], "host": matches[3], "port": matches[4], "path": matches[5], "query": matches[6]} } From e0c56cc1a80eb08d5580094ee7033063f2cb783b Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Wed, 3 Sep 2025 15:07:04 -0400 Subject: [PATCH 010/296] Documentation: update links to policy files --- docs/topics/policy.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/topics/policy.md b/docs/topics/policy.md index 9155c2211..7ea1c2c93 100644 --- a/docs/topics/policy.md +++ b/docs/topics/policy.md @@ -24,11 +24,10 @@ As such, they usually can be bypassed through the admin API or the CLI if needed ### User attributes -The policy is evaluated in three different scenarios: +The policy is evaluated in the following different scenarios: - - [`register.rego`]: During user registration, either with password credentials or with an upstream OAuth 2.0 provider. This calls the [`email.rego`] and [`password.rego`] policies as well. + - [`register.rego`]: During user registration, either with password credentials or with an upstream OAuth 2.0 provider. This calls the [`email.rego`] policy as well. - [`email.rego`]: When a user adds a new email address to their account. - - [`password.rego`]: When a user changes their password. ### Client registration @@ -69,8 +68,7 @@ This is especially important as in the future it will make it possible to implem To understand the authorization process and how sessions are created, refer to the [authorization and sessions](./authorization.md) section. -[`register.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/register.rego -[`email.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/email.rego -[`password.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/password.rego -[`client_registration.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/client_registration.rego -[`authorization_grant.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/authorization_grant.rego +[`register.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/register/register.rego +[`email.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/email/email.rego +[`client_registration.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/client_registration/client_registration.rego +[`authorization_grant.rego`]: https://github.com/element-hq/matrix-authentication-service/blob/main/policies/authorization_grant/authorization_grant.rego From 39fa640671998e38b40fd38465b89bfdeb25dd47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:35:11 +0000 Subject: [PATCH 011/296] build(deps): bump actions/setup-node from 4.4.0 to 5.0.0 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.4.0 to 5.0.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4.4.0...v5.0.0) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yaml | 6 +++--- .github/workflows/docs.yaml | 2 +- .github/workflows/release-branch.yaml | 2 +- .github/workflows/translations-download.yaml | 2 +- .github/workflows/translations-upload.yaml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 50ef76b8c..93c3b1b5f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -63,7 +63,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 @@ -87,7 +87,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 @@ -111,7 +111,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 20 diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index a0ebd9361..b33847ca3 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -39,7 +39,7 @@ jobs: tool: mdbook - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 diff --git a/.github/workflows/release-branch.yaml b/.github/workflows/release-branch.yaml index 1d52cd60b..3bd4248ec 100644 --- a/.github/workflows/release-branch.yaml +++ b/.github/workflows/release-branch.yaml @@ -64,7 +64,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 diff --git a/.github/workflows/translations-download.yaml b/.github/workflows/translations-download.yaml index 1832e2b9c..8694c24a9 100644 --- a/.github/workflows/translations-download.yaml +++ b/.github/workflows/translations-download.yaml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 diff --git a/.github/workflows/translations-upload.yaml b/.github/workflows/translations-upload.yaml index 3121617a4..2ca273b4c 100644 --- a/.github/workflows/translations-upload.yaml +++ b/.github/workflows/translations-upload.yaml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v5 - name: Install Node - uses: actions/setup-node@v4.4.0 + uses: actions/setup-node@v5.0.0 with: node-version: 22 From 9e15f139d6dfbd2e237b29b9311c543aa9edba09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:11:55 +0000 Subject: [PATCH 012/296] build(deps): bump actions/github-script from 7.0.1 to 8.0.0 Bumps [actions/github-script](https://github.com/actions/github-script) from 7.0.1 to 8.0.0. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v7.0.1...v8.0.0) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yaml | 4 ++-- .github/workflows/merge-back.yaml | 2 +- .github/workflows/release-branch.yaml | 2 +- .github/workflows/release-bump.yaml | 2 +- .github/workflows/tag.yaml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f17962b3c..a5720b1bc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -389,7 +389,7 @@ jobs: merge-multiple: true - name: Update unstable git tag - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 with: script: | const script = require('./.github/scripts/update-unstable-tag.cjs'); @@ -460,7 +460,7 @@ jobs: .github/scripts - name: Remove label and comment - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 env: BUILD_IMAGE_MANIFEST: ${{ needs.build-image.outputs.metadata }} with: diff --git a/.github/workflows/merge-back.yaml b/.github/workflows/merge-back.yaml index 17b0e0804..d28d68c20 100644 --- a/.github/workflows/merge-back.yaml +++ b/.github/workflows/merge-back.yaml @@ -30,7 +30,7 @@ jobs: .github/scripts - name: Push branch and open a PR - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 env: SHA: ${{ inputs.sha }} with: diff --git a/.github/workflows/release-branch.yaml b/.github/workflows/release-branch.yaml index 1d52cd60b..6a43fe49f 100644 --- a/.github/workflows/release-branch.yaml +++ b/.github/workflows/release-branch.yaml @@ -112,7 +112,7 @@ jobs: .github/scripts - name: Create a new release branch - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 env: BRANCH: release/v${{ needs.compute-version.outputs.short }} SHA: ${{ needs.tag.outputs.sha }} diff --git a/.github/workflows/release-bump.yaml b/.github/workflows/release-bump.yaml index 22b157a5e..46251a410 100644 --- a/.github/workflows/release-bump.yaml +++ b/.github/workflows/release-bump.yaml @@ -82,7 +82,7 @@ jobs: .github/scripts - name: Update the release branch - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 env: BRANCH: "${{ github.ref_name }}" SHA: ${{ needs.tag.outputs.sha }} diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index cf894e8af..ec3ea290d 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -46,7 +46,7 @@ jobs: run: cargo metadata --format-version 1 - name: Commit and tag using the GitHub API - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 id: commit env: VERSION: ${{ inputs.version }} @@ -58,7 +58,7 @@ jobs: return await script({ core, github, context }); - name: Update the refs - uses: actions/github-script@v7.0.1 + uses: actions/github-script@v8.0.0 env: VERSION: ${{ inputs.version }} TAG_SHA: ${{ fromJSON(steps.commit.outputs.result).tag }} From b9961172eec680bf68e373ef645cec553e427def Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:12:01 +0000 Subject: [PATCH 013/296] build(deps): bump codecov/codecov-action from 5.5.0 to 5.5.1 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.5.0 to 5.5.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v5.5.0...v5.5.1) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 5.5.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/coverage.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 3ac22da5d..3046f45cc 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -38,7 +38,7 @@ jobs: run: make coverage - name: Upload to codecov.io - uses: codecov/codecov-action@v5.5.0 + uses: codecov/codecov-action@v5.5.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: policies/coverage.json @@ -65,7 +65,7 @@ jobs: run: npm run coverage - name: Upload to codecov.io - uses: codecov/codecov-action@v5.5.0 + uses: codecov/codecov-action@v5.5.1 with: token: ${{ secrets.CODECOV_TOKEN }} directory: frontend/coverage/ @@ -132,7 +132,7 @@ jobs: grcov . --binary-path ./target/debug/deps/ -s . -t lcov --branch --ignore-not-existing --ignore '../*' --ignore "/*" -o target/coverage/tests.lcov - name: Upload to codecov.io - uses: codecov/codecov-action@v5.5.0 + uses: codecov/codecov-action@v5.5.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: target/coverage/*.lcov From cb83bee6d398f4c3f3dfd58f18cf74fce794f225 Mon Sep 17 00:00:00 2001 From: Leon Wilzer Date: Fri, 5 Sep 2025 13:28:47 +0200 Subject: [PATCH 014/296] make token_endpoint_auth_signing_alg_values_supported optional token_endpoint_auth_signing_alg_values_supported is an optional value according to OIDC spec --- crates/oauth2-types/src/oidc.rs | 77 +++++++-------------------------- 1 file changed, 15 insertions(+), 62 deletions(-) diff --git a/crates/oauth2-types/src/oidc.rs b/crates/oauth2-types/src/oidc.rs index 39e1074b1..9ac67278b 100644 --- a/crates/oauth2-types/src/oidc.rs +++ b/crates/oauth2-types/src/oidc.rs @@ -692,10 +692,6 @@ impl ProviderMetadata { .token_endpoint_auth_signing_alg_values_supported .iter() .flatten(), - metadata - .token_endpoint_auth_methods_supported - .iter() - .flatten(), )?; if let Some(url) = &metadata.revocation_endpoint { @@ -708,33 +704,18 @@ impl ProviderMetadata { .revocation_endpoint_auth_signing_alg_values_supported .iter() .flatten(), - metadata - .revocation_endpoint_auth_methods_supported - .iter() - .flatten(), )?; if let Some(url) = &metadata.introspection_endpoint { validate_url("introspection_endpoint", url, ExtraUrlRestrictions::None)?; } - // The list can also contain token types so remove them as we don't need to - // check them. - let introspection_methods = metadata - .introspection_endpoint_auth_methods_supported - .as_ref() - .map(|v| { - v.iter() - .filter_map(AuthenticationMethodOrAccessTokenType::authentication_method) - .collect::>() - }); validate_signing_alg_values_supported( "introspection_endpoint", metadata .introspection_endpoint_auth_signing_alg_values_supported .iter() .flatten(), - introspection_methods.into_iter().flatten(), )?; if let Some(url) = &metadata.userinfo_endpoint { @@ -1099,12 +1080,6 @@ pub enum ProviderMetadataVerificationError { #[error("missing `implicit` grant type")] GrantTypesMissingImplicit, - /// The given endpoint is missing auth signing algorithm values, but they - /// are required because it supports at least one of the `client_secret_jwt` - /// or `private_key_jwt` authentication methods. - #[error("{0} missing auth signing algorithm values")] - MissingAuthSigningAlgValues(&'static str), - /// `none` is in the given endpoint's signing algorithm values, but is not /// allowed. #[error("{0} signing algorithm values contain `none`")] @@ -1176,32 +1151,14 @@ fn validate_url( fn validate_signing_alg_values_supported<'a>( endpoint: &'static str, values: impl Iterator, - mut methods: impl Iterator, ) -> Result<(), ProviderMetadataVerificationError> { - let mut no_values = true; - for value in values { if *value == JsonWebSignatureAlg::None { return Err(ProviderMetadataVerificationError::SigningAlgValuesWithNone( endpoint, )); } - - no_values = false; } - - if no_values - && methods.any(|method| { - matches!( - method, - OAuthClientAuthenticationMethod::ClientSecretJwt - | OAuthClientAuthenticationMethod::PrivateKeyJwt - ) - }) - { - return Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)); - } - Ok(()) } @@ -1543,34 +1500,30 @@ mod tests { Some(vec![JsonWebSignatureAlg::Rs256, JsonWebSignatureAlg::EdDsa]); metadata.clone().validate(&issuer).unwrap(); - // Err - `client_secret_jwt` without signing alg values. + // Ok - `client_secret_jwt` with signing alg values. metadata.token_endpoint_auth_methods_supported = Some(vec![OAuthClientAuthenticationMethod::ClientSecretJwt]); - metadata.token_endpoint_auth_signing_alg_values_supported = None; - let endpoint = assert_matches!( - metadata.clone().validate(&issuer), - Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)) => endpoint - ); - assert_eq!(endpoint, "token_endpoint"); - - // Ok - `client_secret_jwt` with signing alg values. metadata.token_endpoint_auth_signing_alg_values_supported = Some(vec![JsonWebSignatureAlg::Rs256]); metadata.clone().validate(&issuer).unwrap(); - // Err - `private_key_jwt` without signing alg values. + // Ok - `private_key_jwt` with signing alg values. + metadata.token_endpoint_auth_methods_supported = + Some(vec![OAuthClientAuthenticationMethod::PrivateKeyJwt]); + metadata.token_endpoint_auth_signing_alg_values_supported = + Some(vec![JsonWebSignatureAlg::Rs256]); + metadata.clone().validate(&issuer).unwrap(); + + // Ok - `client_secret_jwt` without signing alg values. + metadata.token_endpoint_auth_methods_supported = + Some(vec![OAuthClientAuthenticationMethod::ClientSecretJwt]); + metadata.token_endpoint_auth_signing_alg_values_supported = None; + metadata.clone().validate(&issuer).unwrap(); + + // Ok - `private_key_jwt` without signing alg values. metadata.token_endpoint_auth_methods_supported = Some(vec![OAuthClientAuthenticationMethod::PrivateKeyJwt]); metadata.token_endpoint_auth_signing_alg_values_supported = None; - let endpoint = assert_matches!( - metadata.clone().validate(&issuer), - Err(ProviderMetadataVerificationError::MissingAuthSigningAlgValues(endpoint)) => endpoint - ); - assert_eq!(endpoint, "token_endpoint"); - - // Ok - `private_key_jwt` with signing alg values. - metadata.token_endpoint_auth_signing_alg_values_supported = - Some(vec![JsonWebSignatureAlg::Rs256]); metadata.clone().validate(&issuer).unwrap(); // Ok - Other auth methods without signing alg values. From cffda30260d7e10b41a6522eb7bef9cc0a79ccd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:25:18 +0000 Subject: [PATCH 015/296] build(deps): bump softprops/action-gh-release from 2.3.2 to 2.3.3 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.2 to 2.3.3. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2.3.2...v2.3.3) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 2.3.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f17962b3c..c234c8288 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -327,7 +327,7 @@ jobs: merge-multiple: true - name: Prepare a release - uses: softprops/action-gh-release@v2.3.2 + uses: softprops/action-gh-release@v2.3.3 with: generate_release_notes: true body: | @@ -396,7 +396,7 @@ jobs: await script({ core, github, context }); - name: Update unstable release - uses: softprops/action-gh-release@v2.3.2 + uses: softprops/action-gh-release@v2.3.3 with: name: "Unstable build" tag_name: unstable From 86a51a97acbfc6b5d9079953165645b1e6e9d4ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 13:26:56 +0000 Subject: [PATCH 016/296] build(deps): bump psl from 2.1.136 to 2.1.140 Bumps [psl](https://github.com/addr-rs/psl) from 2.1.136 to 2.1.140. - [Release notes](https://github.com/addr-rs/psl/releases) - [Commits](https://github.com/addr-rs/psl/compare/v2.1.136...v2.1.140) --- updated-dependencies: - dependency-name: psl dependency-version: 2.1.140 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29350974d..6ac0f0a1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4727,9 +4727,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.136" +version = "2.1.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4d5ec1bed313b61a9d525e8549493538aea497056a5484f5398b1a05bb8261" +checksum = "89a33878b44e45231ecbc8c619cc8059e4adab882b25812192676fe08dcf352f" dependencies = [ "psl-types", ] diff --git a/Cargo.toml b/Cargo.toml index 77758f1a1..b5c0d0a74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -478,7 +478,7 @@ features = ["std", "pkcs5", "encryption"] # Public Suffix List [workspace.dependencies.psl] -version = "2.1.136" +version = "2.1.140" # Prometheus metrics [workspace.dependencies.prometheus] From a643094f92a363f0dc703a7168ffd8889f9a20ff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:19:26 +0000 Subject: [PATCH 017/296] Translations updates --- frontend/.storybook/locales.ts | 62 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts index 090812bf0..3c370a041 100644 --- a/frontend/.storybook/locales.ts +++ b/frontend/.storybook/locales.ts @@ -27,7 +27,7 @@ export type LocalazyMetadata = { }; const localazyMetadata: LocalazyMetadata = { - projectUrl: "https://localazy.com/p/matrix-authentication-service", + projectUrl: "https://localazy.com/p/matrix-authentication-service!v1.2", baseLocale: "en", languages: [ { @@ -172,21 +172,21 @@ const localazyMetadata: LocalazyMetadata = { file: "frontend.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", - "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", - "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", - "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", - "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", - "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", - "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", - "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", - "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", - "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", - "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", - "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", - "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", - "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", - "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" + "cs": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", + "da": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", + "de": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", + "en": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", + "et": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", + "fi": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", + "fr": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", + "hu": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", + "nb_NO": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", + "nl": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", + "pt": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", + "ru": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", + "sv": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", + "uk": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", + "zh#Hans": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" } }, { @@ -194,21 +194,21 @@ const localazyMetadata: LocalazyMetadata = { file: "file.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", - "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", - "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", - "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", - "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", - "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", - "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", - "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", - "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", - "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", - "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", - "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", - "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", - "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", - "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" + "cs": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", + "da": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", + "de": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", + "en": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", + "et": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", + "fi": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", + "fr": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", + "hu": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", + "nb_NO": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", + "nl": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", + "pt": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", + "ru": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", + "sv": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", + "uk": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", + "zh#Hans": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" } } ] From 07b4c292bc11e7f44f6d7e745d6fbb92a62dc556 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:27:37 +0000 Subject: [PATCH 018/296] 1.2.0 --- Cargo.lock | 56 +++++++++++++++++++++++++------------------------- Cargo.toml | 60 +++++++++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29350974d..7b6d93227 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3117,7 +3117,7 @@ dependencies = [ [[package]] name = "mas-axum-utils" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "axum", @@ -3151,7 +3151,7 @@ dependencies = [ [[package]] name = "mas-cli" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "axum", @@ -3225,7 +3225,7 @@ dependencies = [ [[package]] name = "mas-config" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "camino", @@ -3257,7 +3257,7 @@ dependencies = [ [[package]] name = "mas-context" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "console", "opentelemetry", @@ -3273,7 +3273,7 @@ dependencies = [ [[package]] name = "mas-data-model" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "base64ct", "chrono", @@ -3296,7 +3296,7 @@ dependencies = [ [[package]] name = "mas-email" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "async-trait", "lettre", @@ -3307,7 +3307,7 @@ dependencies = [ [[package]] name = "mas-handlers" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "aide", "anyhow", @@ -3387,7 +3387,7 @@ dependencies = [ [[package]] name = "mas-http" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "futures-util", "headers", @@ -3408,7 +3408,7 @@ dependencies = [ [[package]] name = "mas-i18n" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "camino", "icu_calendar", @@ -3430,7 +3430,7 @@ dependencies = [ [[package]] name = "mas-i18n-scan" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "camino", "clap", @@ -3444,7 +3444,7 @@ dependencies = [ [[package]] name = "mas-iana" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "schemars 0.8.22", "serde", @@ -3452,7 +3452,7 @@ dependencies = [ [[package]] name = "mas-iana-codegen" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "async-trait", @@ -3468,7 +3468,7 @@ dependencies = [ [[package]] name = "mas-jose" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "base64ct", "chrono", @@ -3498,7 +3498,7 @@ dependencies = [ [[package]] name = "mas-keystore" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "aead", "base64ct", @@ -3526,7 +3526,7 @@ dependencies = [ [[package]] name = "mas-listener" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "bytes", @@ -3551,7 +3551,7 @@ dependencies = [ [[package]] name = "mas-matrix" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "async-trait", @@ -3561,7 +3561,7 @@ dependencies = [ [[package]] name = "mas-matrix-synapse" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "async-trait", @@ -3578,7 +3578,7 @@ dependencies = [ [[package]] name = "mas-oidc-client" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "assert_matches", "async-trait", @@ -3614,7 +3614,7 @@ dependencies = [ [[package]] name = "mas-policy" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "arc-swap", @@ -3631,7 +3631,7 @@ dependencies = [ [[package]] name = "mas-router" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "axum", "serde", @@ -3642,7 +3642,7 @@ dependencies = [ [[package]] name = "mas-spa" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "camino", "serde", @@ -3651,7 +3651,7 @@ dependencies = [ [[package]] name = "mas-storage" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "async-trait", "chrono", @@ -3673,7 +3673,7 @@ dependencies = [ [[package]] name = "mas-storage-pg" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "async-trait", "chrono", @@ -3700,7 +3700,7 @@ dependencies = [ [[package]] name = "mas-tasks" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "async-trait", @@ -3732,7 +3732,7 @@ dependencies = [ [[package]] name = "mas-templates" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "arc-swap", @@ -3762,7 +3762,7 @@ dependencies = [ [[package]] name = "mas-tower" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "http", "opentelemetry", @@ -4032,7 +4032,7 @@ dependencies = [ [[package]] name = "oauth2-types" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "assert_matches", "base64ct", @@ -6147,7 +6147,7 @@ dependencies = [ [[package]] name = "syn2mas" -version = "1.2.0-rc.0" +version = "1.2.0" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 77758f1a1..44dc8990f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = ["crates/*"] resolver = "2" # Updated in the CI with a `sed` command -package.version = "1.2.0-rc.0" +package.version = "1.2.0" package.license = "AGPL-3.0-only OR LicenseRef-Element-Commercial" package.authors = ["Element Backend Team"] package.edition = "2024" @@ -34,35 +34,35 @@ broken_intra_doc_links = "deny" [workspace.dependencies] # Workspace crates -mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.2.0-rc.0" } -mas-cli = { path = "./crates/cli/", version = "=1.2.0-rc.0" } -mas-config = { path = "./crates/config/", version = "=1.2.0-rc.0" } -mas-context = { path = "./crates/context/", version = "=1.2.0-rc.0" } -mas-data-model = { path = "./crates/data-model/", version = "=1.2.0-rc.0" } -mas-email = { path = "./crates/email/", version = "=1.2.0-rc.0" } -mas-graphql = { path = "./crates/graphql/", version = "=1.2.0-rc.0" } -mas-handlers = { path = "./crates/handlers/", version = "=1.2.0-rc.0" } -mas-http = { path = "./crates/http/", version = "=1.2.0-rc.0" } -mas-i18n = { path = "./crates/i18n/", version = "=1.2.0-rc.0" } -mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.2.0-rc.0" } -mas-iana = { path = "./crates/iana/", version = "=1.2.0-rc.0" } -mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.2.0-rc.0" } -mas-jose = { path = "./crates/jose/", version = "=1.2.0-rc.0" } -mas-keystore = { path = "./crates/keystore/", version = "=1.2.0-rc.0" } -mas-listener = { path = "./crates/listener/", version = "=1.2.0-rc.0" } -mas-matrix = { path = "./crates/matrix/", version = "=1.2.0-rc.0" } -mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.2.0-rc.0" } -mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.2.0-rc.0" } -mas-policy = { path = "./crates/policy/", version = "=1.2.0-rc.0" } -mas-router = { path = "./crates/router/", version = "=1.2.0-rc.0" } -mas-spa = { path = "./crates/spa/", version = "=1.2.0-rc.0" } -mas-storage = { path = "./crates/storage/", version = "=1.2.0-rc.0" } -mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.2.0-rc.0" } -mas-tasks = { path = "./crates/tasks/", version = "=1.2.0-rc.0" } -mas-templates = { path = "./crates/templates/", version = "=1.2.0-rc.0" } -mas-tower = { path = "./crates/tower/", version = "=1.2.0-rc.0" } -oauth2-types = { path = "./crates/oauth2-types/", version = "=1.2.0-rc.0" } -syn2mas = { path = "./crates/syn2mas", version = "=1.2.0-rc.0" } +mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.2.0" } +mas-cli = { path = "./crates/cli/", version = "=1.2.0" } +mas-config = { path = "./crates/config/", version = "=1.2.0" } +mas-context = { path = "./crates/context/", version = "=1.2.0" } +mas-data-model = { path = "./crates/data-model/", version = "=1.2.0" } +mas-email = { path = "./crates/email/", version = "=1.2.0" } +mas-graphql = { path = "./crates/graphql/", version = "=1.2.0" } +mas-handlers = { path = "./crates/handlers/", version = "=1.2.0" } +mas-http = { path = "./crates/http/", version = "=1.2.0" } +mas-i18n = { path = "./crates/i18n/", version = "=1.2.0" } +mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.2.0" } +mas-iana = { path = "./crates/iana/", version = "=1.2.0" } +mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.2.0" } +mas-jose = { path = "./crates/jose/", version = "=1.2.0" } +mas-keystore = { path = "./crates/keystore/", version = "=1.2.0" } +mas-listener = { path = "./crates/listener/", version = "=1.2.0" } +mas-matrix = { path = "./crates/matrix/", version = "=1.2.0" } +mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.2.0" } +mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.2.0" } +mas-policy = { path = "./crates/policy/", version = "=1.2.0" } +mas-router = { path = "./crates/router/", version = "=1.2.0" } +mas-spa = { path = "./crates/spa/", version = "=1.2.0" } +mas-storage = { path = "./crates/storage/", version = "=1.2.0" } +mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.2.0" } +mas-tasks = { path = "./crates/tasks/", version = "=1.2.0" } +mas-templates = { path = "./crates/templates/", version = "=1.2.0" } +mas-tower = { path = "./crates/tower/", version = "=1.2.0" } +oauth2-types = { path = "./crates/oauth2-types/", version = "=1.2.0" } +syn2mas = { path = "./crates/syn2mas", version = "=1.2.0" } # OpenAPI schema generation and validation [workspace.dependencies.aide] From 2df5594a69f0ddd950f7bf03099cf578274ac385 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 10:37:19 +0000 Subject: [PATCH 019/296] build(deps): bump camino from 1.1.11 to 1.1.12 Bumps [camino](https://github.com/camino-rs/camino) from 1.1.11 to 1.1.12. - [Release notes](https://github.com/camino-rs/camino/releases) - [Changelog](https://github.com/camino-rs/camino/blob/main/CHANGELOG.md) - [Commits](https://github.com/camino-rs/camino/compare/camino-1.1.11...camino-1.1.12) --- updated-dependencies: - dependency-name: camino dependency-version: 1.1.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b6d93227..4cda108ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -831,9 +831,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.11" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d07aa9a93b00c76f71bc35d598bed923f6d4f3a9ca5c24b7737ae1a292841c0" +checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" dependencies = [ "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 44dc8990f..ac51356cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ version = "1.10.1" # UTF-8 paths [workspace.dependencies.camino] -version = "1.1.11" +version = "1.1.12" features = ["serde1"] # ChaCha20Poly1305 AEAD From eb313b41b5fe3e76b6c8809e3465f4adfff9bf3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:14:24 +0000 Subject: [PATCH 020/296] build(deps-dev): bump the storybook group in /frontend with 3 updates Bumps the storybook group in /frontend with 3 updates: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite) and [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core). Updates `@storybook/addon-docs` from 9.1.3 to 9.1.4 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.4/code/addons/docs) Updates `@storybook/react-vite` from 9.1.3 to 9.1.4 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.4/code/frameworks/react-vite) Updates `storybook` from 9.1.3 to 9.1.4 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.4/code/core) --- updated-dependencies: - dependency-name: "@storybook/addon-docs" dependency-version: 9.1.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/react-vite" dependency-version: 9.1.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-version: 9.1.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 70 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cae710f08..4374ac526 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -37,8 +37,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.3", - "@storybook/react-vite": "^9.1.3", + "@storybook/addon-docs": "^9.1.5", + "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.85.5", "@tanstack/react-router-devtools": "^1.131.27", "@tanstack/router-plugin": "^1.131.27", @@ -4982,16 +4982,16 @@ "license": "Apache-2.0" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.3.tgz", - "integrity": "sha512-iCzuHRyUgir2+ExqPO4ouxm90zW+6dkNuB4lyyFwNU10slJhVT8yGPk8PVOT6LhXMIii+7Hqc4dB0tj+kLOW/A==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.5.tgz", + "integrity": "sha512-q1j5RRElxFSnHOh60eS3dS2TAyAHzcQeH/2B9UXo6MUHu7HmhNpw3qt2YibIw0zEogHCvZhLNx6TNzSy+7wRUw==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.3", + "@storybook/csf-plugin": "9.1.5", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.3", + "@storybook/react-dom-shim": "9.1.5", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -5001,17 +5001,17 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.3" + "storybook": "^9.1.5" } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.3.tgz", - "integrity": "sha512-bstS/GsVJ5zVkRKAJociocA2omxU4CaNAP58fxS280JiRYgcrRaydDd7vwk6iGJ3xWbzwV0wH8SP54LVNyRY6Q==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.5.tgz", + "integrity": "sha512-sgt/9+Yl/5O7Bj5hdbHfadN8e/e4CNiDZKDcbLOMpOjKKoqF8vm19I1QocWIAiKjTOhF+4E9v9LddjtAGnfqHQ==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.3", + "@storybook/csf-plugin": "9.1.5", "ts-dedent": "^2.0.0" }, "funding": { @@ -5019,14 +5019,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.3", + "storybook": "^9.1.5", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.3.tgz", - "integrity": "sha512-wqh+tTCX2WZqVDVjhk/a6upsyYj/Kc85Wf6ywPx4pcFYxQZxiKF/wtuM9yzEpZC6fZHNvlKkzXWvP4wJOnm+zg==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.5.tgz", + "integrity": "sha512-PmHuF+j11Z7BxAI2/4wQYn0gH1d67gNvycyR+EWgp4P/AWam9wFbuI/T1R45CRQTV2/VrfGdts/tFrvo5kXWig==", "dev": true, "license": "MIT", "dependencies": { @@ -5037,7 +5037,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.3" + "storybook": "^9.1.5" } }, "node_modules/@storybook/global": { @@ -5062,14 +5062,14 @@ } }, "node_modules/@storybook/react": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.3.tgz", - "integrity": "sha512-CgJMk4Y8EfoFxWiTB53QxnN+nQbAkw+NBaNjsaaeDNOE1R0ximP/fn5b2jcLvM+b5ojjJiJL1QCzFyoPWImHIQ==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.5.tgz", + "integrity": "sha512-fBVP7Go09gzpImtaMcZ2DipLEWdWeTmz7BrACr3Z8uCyKcoH8/d1Wv0JgIiBo1UKDh5ZgYx5pLafaPNqmVAepg==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "9.1.3" + "@storybook/react-dom-shim": "9.1.5" }, "engines": { "node": ">=20.0.0" @@ -5081,7 +5081,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.3", + "storybook": "^9.1.5", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -5091,9 +5091,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.3.tgz", - "integrity": "sha512-zIgFwZqV8cvE+lzJDcD13rItxoWyYNUWu7eJQAnHz5RnyHhpu6rFgQej7i6J3rPmy9xVe+Rq6XsXgDNs6pIekQ==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.5.tgz", + "integrity": "sha512-blSq9uzSYnfgEYPHYKgM5O14n8hbXNiXx2GiVJyDSg8QPNicbsBg+lCb1TC7/USfV26pNZr/lGNNKGkcCEN6Gw==", "dev": true, "license": "MIT", "funding": { @@ -5103,20 +5103,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.3" + "storybook": "^9.1.5" } }, "node_modules/@storybook/react-vite": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.3.tgz", - "integrity": "sha512-iNRRxA5G9Yaw5etbRdCMnJtjI1VkzA7juc+/caVhKKut25sI8cOF4GRPLCbotLz9xmitQR2X7beZMPPVIYk86A==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.5.tgz", + "integrity": "sha512-OYbkHHNCrn8MNPd+4KxMjcSR4M/YHa84h8sWDUHhKRTRtZFmj8i/QDW3E8tGx2BRLxXw3dTYe9J5UYBhJDDxFA==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "9.1.3", - "@storybook/react": "9.1.3", + "@storybook/builder-vite": "9.1.5", + "@storybook/react": "9.1.5", "find-up": "^7.0.0", "magic-string": "^0.30.0", "react-docgen": "^8.0.0", @@ -5133,7 +5133,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.3", + "storybook": "^9.1.5", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -11987,9 +11987,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.3.tgz", - "integrity": "sha512-Sm+qP3iGb/QKx/jTYdfE0mIeTmA2HF+5k9fD70S9oOJq3F9UdW8MLgs+5PE+E/xAfDjZU4OWAKEOyA6EYIvQHg==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.5.tgz", + "integrity": "sha512-cGwJ2AE6nxlwqQlOiI+HKX5qa7+FOV7Ha7Qa+GoASBIQSSnLfbY6UldgAxHCJGJOFtgW/wuqfDtNvni6sj1/OQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 6a5d40c66..beb5140c8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -47,8 +47,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.3", - "@storybook/react-vite": "^9.1.3", + "@storybook/addon-docs": "^9.1.5", + "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.85.5", "@tanstack/react-router-devtools": "^1.131.27", "@tanstack/router-plugin": "^1.131.27", From debca9b5cd58406e933a68c3072b9df797f47f8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 02:14:35 +0000 Subject: [PATCH 021/296] build(deps-dev): bump vite Bumps the npm_and_yarn group with 1 update in the /frontend directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.3.5 to 6.3.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v6.3.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v6.3.6/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 6.3.6 dependency-type: direct:development dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cae710f08..9c76b58c0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -67,7 +67,7 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "6.3.5", + "vite": "6.3.6", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.6.1", "vite-plugin-manifest-sri": "^0.2.0", @@ -13222,9 +13222,9 @@ } }, "node_modules/vite": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", - "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz", + "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 6a5d40c66..37756a76a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -77,7 +77,7 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "6.3.5", + "vite": "6.3.6", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.6.1", "vite-plugin-manifest-sri": "^0.2.0", From 32131e90efcdbc5725413fc934847b786d1eb6f8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 13:16:04 +0000 Subject: [PATCH 022/296] build(deps-dev): bump @biomejs/biome from 2.1.2 to 2.2.4 in /frontend Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.1.2 to 2.2.4. - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.2.4/packages/@biomejs/biome) --- updated-dependencies: - dependency-name: "@biomejs/biome" dependency-version: 2.2.4 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 72 +++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cae710f08..d420fac87 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -29,7 +29,7 @@ "vaul": "^1.1.2" }, "devDependencies": { - "@biomejs/biome": "^2.1.2", + "@biomejs/biome": "^2.2.4", "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", @@ -1114,9 +1114,9 @@ } }, "node_modules/@biomejs/biome": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.1.2.tgz", - "integrity": "sha512-yq8ZZuKuBVDgAS76LWCfFKHSYIAgqkxVB3mGVVpOe2vSkUTs7xG46zXZeNPRNVjiJuw0SZ3+J2rXiYx0RUpfGg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.4.tgz", + "integrity": "sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -1130,20 +1130,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.1.2", - "@biomejs/cli-darwin-x64": "2.1.2", - "@biomejs/cli-linux-arm64": "2.1.2", - "@biomejs/cli-linux-arm64-musl": "2.1.2", - "@biomejs/cli-linux-x64": "2.1.2", - "@biomejs/cli-linux-x64-musl": "2.1.2", - "@biomejs/cli-win32-arm64": "2.1.2", - "@biomejs/cli-win32-x64": "2.1.2" + "@biomejs/cli-darwin-arm64": "2.2.4", + "@biomejs/cli-darwin-x64": "2.2.4", + "@biomejs/cli-linux-arm64": "2.2.4", + "@biomejs/cli-linux-arm64-musl": "2.2.4", + "@biomejs/cli-linux-x64": "2.2.4", + "@biomejs/cli-linux-x64-musl": "2.2.4", + "@biomejs/cli-win32-arm64": "2.2.4", + "@biomejs/cli-win32-x64": "2.2.4" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.1.2.tgz", - "integrity": "sha512-leFAks64PEIjc7MY/cLjE8u5OcfBKkcDB0szxsWUB4aDfemBep1WVKt0qrEyqZBOW8LPHzrFMyDl3FhuuA0E7g==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.4.tgz", + "integrity": "sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==", "cpu": [ "arm64" ], @@ -1158,9 +1158,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.1.2.tgz", - "integrity": "sha512-Nmmv7wRX5Nj7lGmz0FjnWdflJg4zii8Ivruas6PBKzw5SJX/q+Zh2RfnO+bBnuKLXpj8kiI2x2X12otpH6a32A==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.4.tgz", + "integrity": "sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==", "cpu": [ "x64" ], @@ -1175,9 +1175,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.1.2.tgz", - "integrity": "sha512-NWNy2Diocav61HZiv2enTQykbPP/KrA/baS7JsLSojC7Xxh2nl9IczuvE5UID7+ksRy2e7yH7klm/WkA72G1dw==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.4.tgz", + "integrity": "sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==", "cpu": [ "arm64" ], @@ -1192,9 +1192,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.1.2.tgz", - "integrity": "sha512-qgHvafhjH7Oca114FdOScmIKf1DlXT1LqbOrrbR30kQDLFPEOpBG0uzx6MhmsrmhGiCFCr2obDamu+czk+X0HQ==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.4.tgz", + "integrity": "sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==", "cpu": [ "arm64" ], @@ -1209,9 +1209,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.1.2.tgz", - "integrity": "sha512-Km/UYeVowygTjpX6sGBzlizjakLoMQkxWbruVZSNE6osuSI63i4uCeIL+6q2AJlD3dxoiBJX70dn1enjQnQqwA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.4.tgz", + "integrity": "sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==", "cpu": [ "x64" ], @@ -1226,9 +1226,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.1.2.tgz", - "integrity": "sha512-xlB3mU14ZUa3wzLtXfmk2IMOGL+S0aHFhSix/nssWS/2XlD27q+S6f0dlQ8WOCbYoXcuz8BCM7rCn2lxdTrlQA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.4.tgz", + "integrity": "sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==", "cpu": [ "x64" ], @@ -1243,9 +1243,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.1.2.tgz", - "integrity": "sha512-G8KWZli5ASOXA3yUQgx+M4pZRv3ND16h77UsdunUL17uYpcL/UC7RkWTdkfvMQvogVsAuz5JUcBDjgZHXxlKoA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.4.tgz", + "integrity": "sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==", "cpu": [ "arm64" ], @@ -1260,9 +1260,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.1.2.tgz", - "integrity": "sha512-9zajnk59PMpjBkty3bK2IrjUsUHvqe9HWwyAWQBjGLE7MIBjbX2vwv1XPEhmO2RRuGoTkVx3WCanHrjAytICLA==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.4.tgz", + "integrity": "sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==", "cpu": [ "x64" ], diff --git a/frontend/package.json b/frontend/package.json index 6a5d40c66..12b38c51a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,7 +39,7 @@ "vaul": "^1.1.2" }, "devDependencies": { - "@biomejs/biome": "^2.1.2", + "@biomejs/biome": "^2.2.4", "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", From 55342d284cfb66da39da5b1d1d38a444699b3d70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 07:38:47 +0000 Subject: [PATCH 023/296] build(deps): bump the i18next group across 1 directory with 2 updates Bumps the i18next group with 2 updates in the /frontend directory: [i18next](https://github.com/i18next/i18next) and [react-i18next](https://github.com/i18next/react-i18next). Updates `i18next` from 25.4.2 to 25.5.0 - [Release notes](https://github.com/i18next/i18next/releases) - [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next/compare/v25.4.2...v25.5.0) Updates `react-i18next` from 15.7.2 to 15.7.3 - [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/react-i18next/compare/v15.7.2...v15.7.3) --- updated-dependencies: - dependency-name: i18next dependency-version: 25.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: i18next - dependency-name: react-i18next dependency-version: 15.7.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: i18next ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9c76b58c0..70c61490f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,10 +20,10 @@ "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", "date-fns": "^4.1.0", - "i18next": "^25.4.2", + "i18next": "^25.5.2", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-i18next": "^15.7.2", + "react-i18next": "^15.7.3", "swagger-ui-dist": "^5.27.1", "valibot": "^1.1.0", "vaul": "^1.1.2" @@ -8697,9 +8697,9 @@ } }, "node_modules/i18next": { - "version": "25.4.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.4.2.tgz", - "integrity": "sha512-gD4T25a6ovNXsfXY1TwHXXXLnD/K2t99jyYMCSimSCBnBRJVQr5j+VAaU83RJCPzrTGhVQ6dqIga66xO2rtd5g==", + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.2.tgz", + "integrity": "sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw==", "funding": [ { "type": "individual", @@ -11086,9 +11086,9 @@ } }, "node_modules/react-i18next": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.7.2.tgz", - "integrity": "sha512-xJxq7ibnhUlMvd82lNC4te1GxGUMoM1A05KKyqoqsBXVZtEvZg/fz/fnVzdlY/hhQ3SpP/79qCocZOtICGhd3g==", + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.7.3.tgz", + "integrity": "sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.6", diff --git a/frontend/package.json b/frontend/package.json index 37756a76a..c7e268a0c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,10 +30,10 @@ "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", "date-fns": "^4.1.0", - "i18next": "^25.4.2", + "i18next": "^25.5.2", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-i18next": "^15.7.2", + "react-i18next": "^15.7.3", "swagger-ui-dist": "^5.27.1", "valibot": "^1.1.0", "vaul": "^1.1.2" From 6824fcb9e3adb1105a9bbeadc5d8c36a7ff2cf90 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 09:46:52 +0200 Subject: [PATCH 024/296] Ignore a few linting errors --- biome.json | 8 +++++++- frontend/src/components/Separator/Separator.tsx | 1 + frontend/src/routes/_account.sessions.index.tsx | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/biome.json b/biome.json index 9dc190833..cc5454160 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json", + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", "assist": { "actions": { "source": { "organizeImports": "on" } } }, "vcs": { "enabled": true, @@ -32,6 +32,12 @@ "enabled": true, "rules": { "recommended": true, + "complexity": { + "noImportantStyles": "off" + }, + "suspicious": { + "noUnknownAtRules": "off" + }, "correctness": { "noUnusedImports": "warn", "noUnusedVariables": "warn" diff --git a/frontend/src/components/Separator/Separator.tsx b/frontend/src/components/Separator/Separator.tsx index 886c63040..a0472231e 100644 --- a/frontend/src/components/Separator/Separator.tsx +++ b/frontend/src/components/Separator/Separator.tsx @@ -5,6 +5,7 @@ // biome-ignore-all lint/a11y/useFocusableInteractive: this is a false positive // biome-ignore-all lint/a11y/useAriaPropsForRole: this is a false positive +// biome-ignore-all lint/a11y/useSemanticElements: I don't want to use an
import cx from "classnames"; import { forwardRef } from "react"; diff --git a/frontend/src/routes/_account.sessions.index.tsx b/frontend/src/routes/_account.sessions.index.tsx index e7f930a57..5e9085d75 100644 --- a/frontend/src/routes/_account.sessions.index.tsx +++ b/frontend/src/routes/_account.sessions.index.tsx @@ -179,7 +179,7 @@ function Sessions(): React.ReactElement { ); default: - unknownSessionType(type); + return unknownSessionType(type); } })} From 8a76c6c30fb5d2ff700c11ff077747e829ccfdd4 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:06:49 +0200 Subject: [PATCH 025/296] Remove the codecov vite plugin --- frontend/package-lock.json | 317 ------------------------------------- frontend/package.json | 1 - frontend/vite.config.ts | 8 - 3 files changed, 326 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 68e2908a5..c61a15c1d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -33,7 +33,6 @@ "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", - "@codecov/vite-plugin": "^1.9.1", "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", @@ -74,61 +73,6 @@ "vitest": "^3.2.3" } }, - "node_modules/@actions/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz", - "integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/exec": "^1.1.1", - "@actions/http-client": "^2.0.1" - } - }, - "node_modules/@actions/exec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/io": "^1.0.1" - } - }, - "node_modules/@actions/github": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.1.tgz", - "integrity": "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/http-client": "^2.2.0", - "@octokit/core": "^5.0.1", - "@octokit/plugin-paginate-rest": "^9.2.2", - "@octokit/plugin-rest-endpoint-methods": "^10.4.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "undici": "^5.28.5" - } - }, - "node_modules/@actions/http-client": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz", - "integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tunnel": "^0.0.6", - "undici": "^5.25.4" - } - }, - "node_modules/@actions/io": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz", - "integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@adobe/css-tools": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", @@ -1314,41 +1258,6 @@ "statuses": "^2.0.1" } }, - "node_modules/@codecov/bundler-plugin-core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@codecov/bundler-plugin-core/-/bundler-plugin-core-1.9.1.tgz", - "integrity": "sha512-dt3ic7gMswz4p/qdkYPVJwXlLiLsz55rBBn2I7mr0HTG8pCoLRqnANJIwo5WrqGBZgPyVSMPBqBra6VxLWfDyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@actions/core": "^1.10.1", - "@actions/github": "^6.0.0", - "chalk": "4.1.2", - "semver": "^7.5.4", - "unplugin": "^1.10.1", - "zod": "^3.22.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@codecov/vite-plugin": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@codecov/vite-plugin/-/vite-plugin-1.9.1.tgz", - "integrity": "sha512-S6Yne7comVulJ1jD3T7rCfYFHPR0zUjAYoLjUDPXNJCUrdzWJdf/ak/UepE7TicqQG+yBa6eb5WusqcPgg+1AQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@codecov/bundler-plugin-core": "^1.9.1", - "unplugin": "^1.10.1" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "vite": "4.x || 5.x || 6.x" - } - }, "node_modules/@csstools/selector-resolve-nested": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", @@ -3539,178 +3448,6 @@ "node": ">= 8" } }, - "node_modules/@octokit/auth-token": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", - "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.1.tgz", - "integrity": "sha512-dKYCMuPO1bmrpuogcjQ8z7ICCH3FP6WmxpwC03yjzGfZhj9fTJg6+bS1+UAplekbN2C+M61UNllGOOoAfGCrdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^4.0.0", - "@octokit/graphql": "^7.1.0", - "@octokit/request": "^8.4.1", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.0.0", - "before-after-hook": "^2.2.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz", - "integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request": "^8.4.1", - "@octokit/types": "^13.0.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", - "integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^12.6.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", - "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^12.6.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "5" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", - "integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz", - "integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^20.0.0" - } - }, - "node_modules/@octokit/request": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", - "integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^9.0.6", - "@octokit/request-error": "^5.1.1", - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", - "integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.1.0", - "deprecation": "^2.0.0", - "once": "^1.4.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, "node_modules/@open-draft/deferred-promise": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", @@ -6435,13 +6172,6 @@ ], "license": "MIT" }, - "node_modules/before-after-hook": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", - "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/better-opn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", @@ -7474,13 +7204,6 @@ "node": ">= 0.6.0" } }, - "node_modules/deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", - "dev": true, - "license": "ISC" - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -12768,16 +12491,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", @@ -12856,19 +12569,6 @@ "node": "*" } }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -12876,16 +12576,6 @@ "dev": true, "license": "MIT" }, - "node_modules/undici/node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", @@ -12899,13 +12589,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", - "dev": true, - "license": "ISC" - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 4c9346a0a..20a73e137 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -43,7 +43,6 @@ "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", - "@codecov/vite-plugin": "^1.9.1", "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index fdc00cab7..11cfac300 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -7,7 +7,6 @@ import { readFile, writeFile } from "node:fs/promises"; import { resolve } from "node:path"; -import { codecovVitePlugin } from "@codecov/vite-plugin"; import { tanstackRouter } from "@tanstack/router-plugin/vite"; import react from "@vitejs/plugin-react"; import browserslistToEsbuild from "browserslist-to-esbuild"; @@ -74,13 +73,6 @@ export default defineConfig((env) => ({ react(), - codecovVitePlugin({ - enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined, - bundleName: "mas-frontend", - uploadToken: process.env.CODECOV_TOKEN, - gitService: "github", - }), - // Custom plugin to make sure that each asset has an entry in the manifest // This is needed so that the preloading & asset integrity generation works { From be3b0231da56745b22fadd67da381c24b3f78b3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 08:33:55 +0000 Subject: [PATCH 026/296] build(deps-dev): bump the vite group across 1 directory with 3 updates Bumps the vite group with 3 updates in the /frontend directory: [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [vite-plugin-graphql-codegen](https://github.com/danielwaltz/vite-plugin-graphql-codegen). Updates `@vitejs/plugin-react` from 4.5.2 to 4.6.0 - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@4.6.0/packages/plugin-react) Updates `vite` from 6.3.5 to 7.0.0 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/create-vite@7.0.0/packages/vite) Updates `vite-plugin-graphql-codegen` from 3.6.1 to 3.6.2 - [Release notes](https://github.com/danielwaltz/vite-plugin-graphql-codegen/releases) - [Changelog](https://github.com/danielwaltz/vite-plugin-graphql-codegen/blob/main/CHANGELOG.md) - [Commits](https://github.com/danielwaltz/vite-plugin-graphql-codegen/compare/v3.6.1...v3.6.2) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 4.6.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: vite - dependency-name: vite dependency-version: 7.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: vite - dependency-name: vite-plugin-graphql-codegen dependency-version: 3.6.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 177 ++++++++++++++++++++----------------- frontend/package.json | 6 +- 2 files changed, 101 insertions(+), 82 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1704b4575..aeee78fe3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -48,7 +48,7 @@ "@types/react": "19.1.10", "@types/react-dom": "19.1.7", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^4.5.2", + "@vitejs/plugin-react": "^5.0.2", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -66,9 +66,9 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "6.3.6", + "vite": "7.1.5", "vite-plugin-compression": "^0.5.1", - "vite-plugin-graphql-codegen": "^3.6.1", + "vite-plugin-graphql-codegen": "^3.6.3", "vite-plugin-manifest-sri": "^0.2.0", "vitest": "^3.2.3" } @@ -158,21 +158,22 @@ } }, "node_modules/@babel/core": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", - "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, + "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.6", - "@babel/parser": "^7.28.0", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -198,13 +199,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -323,15 +325,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -426,26 +428,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -1017,17 +1020,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", + "@babel/types": "^7.28.4", "debug": "^4.3.1" }, "engines": { @@ -1035,10 +1039,11 @@ } }, "node_modules/@babel/types": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.0.tgz", - "integrity": "sha512-jYnje+JyZG5YThjHiF28oT4SIZLnYOcSBb6+SDaFIyzDVSkXQmQQYclJ2R+YxcdmK0AX6x1E5OQNtuh3jHDrUg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" @@ -3334,6 +3339,17 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -4402,9 +4418,9 @@ "license": "MIT" }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz", - "integrity": "sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==", + "version": "1.0.0-beta.34", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz", + "integrity": "sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==", "dev": true, "license": "MIT" }, @@ -5534,24 +5550,24 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.5.2.tgz", - "integrity": "sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz", + "integrity": "sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", + "@babel/core": "^7.28.3", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.11", + "@rolldown/pluginutils": "1.0.0-beta.34", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@vitest/coverage-v8": { @@ -7662,11 +7678,14 @@ } }, "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -10366,9 +10385,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -12305,14 +12324,14 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", - "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.4", - "picomatch": "^4.0.2" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { "node": ">=12.0.0" @@ -12905,24 +12924,24 @@ } }, "node_modules/vite": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz", - "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==", + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", + "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -12931,14 +12950,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -13033,15 +13052,15 @@ } }, "node_modules/vite-plugin-graphql-codegen": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/vite-plugin-graphql-codegen/-/vite-plugin-graphql-codegen-3.6.1.tgz", - "integrity": "sha512-6uTRv8jD1pp9kt6StjOL6BGj166qVXmRwe06m9I1qtxjIVf+i7aF95gFv0NKxhEXXaDr1hFVlpp+3Ts+SQAy4g==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/vite-plugin-graphql-codegen/-/vite-plugin-graphql-codegen-3.6.3.tgz", + "integrity": "sha512-A6C5fEGg26jG4bUhxTRH3KegFXNJ4Vxy4x/F/UKTfl73wOeb64qA3/rJFybyambvjNFndyameNazyeUglfH4Qg==", "dev": true, "license": "MIT", "peerDependencies": { "@graphql-codegen/cli": ">=1.0.0 <6.0.0", "graphql": ">=14.0.0 <17.0.0", - "vite": ">=2.7.0 <7.0.0" + "vite": ">=2.7.0 <8.0.0" } }, "node_modules/vite-plugin-manifest-sri": { diff --git a/frontend/package.json b/frontend/package.json index 8fb16ca91..48708f7d4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -58,7 +58,7 @@ "@types/react": "19.1.10", "@types/react-dom": "19.1.7", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^4.5.2", + "@vitejs/plugin-react": "^5.0.2", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -76,9 +76,9 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "6.3.6", + "vite": "7.1.5", "vite-plugin-compression": "^0.5.1", - "vite-plugin-graphql-codegen": "^3.6.1", + "vite-plugin-graphql-codegen": "^3.6.3", "vite-plugin-manifest-sri": "^0.2.0", "vitest": "^3.2.3" }, From 5667ae677d33a67b4764fa3d436e392fce346495 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:37:41 +0200 Subject: [PATCH 027/296] Enforce npm strict engine --- Dockerfile | 2 +- frontend/.npmrc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 frontend/.npmrc diff --git a/Dockerfile b/Dockerfile index 14eda1924..b54509e8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,7 @@ FROM --platform=${BUILDPLATFORM} docker.io/library/node:${NODEJS_VERSION}-${DEBI WORKDIR /app/frontend -COPY ./frontend/package.json ./frontend/package-lock.json /app/frontend/ +COPY ./frontend/.npmrc ./frontend/package.json ./frontend/package-lock.json /app/frontend/ # Network access: to fetch dependencies RUN --network=default \ npm ci diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 000000000..b6f27f135 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +engine-strict=true From 7118a09ec641d3920c634c69354ed51330757ae1 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:45:12 +0200 Subject: [PATCH 028/296] Upgrade Node in the Dockerfile to 22.19.0 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b54509e8e..e8b991937 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ ARG DEBIAN_VERSION=12 ARG DEBIAN_VERSION_NAME=bookworm ARG RUSTC_VERSION=1.89.0 -ARG NODEJS_VERSION=20.15.0 +ARG NODEJS_VERSION=22.19.0 ARG OPA_VERSION=1.1.0 ARG CARGO_AUDITABLE_VERSION=0.6.6 From 893d51d0bc0977281fabf862b6ce174abf7f30d1 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:45:39 +0200 Subject: [PATCH 029/296] Upgrade cargo-auditable to 0.7.0 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e8b991937..ed4f54ae7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ ARG DEBIAN_VERSION_NAME=bookworm ARG RUSTC_VERSION=1.89.0 ARG NODEJS_VERSION=22.19.0 ARG OPA_VERSION=1.1.0 -ARG CARGO_AUDITABLE_VERSION=0.6.6 +ARG CARGO_AUDITABLE_VERSION=0.7.0 ########################################## ## Build stage that builds the frontend ## From e74061730ea572dd7b65fed88a5e2f97a67da532 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:52:39 +0200 Subject: [PATCH 030/296] Upgrade OPA and regal to latest versions --- .github/actions/build-policies/action.yml | 3 ++- .github/workflows/ci.yaml | 3 ++- Dockerfile | 3 ++- policies/.regal/config.yaml | 3 +++ policies/Makefile | 6 ++++-- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/actions/build-policies/action.yml b/.github/actions/build-policies/action.yml index 0eba08e6e..e1dc28547 100644 --- a/.github/actions/build-policies/action.yml +++ b/.github/actions/build-policies/action.yml @@ -12,7 +12,8 @@ runs: - name: Install Open Policy Agent uses: open-policy-agent/setup-opa@v2.2.0 with: - version: 1.1.0 + # Keep in sync with the Dockerfile and policies/Makefile + version: 1.8.0 - name: Build the policies run: make diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 93c3b1b5f..080fae3df 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,8 @@ jobs: - name: Setup Regal uses: StyraInc/setup-regal@v1 with: - version: 0.29.2 + # Keep in sync with policies/Makefile + version: 0.36.1 - name: Lint policies working-directory: ./policies diff --git a/Dockerfile b/Dockerfile index ed4f54ae7..0a6ff4322 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,8 @@ ARG DEBIAN_VERSION=12 ARG DEBIAN_VERSION_NAME=bookworm ARG RUSTC_VERSION=1.89.0 ARG NODEJS_VERSION=22.19.0 -ARG OPA_VERSION=1.1.0 +# Keep in sync with .github/actions/build-policies/action.yml and policies/Makefile +ARG OPA_VERSION=1.8.0 ARG CARGO_AUDITABLE_VERSION=0.7.0 ########################################## diff --git a/policies/.regal/config.yaml b/policies/.regal/config.yaml index 0620e6872..2c99d0efa 100644 --- a/policies/.regal/config.yaml +++ b/policies/.regal/config.yaml @@ -4,6 +4,9 @@ # Please see LICENSE files in the repository root for full details. rules: + imports: + unresolved-reference: + level: ignore style: external-reference: level: ignore diff --git a/policies/Makefile b/policies/Makefile index 0e4d8ebdd..2d4b7f2cb 100644 --- a/policies/Makefile +++ b/policies/Makefile @@ -6,8 +6,10 @@ # Set to 1 to run OPA through Docker DOCKER := 0 PODMAN := 0 -OPA_DOCKER_IMAGE := docker.io/openpolicyagent/opa:1.1.0-debug -REGAL_DOCKER_IMAGE := ghcr.io/styrainc/regal:0.31.0 +# Keep in sync with Dockerfile and .github/actions/build-policies/action.yml +OPA_DOCKER_IMAGE := docker.io/openpolicyagent/opa:1.8.0-debug +# Keep in sync with .github/workflows/ci.yaml +REGAL_DOCKER_IMAGE := ghcr.io/styrainc/regal:0.36.1 INPUTS := \ common/common.rego \ From 9a932e1b601649c73301f0659e60da0bb15fad00 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 10:58:55 +0200 Subject: [PATCH 031/296] Fix reference to the regal image --- policies/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policies/Makefile b/policies/Makefile index 2d4b7f2cb..421990d07 100644 --- a/policies/Makefile +++ b/policies/Makefile @@ -9,7 +9,7 @@ PODMAN := 0 # Keep in sync with Dockerfile and .github/actions/build-policies/action.yml OPA_DOCKER_IMAGE := docker.io/openpolicyagent/opa:1.8.0-debug # Keep in sync with .github/workflows/ci.yaml -REGAL_DOCKER_IMAGE := ghcr.io/styrainc/regal:0.36.1 +REGAL_DOCKER_IMAGE := ghcr.io/open-policy-agent/regal:0.36.1 INPUTS := \ common/common.rego \ From 0d04db7c492ae0832ad03fa935daadc98d58569a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 11:06:26 +0200 Subject: [PATCH 032/296] Update the vite manifest definition --- crates/spa/src/vite.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/crates/spa/src/vite.rs b/crates/spa/src/vite.rs index e2706d512..b488bea6b 100644 --- a/crates/spa/src/vite.rs +++ b/crates/spa/src/vite.rs @@ -12,10 +12,13 @@ use thiserror::Error; #[derive(serde::Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ManifestEntry { - #[allow(dead_code)] + #[expect(dead_code)] name: Option, - #[allow(dead_code)] + #[expect(dead_code)] + names: Option>, + + #[expect(dead_code)] src: Option, file: Utf8PathBuf, @@ -24,15 +27,15 @@ pub struct ManifestEntry { assets: Option>, - #[allow(dead_code)] + #[expect(dead_code)] is_entry: Option, - #[allow(dead_code)] + #[expect(dead_code)] is_dynamic_entry: Option, imports: Option>, - #[allow(dead_code)] + #[expect(dead_code)] dynamic_imports: Option>, integrity: Option, From 2db3cdb389c120e0890b3d661acfb66a9657696a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:15:38 +0000 Subject: [PATCH 033/296] build(deps): bump @fontsource/inconsolata Bumps the fontsource group in /frontend with 1 update: [@fontsource/inconsolata](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/inconsolata). Updates `@fontsource/inconsolata` from 5.2.6 to 5.2.7 - [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md) - [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/inconsolata) --- updated-dependencies: - dependency-name: "@fontsource/inconsolata" dependency-version: 5.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fontsource ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1704b4575..7c4635d7b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,7 @@ "name": "mas-frontend", "version": "0.0.0", "dependencies": { - "@fontsource/inconsolata": "^5.2.6", + "@fontsource/inconsolata": "^5.2.7", "@fontsource/inter": "^5.2.6", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", @@ -1868,9 +1868,9 @@ "license": "MIT" }, "node_modules/@fontsource/inconsolata": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.6.tgz", - "integrity": "sha512-TRGh7bN+BN/oP8qD1IYe8REXM/0Uw3jbuERSncA/ZF6mqKFEOeTt6PR2T3xK7G+65N9pn2p0ablamdboee2nFQ==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.7.tgz", + "integrity": "sha512-qmARxA7lS16PCoB404sehiXzh8mzcZzFio6n05/zpxIC97W+AxdJqgWQ0kfMzdj78ILy2PaaXZ1Js4kfxL1JMw==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" diff --git a/frontend/package.json b/frontend/package.json index 8fb16ca91..b40aa831a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,7 @@ "knip": "knip" }, "dependencies": { - "@fontsource/inconsolata": "^5.2.6", + "@fontsource/inconsolata": "^5.2.7", "@fontsource/inter": "^5.2.6", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", From a2c963a4cd945acc8bbb6f4829cfc41e5951d5cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:16:50 +0000 Subject: [PATCH 034/296] build(deps): bump the tanstack-router group in /frontend with 3 updates Bumps the tanstack-router group in /frontend with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/react-router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/react-router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin). Updates `@tanstack/react-router` from 1.131.27 to 1.131.41 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.41/packages/react-router) Updates `@tanstack/react-router-devtools` from 1.131.27 to 1.131.42 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.42/packages/react-router-devtools) Updates `@tanstack/router-plugin` from 1.131.27 to 1.131.41 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.41/packages/router-plugin) --- updated-dependencies: - dependency-name: "@tanstack/react-router" dependency-version: 1.131.41 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: tanstack-router - dependency-name: "@tanstack/react-router-devtools" dependency-version: 1.131.42 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: tanstack-router - dependency-name: "@tanstack/router-plugin" dependency-version: 1.131.41 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: tanstack-router ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 58 +++++++++++++++++++------------------- frontend/package.json | 6 ++-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1704b4575..7eb73dc51 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,7 +13,7 @@ "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", "@tanstack/react-query": "^5.85.5", - "@tanstack/react-router": "^1.131.27", + "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "5.0.2", "@vector-im/compound-web": "^8.2.0", "@zxcvbn-ts/core": "^3.0.4", @@ -39,8 +39,8 @@ "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.85.5", - "@tanstack/react-router-devtools": "^1.131.27", - "@tanstack/router-plugin": "^1.131.27", + "@tanstack/react-router-devtools": "^1.131.42", + "@tanstack/router-plugin": "^1.131.41", "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", @@ -4943,14 +4943,14 @@ } }, "node_modules/@tanstack/react-router": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.27.tgz", - "integrity": "sha512-JLUsmlarNxMz7VDhFscZCqoc2quhocQZKhia/7YXWf8Jbc8rANk6lukK4ecYn92m/ytoHAAy77JeaB6n0HvqwQ==", + "version": "1.131.41", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.41.tgz", + "integrity": "sha512-QEbTYpAosiD8e4qEZRr9aJipGSb8pQc+pfZwK6NCD2Tcxwu2oF6MVtwv0bIDLRpZP0VJMBpxXlTRISUDNMNqIA==", "license": "MIT", "dependencies": { "@tanstack/history": "1.131.2", "@tanstack/react-store": "^0.7.0", - "@tanstack/router-core": "1.131.27", + "@tanstack/router-core": "1.131.41", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" @@ -4968,13 +4968,13 @@ } }, "node_modules/@tanstack/react-router-devtools": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.131.27.tgz", - "integrity": "sha512-SHulN0a7hZvyl3fXi+VLHxdMKdsg1lhPOZeKd5xs6bu/x+N5FaXEA5bUPGB2sbiSYXw/XFcjUqR5dkw8T1dkXg==", + "version": "1.131.42", + "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.131.42.tgz", + "integrity": "sha512-7pymFB1CCimRHot2Zp0ZekQjd1iN812V88n9NLPSeiv9sVRtRVIaLphJjDeudx1NNgkfSJPx2lOhz6K38cuZog==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/router-devtools-core": "1.131.27" + "@tanstack/router-devtools-core": "1.131.42" }, "engines": { "node": ">=12" @@ -4984,15 +4984,15 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-router": "^1.131.27", + "@tanstack/react-router": "^1.131.41", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "node_modules/@tanstack/react-router-devtools/node_modules/@tanstack/router-devtools-core": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.27.tgz", - "integrity": "sha512-upoMv/uq1CQdrOyBO2h6CLXI1Ym7Rawoovt26fN1Wl+RMXqKGVpHAXYuKpugdFMFhFieccKVYcrj9NP4V5BIDw==", + "version": "1.131.42", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.42.tgz", + "integrity": "sha512-o8jKTiwXcUSjmkozcMjIw1yhjVYeXcuQO7DtfgjKW3B85iveH6VzYK+bGEVU7wmLNMuUSe2eI/7RBzJ6a5+MCA==", "dev": true, "license": "MIT", "dependencies": { @@ -5008,7 +5008,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/router-core": "^1.131.27", + "@tanstack/router-core": "^1.131.41", "csstype": "^3.0.10", "solid-js": ">=1.9.5", "tiny-invariant": "^1.3.3" @@ -5038,9 +5038,9 @@ } }, "node_modules/@tanstack/router-core": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.27.tgz", - "integrity": "sha512-NEBNxZ/LIBIh6kvQntr6bKq57tDe55zecyTtjAmzPkYFsMy1LXEpRm5H3BPiteBMRApAjuaq+bS1qA664hLH6Q==", + "version": "1.131.41", + "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.41.tgz", + "integrity": "sha512-VoLly00DWM0abKuVPRm8wiwGtRBHOKs6K896fy48Q/KYoDVLs8kRCRjFGS7rGnYC2FIkmmvHqYRqNg7jgCx2yg==", "license": "MIT", "dependencies": { "@tanstack/history": "1.131.2", @@ -5060,13 +5060,13 @@ } }, "node_modules/@tanstack/router-generator": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.27.tgz", - "integrity": "sha512-PXBIVl45q2bBq9g0DDXLBGeKjO9eExcZd2JotLjLdIJ0I/wdxPQOBJHLPZfnmbf3vispToedRvG3b1YDWjL48g==", + "version": "1.131.41", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.41.tgz", + "integrity": "sha512-HsDkBU1u/KvHrzn76v/9oeyMFuxvVlE3dfIu4fldZbPy/i903DWBwODIDGe6fVUsYtzPPrRvNtbjV18HVz5GCA==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/router-core": "1.131.27", + "@tanstack/router-core": "1.131.41", "@tanstack/router-utils": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2", "prettier": "^3.5.0", @@ -5084,9 +5084,9 @@ } }, "node_modules/@tanstack/router-plugin": { - "version": "1.131.27", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.27.tgz", - "integrity": "sha512-0V611ehOE8nfCFT2tvrLfQMroyoYW/virDXPaaFe38hdDxslmfCW2miJxngxz4+QqgK/M3sX71ElrZDvkP2Ixw==", + "version": "1.131.41", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.41.tgz", + "integrity": "sha512-MENVYQwvhKFIPZ/YO/CGCwbh3Ba3TRvUYZ2y2KiU6aa1CWao4KHDRsungzv34AbbUBSmzbc8mKVeqd+G+E9cDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5096,8 +5096,8 @@ "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", - "@tanstack/router-core": "1.131.27", - "@tanstack/router-generator": "1.131.27", + "@tanstack/router-core": "1.131.41", + "@tanstack/router-generator": "1.131.41", "@tanstack/router-utils": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2", "babel-dead-code-elimination": "^1.0.10", @@ -5114,7 +5114,7 @@ }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", - "@tanstack/react-router": "^1.131.27", + "@tanstack/react-router": "^1.131.41", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" diff --git a/frontend/package.json b/frontend/package.json index 8fb16ca91..b2522b507 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,7 +23,7 @@ "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", "@tanstack/react-query": "^5.85.5", - "@tanstack/react-router": "^1.131.27", + "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "5.0.2", "@vector-im/compound-web": "^8.2.0", "@zxcvbn-ts/core": "^3.0.4", @@ -49,8 +49,8 @@ "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.85.5", - "@tanstack/react-router-devtools": "^1.131.27", - "@tanstack/router-plugin": "^1.131.27", + "@tanstack/react-router-devtools": "^1.131.42", + "@tanstack/router-plugin": "^1.131.41", "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", From 07905c42159e605f6de131aeac755e770059498f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:17:55 +0000 Subject: [PATCH 035/296] build(deps): bump psl from 2.1.140 to 2.1.141 Bumps [psl](https://github.com/addr-rs/psl) from 2.1.140 to 2.1.141. - [Release notes](https://github.com/addr-rs/psl/releases) - [Commits](https://github.com/addr-rs/psl/compare/v2.1.140...v2.1.141) --- updated-dependencies: - dependency-name: psl dependency-version: 2.1.141 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4174b87c3..7399950af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4727,9 +4727,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.140" +version = "2.1.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a33878b44e45231ecbc8c619cc8059e4adab882b25812192676fe08dcf352f" +checksum = "98c10a4dce9ad24c1fad826cffc79a624cf626bfaddb466e969368a53d877b30" dependencies = [ "psl-types", ] diff --git a/Cargo.toml b/Cargo.toml index 6ef0e9645..c8b1fa61e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -478,7 +478,7 @@ features = ["std", "pkcs5", "encryption"] # Public Suffix List [workspace.dependencies.psl] -version = "2.1.140" +version = "2.1.141" # Prometheus metrics [workspace.dependencies.prometheus] From da8addfb9ae7260c6afea74cdf6127813426f005 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:18:22 +0000 Subject: [PATCH 036/296] build(deps): bump indexmap from 2.11.0 to 2.11.1 Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.11.0 to 2.11.1. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.11.0...2.11.1) --- updated-dependencies: - dependency-name: indexmap dependency-version: 2.11.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4174b87c3..b792e506d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ dependencies = [ "bytes", "cfg-if", "http", - "indexmap 2.11.0", + "indexmap 2.11.1", "schemars 0.8.22", "serde", "serde_json", @@ -316,7 +316,7 @@ dependencies = [ "futures-timer", "futures-util", "http", - "indexmap 2.11.0", + "indexmap 2.11.1", "mime", "multer", "num-traits", @@ -368,7 +368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ecdaff7c9cffa3614a9f9999bf9ee4c3078fe3ce4d6a6e161736b56febf2de" dependencies = [ "bytes", - "indexmap 2.11.0", + "indexmap 2.11.1", "serde", "serde_json", ] @@ -2059,7 +2059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", - "indexmap 2.11.0", + "indexmap 2.11.1", "stable_deref_trait", ] @@ -2125,7 +2125,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.0", + "indexmap 2.11.1", "slab", "tokio", "tokio-util", @@ -2733,9 +2733,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" dependencies = [ "equivalent", "hashbrown 0.15.4", @@ -3329,7 +3329,7 @@ dependencies = [ "hex", "hyper", "icu_normalizer", - "indexmap 2.11.0", + "indexmap 2.11.1", "insta", "lettre", "mas-axum-utils", @@ -4037,7 +4037,7 @@ dependencies = [ "assert_matches", "base64ct", "chrono", - "indexmap 2.11.0", + "indexmap 2.11.1", "insta", "language-tags", "mas-iana", @@ -4058,7 +4058,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.4", - "indexmap 2.11.0", + "indexmap 2.11.1", "memchr", ] @@ -4541,7 +4541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64", - "indexmap 2.11.0", + "indexmap 2.11.1", "quick-xml", "serde", "time", @@ -5072,7 +5072,7 @@ dependencies = [ "base64", "bytes", "form_urlencoded", - "indexmap 2.11.0", + "indexmap 2.11.1", "js_int", "percent-encoding", "regex", @@ -5310,7 +5310,7 @@ dependencies = [ "chrono", "dyn-clone", "indexmap 1.9.3", - "indexmap 2.11.0", + "indexmap 2.11.1", "schemars_derive", "serde", "serde_json", @@ -5614,7 +5614,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" dependencies = [ "form_urlencoded", - "indexmap 2.11.0", + "indexmap 2.11.1", "itoa", "ryu", "serde", @@ -5626,7 +5626,7 @@ version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.11.1", "itoa", "memchr", "ryu", @@ -5687,7 +5687,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.0", + "indexmap 2.11.1", "schemars 0.9.0", "schemars 1.0.4", "serde", @@ -5715,7 +5715,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.11.1", "itoa", "ryu", "serde", @@ -5890,7 +5890,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.4", "hashlink", - "indexmap 2.11.0", + "indexmap 2.11.1", "ipnetwork", "log", "memchr", @@ -6465,7 +6465,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.11.1", "serde", "serde_spanned", "toml_datetime", @@ -7033,7 +7033,7 @@ checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", "hashbrown 0.15.4", - "indexmap 2.11.0", + "indexmap 2.11.1", "semver", "serde", ] @@ -7063,7 +7063,7 @@ dependencies = [ "cc", "cfg-if", "hashbrown 0.15.4", - "indexmap 2.11.0", + "indexmap 2.11.1", "libc", "log", "mach2", @@ -7103,7 +7103,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.0", + "indexmap 2.11.1", "log", "object", "postcard", @@ -7248,7 +7248,7 @@ checksum = "1ae057d44a5b60e6ec529b0c21809a9d1fc92e91ef6e0f6771ed11dd02a94a08" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.0", + "indexmap 2.11.1", "wit-parser", ] @@ -7763,7 +7763,7 @@ checksum = "0a1f95a87d03a33e259af286b857a95911eb46236a0f726cbaec1227b3dfc67a" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.0", + "indexmap 2.11.1", "log", "semver", "serde", diff --git a/Cargo.toml b/Cargo.toml index 6ef0e9645..5dfea40ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -321,7 +321,7 @@ features = ["std"] # HashMap which preserves insertion order [workspace.dependencies.indexmap] -version = "2.11.0" +version = "2.11.1" features = ["serde"] # Indented string literals From 78d3ec4ac8cd6a5af003227ca19432842c59161e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:19:37 +0000 Subject: [PATCH 037/296] build(deps): bump pest from 2.8.1 to 2.8.2 Bumps [pest](https://github.com/pest-parser/pest) from 2.8.1 to 2.8.2. - [Release notes](https://github.com/pest-parser/pest/releases) - [Commits](https://github.com/pest-parser/pest/compare/v2.8.1...v2.8.2) --- updated-dependencies: - dependency-name: pest dependency-version: 2.8.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4174b87c3..6c1147d4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4387,9 +4387,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", "thiserror 2.0.16", diff --git a/Cargo.toml b/Cargo.toml index 6ef0e9645..ee01f8608 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -456,7 +456,7 @@ features = ["std"] # Parser generator [workspace.dependencies.pest] -version = "2.8.1" +version = "2.8.2" # Pest derive macros [workspace.dependencies.pest_derive] From b2e5a467a12da5ea070122f82a37337ffe73cc38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:20:12 +0000 Subject: [PATCH 038/296] build(deps): bump clap from 4.5.46 to 4.5.47 Bumps [clap](https://github.com/clap-rs/clap) from 4.5.46 to 4.5.47. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.46...clap_complete-v4.5.47) --- updated-dependencies: - dependency-name: clap dependency-version: 4.5.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4174b87c3..497bb4b06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -980,9 +980,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -990,9 +990,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -1002,9 +1002,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck 0.5.0", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 6ef0e9645..7c408db01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -167,7 +167,7 @@ features = ["serde", "clock"] # CLI argument parsing [workspace.dependencies.clap] -version = "4.5.46" +version = "4.5.47" features = ["derive"] # Object Identifiers (OIDs) as constants From 062098b5ce0900964f44497e595c8f6b6d2a0a3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:50:57 +0000 Subject: [PATCH 039/296] build(deps): bump the tanstack-query group in /frontend with 2 updates Bumps the tanstack-query group in /frontend with 2 updates: [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) and [@tanstack/react-query-devtools](https://github.com/TanStack/query/tree/HEAD/packages/react-query-devtools). Updates `@tanstack/react-query` from 5.85.5 to 5.87.4 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.87.4/packages/react-query) Updates `@tanstack/react-query-devtools` from 5.85.5 to 5.87.4 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.87.4/packages/react-query-devtools) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.87.4 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: tanstack-query - dependency-name: "@tanstack/react-query-devtools" dependency-version: 5.87.4 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: tanstack-query ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 34 +++++++++++++++++----------------- frontend/package.json | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index daf3c27b9..dcc2b65c2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,7 @@ "@fontsource/inter": "^5.2.6", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", - "@tanstack/react-query": "^5.85.5", + "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "5.0.2", "@vector-im/compound-web": "^8.2.0", @@ -38,7 +38,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", - "@tanstack/react-query-devtools": "^5.85.5", + "@tanstack/react-query-devtools": "^5.87.4", "@tanstack/react-router-devtools": "^1.131.42", "@tanstack/router-plugin": "^1.131.41", "@testing-library/jest-dom": "^6.8.0", @@ -4904,9 +4904,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.85.5", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.5.tgz", - "integrity": "sha512-KO0WTob4JEApv69iYp1eGvfMSUkgw//IpMnq+//cORBzXf0smyRwPLrUvEe5qtAEGjwZTXrjxg+oJNP/C00t6w==", + "version": "5.87.4", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.87.4.tgz", + "integrity": "sha512-uNsg6zMxraEPDVO2Bn+F3/ctHi+Zsk+MMpcN8h6P7ozqD088F6mFY5TfGM7zuyIrL7HKpDyu6QHfLWiDxh3cuw==", "license": "MIT", "funding": { "type": "github", @@ -4914,9 +4914,9 @@ } }, "node_modules/@tanstack/query-devtools": { - "version": "5.84.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.84.0.tgz", - "integrity": "sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ==", + "version": "5.87.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.87.3.tgz", + "integrity": "sha512-LkzxzSr2HS1ALHTgDmJH5eGAVsSQiuwz//VhFW5OqNk0OQ+Fsqba0Tsf+NzWRtXYvpgUqwQr4b2zdFZwxHcGvg==", "dev": true, "license": "MIT", "funding": { @@ -4925,12 +4925,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.85.5", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.5.tgz", - "integrity": "sha512-/X4EFNcnPiSs8wM2v+b6DqS5mmGeuJQvxBglmDxl6ZQb5V26ouD2SJYAcC3VjbNwqhY2zjxVD15rDA5nGbMn3A==", + "version": "5.87.4", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.87.4.tgz", + "integrity": "sha512-T5GT/1ZaNsUXf5I3RhcYuT17I4CPlbZgyLxc/ZGv7ciS6esytlbjb3DgUFO6c8JWYMDpdjSWInyGZUErgzqhcA==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.85.5" + "@tanstack/query-core": "5.87.4" }, "funding": { "type": "github", @@ -4941,20 +4941,20 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.85.5", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.85.5.tgz", - "integrity": "sha512-6Ol6Q+LxrCZlQR4NoI5181r+ptTwnlPG2t7H9Sp3klxTBhYGunONqcgBn2YKRPsaKiYM8pItpKMdMXMEINntMQ==", + "version": "5.87.4", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.87.4.tgz", + "integrity": "sha512-JYcnVJBBW1DCPyNGM0S2CyrLpe6KFiL2gpYd/k9tAp62Du7+Y27zkzd+dKFyxpFadYaTxsx4kUA7YvnkMLVUoQ==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/query-devtools": "5.84.0" + "@tanstack/query-devtools": "5.87.3" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.85.5", + "@tanstack/react-query": "^5.87.4", "react": "^18 || ^19" } }, diff --git a/frontend/package.json b/frontend/package.json index a1a00a2fc..414ba2608 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,7 +22,7 @@ "@fontsource/inter": "^5.2.6", "@radix-ui/react-collapsible": "^1.1.11", "@radix-ui/react-dialog": "^1.1.14", - "@tanstack/react-query": "^5.85.5", + "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "5.0.2", "@vector-im/compound-web": "^8.2.0", @@ -48,7 +48,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", - "@tanstack/react-query-devtools": "^5.85.5", + "@tanstack/react-query-devtools": "^5.87.4", "@tanstack/react-router-devtools": "^1.131.42", "@tanstack/router-plugin": "^1.131.41", "@testing-library/jest-dom": "^6.8.0", From 5d4c3f7a34f01bde2ffc68de2d090322aeac1a6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:51:20 +0000 Subject: [PATCH 040/296] build(deps-dev): bump the types group in /frontend with 3 updates Bumps the types group in /frontend with 3 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom). Updates `@types/node` from 24.3.0 to 24.3.1 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/react` from 19.1.10 to 19.1.12 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) Updates `@types/react-dom` from 19.1.7 to 19.1.9 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types - dependency-name: "@types/react" dependency-version: 19.1.12 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types - dependency-name: "@types/react-dom" dependency-version: 19.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index daf3c27b9..3ce6b2d81 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,9 +44,9 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.3.0", - "@types/react": "19.1.10", - "@types/react-dom": "19.1.7", + "@types/node": "^24.3.1", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.2", "@vitest/coverage-v8": "^3.2.4", @@ -5428,9 +5428,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", - "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", + "version": "24.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", + "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", "dev": true, "license": "MIT", "dependencies": { @@ -5438,9 +5438,9 @@ } }, "node_modules/@types/react": { - "version": "19.1.10", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", - "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", + "version": "19.1.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", + "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5448,9 +5448,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.1.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", - "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", + "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", "devOptional": true, "license": "MIT", "peerDependencies": { diff --git a/frontend/package.json b/frontend/package.json index a1a00a2fc..31e11db7f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,9 +54,9 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.3.0", - "@types/react": "19.1.10", - "@types/react-dom": "19.1.7", + "@types/node": "^24.3.1", + "@types/react": "19.1.12", + "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.2", "@vitest/coverage-v8": "^3.2.4", From a55d545e51a25b3d2c5395262bf4e457e739f011 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:51:32 +0000 Subject: [PATCH 041/296] build(deps-dev): bump msw from 2.11.1 to 2.11.2 in /frontend Bumps [msw](https://github.com/mswjs/msw) from 2.11.1 to 2.11.2. - [Release notes](https://github.com/mswjs/msw/releases) - [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md) - [Commits](https://github.com/mswjs/msw/compare/v2.11.1...v2.11.2) --- updated-dependencies: - dependency-name: msw dependency-version: 2.11.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++++++---- frontend/package.json | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index daf3c27b9..0e946d703 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -56,7 +56,7 @@ "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", "knip": "^5.62.0", - "msw": "^2.11.1", + "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", @@ -9677,9 +9677,9 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.1.tgz", - "integrity": "sha512-dGSRx0AJmQVQfpGXTsAAq4JFdwdhOBdJ6sJS/jnN0ac3s0NZB6daacHF1z5Pefx+IejmvuiLWw260RlyQOf3sQ==", + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.2.tgz", + "integrity": "sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -9698,6 +9698,7 @@ "outvariant": "^1.4.3", "path-to-regexp": "^6.3.0", "picocolors": "^1.1.1", + "rettime": "^0.7.0", "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.0", "type-fest": "^4.26.1", @@ -11183,6 +11184,13 @@ "dev": true, "license": "ISC" }, + "node_modules/rettime": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", + "integrity": "sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==", + "dev": true, + "license": "MIT" + }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index a1a00a2fc..bdacde7df 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,7 +66,7 @@ "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", "knip": "^5.62.0", - "msw": "^2.11.1", + "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", From 2ba8faee8d9f3346714151842b19d761efec0230 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:53:21 +0000 Subject: [PATCH 042/296] build(deps): bump chrono from 0.4.41 to 0.4.42 Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.41 to 0.4.42. - [Release notes](https://github.com/chronotope/chrono/releases) - [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md) - [Commits](https://github.com/chronotope/chrono/compare/v0.4.41...v0.4.42) --- updated-dependencies: - dependency-name: chrono dependency-version: 0.4.42 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 29 ++++++++++++++--------------- Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb8a1a24b..9e124f1b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -123,12 +123,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -914,17 +908,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -2252,7 +2245,7 @@ checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" dependencies = [ "cfg-if", "libc", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7340,7 +7333,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -7373,13 +7366,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-result" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7388,7 +7387,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -7488,7 +7487,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/Cargo.toml b/Cargo.toml index 53383f4f2..c5488a3dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -161,7 +161,7 @@ features = ["serde_json"] # Time utilities [workspace.dependencies.chrono] -version = "0.4.41" +version = "0.4.42" default-features = false features = ["serde", "clock"] From 14486371d865608a1f7303fb5d96c5889883328a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:54:06 +0000 Subject: [PATCH 043/296] build(deps): bump pest_derive from 2.8.1 to 2.8.2 Bumps [pest_derive](https://github.com/pest-parser/pest) from 2.8.1 to 2.8.2. - [Release notes](https://github.com/pest-parser/pest/releases) - [Commits](https://github.com/pest-parser/pest/compare/v2.8.1...v2.8.2) --- updated-dependencies: - dependency-name: pest_derive dependency-version: 2.8.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb8a1a24b..d92f4ca12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4396,9 +4396,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" dependencies = [ "pest", "pest_generator", @@ -4406,9 +4406,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" dependencies = [ "pest", "pest_meta", @@ -4419,9 +4419,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" dependencies = [ "pest", "sha2", diff --git a/Cargo.toml b/Cargo.toml index 53383f4f2..5e9d29f75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -458,7 +458,7 @@ version = "2.8.2" # Pest derive macros [workspace.dependencies.pest_derive] -version = "2.8.1" +version = "2.8.2" # Pin projection [workspace.dependencies.pin-project-lite] From c527eda57a9e2e66cbd4d858e03898aec4130b9b Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 15:54:47 +0200 Subject: [PATCH 044/296] Update mockServiceWorker.js to 2.11.2 --- .../.storybook/public/mockServiceWorker.js | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/frontend/.storybook/public/mockServiceWorker.js b/frontend/.storybook/public/mockServiceWorker.js index 7e23102e0..2eec3ee33 100644 --- a/frontend/.storybook/public/mockServiceWorker.js +++ b/frontend/.storybook/public/mockServiceWorker.js @@ -7,8 +7,8 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.11.1' -const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af' +const PACKAGE_VERSION = '2.11.2' +const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -71,11 +71,6 @@ addEventListener('message', async function (event) { break } - case 'MOCK_DEACTIVATE': { - activeClientIds.delete(clientId) - break - } - case 'CLIENT_CLOSED': { activeClientIds.delete(clientId) @@ -94,6 +89,8 @@ addEventListener('message', async function (event) { }) addEventListener('fetch', function (event) { + const requestInterceptedAt = Date.now() + // Bypass navigation requests. if (event.request.mode === 'navigate') { return @@ -110,23 +107,29 @@ addEventListener('fetch', function (event) { // Bypass all requests when there are no active clients. // Prevents the self-unregistered worked from handling requests - // after it's been deleted (still remains active until the next reload). + // after it's been terminated (still remains active until the next reload). if (activeClientIds.size === 0) { return } const requestId = crypto.randomUUID() - event.respondWith(handleRequest(event, requestId)) + event.respondWith(handleRequest(event, requestId, requestInterceptedAt)) }) /** * @param {FetchEvent} event * @param {string} requestId + * @param {number} requestInterceptedAt */ -async function handleRequest(event, requestId) { +async function handleRequest(event, requestId, requestInterceptedAt) { const client = await resolveMainClient(event) const requestCloneForEvents = event.request.clone() - const response = await getResponse(event, client, requestId) + const response = await getResponse( + event, + client, + requestId, + requestInterceptedAt, + ) // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise @@ -204,7 +207,7 @@ async function resolveMainClient(event) { * @param {string} requestId * @returns {Promise} */ -async function getResponse(event, client, requestId) { +async function getResponse(event, client, requestId, requestInterceptedAt) { // Clone the request because it might've been already used // (i.e. its body has been read and sent to the client). const requestClone = event.request.clone() @@ -255,6 +258,7 @@ async function getResponse(event, client, requestId) { type: 'REQUEST', payload: { id: requestId, + interceptedAt: requestInterceptedAt, ...serializedRequest, }, }, From 7aa9a9ad408ddb01c418307600c0d720943f0ced Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 13:55:04 +0000 Subject: [PATCH 045/296] build(deps): bump insta from 1.43.1 to 1.43.2 Bumps [insta](https://github.com/mitsuhiko/insta) from 1.43.1 to 1.43.2. - [Release notes](https://github.com/mitsuhiko/insta/releases) - [Changelog](https://github.com/mitsuhiko/insta/blob/master/CHANGELOG.md) - [Commits](https://github.com/mitsuhiko/insta/compare/1.43.1...1.43.2) --- updated-dependencies: - dependency-name: insta dependency-version: 1.43.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb8a1a24b..f76284c47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2777,9 +2777,9 @@ dependencies = [ [[package]] name = "insta" -version = "1.43.1" +version = "1.43.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" +checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" dependencies = [ "console", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 53383f4f2..6c878ea9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,7 +330,7 @@ version = "2.0.6" # Snapshot testing [workspace.dependencies.insta] -version = "1.43.1" +version = "1.43.2" features = ["yaml", "json"] # IP network address types From 40e74aa5d94a6851034f771db53b831e94145986 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Sep 2025 14:03:36 +0000 Subject: [PATCH 046/296] build(deps): bump @vector-im/compound-design-tokens in /frontend Bumps [@vector-im/compound-design-tokens](https://github.com/vector-im/compound-design-tokens) from 5.0.2 to 6.0.0. - [Release notes](https://github.com/vector-im/compound-design-tokens/releases) - [Changelog](https://github.com/element-hq/compound-design-tokens/blob/main/docs/release.md) - [Commits](https://github.com/vector-im/compound-design-tokens/compare/v5.0.2...v6.0.0) --- updated-dependencies: - dependency-name: "@vector-im/compound-design-tokens" dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c7d95a363..3ae942f60 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,7 @@ "@radix-ui/react-dialog": "^1.1.14", "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", - "@vector-im/compound-design-tokens": "5.0.2", + "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.0", "@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4", @@ -5503,9 +5503,9 @@ } }, "node_modules/@vector-im/compound-design-tokens": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@vector-im/compound-design-tokens/-/compound-design-tokens-5.0.2.tgz", - "integrity": "sha512-LcdrGY9qktuSs9TNX+DdGGq64vP7Qk5FiiqtZBr4PEk+hCQPEyRtKDfkXbAST+0tpAjUqVp5pzlOqNUKhpIhfg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@vector-im/compound-design-tokens/-/compound-design-tokens-6.0.0.tgz", + "integrity": "sha512-Jk0NsLPCvdcuZi6an1cfyf4MDcIuoPlvja5ZWgJcORyGQZV1eLMHPYKShq9gj+EYk/BXZoPvQ1d6/T+/LSCNPA==", "license": "SEE LICENSE IN README.md", "peerDependencies": { "@types/react": "*", diff --git a/frontend/package.json b/frontend/package.json index 11ca8a203..18c530891 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,7 +24,7 @@ "@radix-ui/react-dialog": "^1.1.14", "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", - "@vector-im/compound-design-tokens": "5.0.2", + "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.0", "@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4", From ca9aeb42c068fcb0fd4aea34d81e16679af3c37c Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 17:46:53 +0200 Subject: [PATCH 047/296] Admin API to expose a few configuration values --- crates/handlers/src/admin/mod.rs | 8 +- crates/handlers/src/admin/v1/mod.rs | 8 +- crates/handlers/src/admin/v1/site_config.rs | 92 +++++++++++++++++ crates/handlers/src/bin/api-schema.rs | 1 + docs/api/spec.json | 103 ++++++++++++++++++++ 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 crates/handlers/src/admin/v1/site_config.rs diff --git a/crates/handlers/src/admin/mod.rs b/crates/handlers/src/admin/mod.rs index 8cc2956c0..2670d35ab 100644 --- a/crates/handlers/src/admin/mod.rs +++ b/crates/handlers/src/admin/mod.rs @@ -20,7 +20,7 @@ use axum::{ use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE}; use indexmap::IndexMap; use mas_axum_utils::InternalError; -use mas_data_model::BoxRng; +use mas_data_model::{BoxRng, SiteConfig}; use mas_http::CorsLayerExt; use mas_matrix::HomeserverConnection; use mas_policy::PolicyFactory; @@ -43,6 +43,11 @@ use crate::passwords::PasswordManager; fn finish(t: TransformOpenApi) -> TransformOpenApi { t.title("Matrix Authentication Service admin API") + .tag(Tag { + name: "server".to_owned(), + description: Some("Information about the server".to_owned()), + ..Tag::default() + }) .tag(Tag { name: "compat-session".to_owned(), description: Some("Manage compatibility sessions from legacy clients".to_owned()), @@ -153,6 +158,7 @@ where Templates: FromRef, UrlBuilder: FromRef, Arc: FromRef, + SiteConfig: FromRef, { // We *always* want to explicitly set the possible responses, beacuse the // infered ones are not necessarily correct diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index 49ff75001..afe71a05f 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -11,7 +11,7 @@ use aide::axum::{ routing::{get_with, post_with}, }; use axum::extract::{FromRef, FromRequestParts}; -use mas_data_model::BoxRng; +use mas_data_model::{BoxRng, SiteConfig}; use mas_matrix::HomeserverConnection; use mas_policy::PolicyFactory; @@ -21,6 +21,7 @@ use crate::passwords::PasswordManager; mod compat_sessions; mod oauth2_sessions; mod policy_data; +mod site_config; mod upstream_oauth_links; mod user_emails; mod user_registration_tokens; @@ -32,11 +33,16 @@ where S: Clone + Send + Sync + 'static, Arc: FromRef, PasswordManager: FromRef, + SiteConfig: FromRef, Arc: FromRef, BoxRng: FromRequestParts, CallContext: FromRequestParts, { ApiRouter::::new() + .api_route( + "/site-config", + get_with(self::site_config::handler, self::site_config::doc), + ) .api_route( "/compat-sessions", get_with(self::compat_sessions::list, self::compat_sessions::list_doc), diff --git a/crates/handlers/src/admin/v1/site_config.rs b/crates/handlers/src/admin/v1/site_config.rs new file mode 100644 index 000000000..b9b05dac7 --- /dev/null +++ b/crates/handlers/src/admin/v1/site_config.rs @@ -0,0 +1,92 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::transform::TransformOperation; +use axum::{Json, extract::State}; +use schemars::JsonSchema; +use serde::Serialize; + +use crate::admin::call_context::CallContext; + +#[allow(clippy::struct_excessive_bools)] +#[derive(Serialize, JsonSchema)] +pub struct SiteConfig { + /// The Matrix server name for which this instance is configured + server_name: String, + + /// Whether password login is enabled. + pub password_login_enabled: bool, + + /// Whether password registration is enabled. + pub password_registration_enabled: bool, + + /// Whether registration tokens are required for password registrations. + pub registration_token_required: bool, + + /// Whether users can change their email. + pub email_change_allowed: bool, + + /// Whether users can change their display name. + pub displayname_change_allowed: bool, + + /// Whether users can change their password. + pub password_change_allowed: bool, + + /// Whether users can recover their account via email. + pub account_recovery_allowed: bool, + + /// Whether users can delete their own account. + pub account_deactivation_allowed: bool, + + /// Whether CAPTCHA during registration is enabled. + pub captcha_enabled: bool, + + /// Minimum password complexity, between 0 and 4. + /// This is a score from zxcvbn. + #[schemars(range(min = 0, max = 4))] + pub minimum_password_complexity: u8, +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("siteConfig") + .tag("server") + .summary("Get informations about the configuration of this MAS instance") + .response_with::<200, Json, _>(|t| { + t.example(SiteConfig { + server_name: "example.com".to_owned(), + password_login_enabled: true, + password_registration_enabled: true, + registration_token_required: true, + email_change_allowed: true, + displayname_change_allowed: true, + password_change_allowed: true, + account_recovery_allowed: true, + account_deactivation_allowed: true, + captcha_enabled: true, + minimum_password_complexity: 3, + }) + }) +} + +#[tracing::instrument(name = "handler.admin.v1.site_config", skip_all)] +pub async fn handler( + _: CallContext, + State(site_config): State, +) -> Json { + Json(SiteConfig { + server_name: site_config.server_name, + password_login_enabled: site_config.password_login_enabled, + password_registration_enabled: site_config.password_registration_enabled, + registration_token_required: site_config.registration_token_required, + email_change_allowed: site_config.email_change_allowed, + displayname_change_allowed: site_config.displayname_change_allowed, + password_change_allowed: site_config.password_change_allowed, + account_recovery_allowed: site_config.account_recovery_allowed, + account_deactivation_allowed: site_config.account_deactivation_allowed, + captcha_enabled: site_config.captcha.is_some(), + minimum_password_complexity: site_config.minimum_password_complexity, + }) +} diff --git a/crates/handlers/src/bin/api-schema.rs b/crates/handlers/src/bin/api-schema.rs index 894546961..6eed219da 100644 --- a/crates/handlers/src/bin/api-schema.rs +++ b/crates/handlers/src/bin/api-schema.rs @@ -59,6 +59,7 @@ impl_from_ref!(Arc); impl_from_ref!(mas_keystore::Keystore); impl_from_ref!(mas_handlers::passwords::PasswordManager); impl_from_ref!(Arc); +impl_from_ref!(mas_data_model::SiteConfig); fn main() -> Result<(), Box> { let (mut api, _) = mas_handlers::admin_api_router::(); diff --git a/docs/api/spec.json b/docs/api/spec.json index 9e3e336aa..ab8e7f2ec 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -16,6 +16,40 @@ } ], "paths": { + "/api/admin/v1/site-config": { + "get": { + "tags": [ + "server" + ], + "summary": "Get informations about the configuration of this MAS instance", + "operationId": "siteConfig", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SiteConfig" + }, + "example": { + "server_name": "example.com", + "password_login_enabled": true, + "password_registration_enabled": true, + "registration_token_required": true, + "email_change_allowed": true, + "displayname_change_allowed": true, + "password_change_allowed": true, + "account_recovery_allowed": true, + "account_deactivation_allowed": true, + "captcha_enabled": true, + "minimum_password_complexity": 3 + } + } + } + } + } + } + }, "/api/admin/v1/compat-sessions": { "get": { "tags": [ @@ -3186,6 +3220,71 @@ } }, "schemas": { + "SiteConfig": { + "type": "object", + "required": [ + "account_deactivation_allowed", + "account_recovery_allowed", + "captcha_enabled", + "displayname_change_allowed", + "email_change_allowed", + "minimum_password_complexity", + "password_change_allowed", + "password_login_enabled", + "password_registration_enabled", + "registration_token_required", + "server_name" + ], + "properties": { + "server_name": { + "description": "The Matrix server name for which this instance is configured", + "type": "string" + }, + "password_login_enabled": { + "description": "Whether password login is enabled.", + "type": "boolean" + }, + "password_registration_enabled": { + "description": "Whether password registration is enabled.", + "type": "boolean" + }, + "registration_token_required": { + "description": "Whether registration tokens are required for password registrations.", + "type": "boolean" + }, + "email_change_allowed": { + "description": "Whether users can change their email.", + "type": "boolean" + }, + "displayname_change_allowed": { + "description": "Whether users can change their display name.", + "type": "boolean" + }, + "password_change_allowed": { + "description": "Whether users can change their password.", + "type": "boolean" + }, + "account_recovery_allowed": { + "description": "Whether users can recover their account via email.", + "type": "boolean" + }, + "account_deactivation_allowed": { + "description": "Whether users can delete their own account.", + "type": "boolean" + }, + "captcha_enabled": { + "description": "Whether CAPTCHA during registration is enabled.", + "type": "boolean" + }, + "minimum_password_complexity": { + "description": "Minimum password complexity, between 0 and 4. This is a score from zxcvbn.", + "type": "integer", + "format": "uint8", + "maximum": 4.0, + "minimum": 0.0 + } + } + }, "PaginationParams": { "type": "object", "properties": { @@ -4586,6 +4685,10 @@ } ], "tags": [ + { + "name": "server", + "description": "Information about the server" + }, { "name": "compat-session", "description": "Manage compatibility sessions from legacy clients" From 38cc1ae0f28bb85ea2a8d6d01bff0133d65099c7 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 12 Sep 2025 18:04:34 +0200 Subject: [PATCH 048/296] Update most frontend dependencies --- frontend/package-lock.json | 1914 ++++++++++++++++++++---------------- frontend/package.json | 14 +- 2 files changed, 1060 insertions(+), 868 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3ae942f60..dabbd635d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,12 +10,12 @@ "dependencies": { "@fontsource/inconsolata": "^5.2.7", "@fontsource/inter": "^5.2.6", - "@radix-ui/react-collapsible": "^1.1.11", - "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "6.0.0", - "@vector-im/compound-web": "^8.2.0", + "@vector-im/compound-web": "^8.2.4", "@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", @@ -24,7 +24,7 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^15.7.3", - "swagger-ui-dist": "^5.27.1", + "swagger-ui-dist": "^5.29.0", "valibot": "^1.1.0", "vaul": "^1.1.2" }, @@ -55,14 +55,14 @@ "graphql": "^16.11.0", "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", - "knip": "^5.62.0", + "knip": "^5.63.1", "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", "postcss-nesting": "^13.0.2", "rimraf": "^6.0.1", - "storybook": "^9.0.1", + "storybook": "^9.1.5", "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", @@ -70,13 +70,13 @@ "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.6.3", "vite-plugin-manifest-sri": "^0.2.0", - "vitest": "^3.2.3" + "vitest": "^3.2.4" } }, "node_modules/@adobe/css-tools": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", - "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", "dev": true, "license": "MIT" }, @@ -148,9 +148,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", - "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, "license": "MIT", "engines": { @@ -188,16 +188,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", @@ -245,29 +235,19 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", - "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.27.1", "@babel/helper-optimise-call-expression": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.27.1", + "@babel/traverse": "^7.28.3", "semver": "^6.3.1" }, "engines": { @@ -277,21 +257,12 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -619,9 +590,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz", - "integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", + "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", "dev": true, "license": "MIT", "dependencies": { @@ -635,18 +606,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", - "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.27.1", - "globals": "^11.1.0" + "@babel/traverse": "^7.28.4" }, "engines": { "node": ">=6.9.0" @@ -673,13 +644,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz", - "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -807,9 +779,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", - "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, "license": "MIT", "dependencies": { @@ -839,9 +811,9 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.27.1.tgz", - "integrity": "sha512-p9+Vl3yuHPmkirRrg021XiP+EETmPMQTLr6Ayjj85RLNEbb3Eya/4VI0vAdzQG9SEAl2Lnt7fy5lZyMzjYoZQQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", "dev": true, "license": "MIT", "dependencies": { @@ -996,9 +968,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1310,21 +1282,21 @@ } }, "node_modules/@emnapi/core": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", - "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.0.2", + "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", - "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", "dev": true, "license": "MIT", "optional": true, @@ -1333,9 +1305,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", - "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "dev": true, "license": "MIT", "optional": true, @@ -1344,9 +1316,9 @@ } }, "node_modules/@envelop/core": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@envelop/core/-/core-5.2.3.tgz", - "integrity": "sha512-KfoGlYD/XXQSc3BkM1/k15+JQbkQ4ateHazeZoWl9P71FsLTDXSjGy6j7QqfhpIDSbxNISqhPMfZHYSbDFOofQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@envelop/core/-/core-5.3.1.tgz", + "integrity": "sha512-n29V3vRqXvPcG76C8zE482LQykk0P66zv1mjpk7aHeGe9qnh8AzB/RvoX5SVFwApJQPp0ixob8NoYXg4FHKMGA==", "dev": true, "license": "MIT", "dependencies": { @@ -1388,9 +1360,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", - "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -1405,9 +1377,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", - "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -1422,9 +1394,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", - "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -1439,9 +1411,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", - "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -1456,9 +1428,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", - "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -1473,9 +1445,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", - "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -1490,9 +1462,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", - "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -1507,9 +1479,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", - "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -1524,9 +1496,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", - "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -1541,9 +1513,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", - "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -1558,9 +1530,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", - "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -1575,9 +1547,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", - "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -1592,9 +1564,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", - "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -1609,9 +1581,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", - "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -1626,9 +1598,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", - "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -1643,9 +1615,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", - "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -1660,9 +1632,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", - "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -1677,9 +1649,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", - "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -1694,9 +1666,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", - "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -1711,9 +1683,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", - "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -1728,9 +1700,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", - "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -1744,10 +1716,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", - "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -1762,9 +1751,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", - "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -1779,9 +1768,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", - "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -1796,9 +1785,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", - "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -1813,39 +1802,39 @@ } }, "node_modules/@fastify/busboy": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.1.1.tgz", - "integrity": "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-3.2.0.tgz", + "integrity": "sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==", "dev": true, "license": "MIT" }, "node_modules/@floating-ui/core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz", - "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz", - "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.1", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/react": { - "version": "0.27.12", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.12.tgz", - "integrity": "sha512-kKlWNrpIQxF1B/a2MZvE0/uyKby4960yjO91W7nVyNKmmfNi62xU9HCjL1M1eWzx/LFj/VPSwJVbwQk9Pq/68A==", + "version": "0.27.16", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.16.tgz", + "integrity": "sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==", "license": "MIT", "dependencies": { - "@floating-ui/react-dom": "^2.1.3", - "@floating-ui/utils": "^0.2.9", + "@floating-ui/react-dom": "^2.1.6", + "@floating-ui/utils": "^0.2.10", "tabbable": "^6.0.0" }, "peerDependencies": { @@ -1854,12 +1843,12 @@ } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.3.tgz", - "integrity": "sha512-huMBfiU9UnQ2oBwIhgzyIiSpVgvlDstU8CX0AF+wS+KzmYMs0J2a3GwuFHV1Lz+jlrQGeC1fF+Nv0QoumyV0bA==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0" + "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", @@ -1867,9 +1856,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@fontsource/inconsolata": { @@ -1978,6 +1967,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.8.3.tgz", "integrity": "sha512-QpEsPSO9fnRxA6Z66AmBuGcwHjZ6dYSxYo5ycMlYgSPzAbyG8gn/kWljofjJfWqSY+T/lRn+r8IXTH14ml24vQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", @@ -2118,6 +2108,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.1.2.tgz", "integrity": "sha512-jaxfViDqFRbNQmfKwUY8hDyjnLTw2Z7DhGutxoOiiAI0gE/LfPe0LYaVFKVmVOOD7M3bWxoWfu4slrkbWbUbEw==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/visitor-plugin-common": "5.8.0", @@ -2136,7 +2127,8 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { "version": "4.1.6", @@ -2421,6 +2413,16 @@ "node": ">=8" } }, + "node_modules/@graphql-codegen/typescript-msw/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@graphql-codegen/typescript-msw/node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", @@ -2548,13 +2550,13 @@ } }, "node_modules/@graphql-tools/apollo-engine-loader": { - "version": "8.0.20", - "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.20.tgz", - "integrity": "sha512-m5k9nXSyjq31yNsEqDXLyykEjjn3K3Mo73oOKI+Xjy8cpnsgbT4myeUJIYYQdLrp7fr9Y9p7ZgwT5YcnwmnAbA==", + "version": "8.0.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.22.tgz", + "integrity": "sha512-ssD2wNxeOTRcUEkuGcp0KfZAGstL9YLTe/y3erTDZtOs2wL1TJESw8NVAp+3oUHPeHKBZQB4Z6RFEbPgMdT2wA==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "@whatwg-node/fetch": "^0.10.0", "sync-fetch": "0.6.0-2", "tslib": "^2.4.0" @@ -2567,13 +2569,13 @@ } }, "node_modules/@graphql-tools/batch-execute": { - "version": "9.0.17", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.17.tgz", - "integrity": "sha512-i7BqBkUP2+ex8zrQrCQTEt6nYHQmIey9qg7CMRRa1hXCY2X8ZCVjxsvbsi7gOLwyI/R3NHxSRDxmzZevE2cPLg==", + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.19.tgz", + "integrity": "sha512-VGamgY4PLzSx48IHPoblRw0oTaBa7S26RpZXt0Y4NN90ytoE0LutlpB2484RbkfcTjv9wa64QD474+YP1kEgGA==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.1", + "@graphql-tools/utils": "^10.9.1", "@whatwg-node/promise-helpers": "^1.3.0", "dataloader": "^2.2.3", "tslib": "^2.8.1" @@ -2586,14 +2588,14 @@ } }, "node_modules/@graphql-tools/code-file-loader": { - "version": "8.1.20", - "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.20.tgz", - "integrity": "sha512-GzIbjjWJIc04KWnEr8VKuPe0FA2vDTlkaeub5p4lLimljnJ6C0QSkOyCUnFmsB9jetQcHm0Wfmn/akMnFUG+wA==", + "version": "8.1.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.22.tgz", + "integrity": "sha512-FSka29kqFkfFmw36CwoQ+4iyhchxfEzPbXOi37lCEjWLHudGaPkXc3RyB9LdmBxx3g3GHEu43a5n5W8gfcrMdA==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.19", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/graphql-tag-pluck": "8.3.21", + "@graphql-tools/utils": "^10.9.1", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2606,16 +2608,16 @@ } }, "node_modules/@graphql-tools/delegate": { - "version": "10.2.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.2.19.tgz", - "integrity": "sha512-aaCGAALTQmKctHwumbtz0c5XehGjYLSfoDx1IB2vdPt76Q0MKz2AiEDlENgzTVr4JHH7fd9YNrd+IO3D8tFlIg==", + "version": "10.2.23", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.2.23.tgz", + "integrity": "sha512-xrPtl7f1LxS+B6o+W7ueuQh67CwRkfl+UKJncaslnqYdkxKmNBB4wnzVcW8ZsRdwbsla/v43PtwAvSlzxCzq2w==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/batch-execute": "^9.0.17", - "@graphql-tools/executor": "^1.4.7", - "@graphql-tools/schema": "^10.0.11", - "@graphql-tools/utils": "^10.8.1", + "@graphql-tools/batch-execute": "^9.0.19", + "@graphql-tools/executor": "^1.4.9", + "@graphql-tools/schema": "^10.0.25", + "@graphql-tools/utils": "^10.9.1", "@repeaterjs/repeater": "^3.0.6", "@whatwg-node/promise-helpers": "^1.3.0", "dataloader": "^2.2.3", @@ -2647,13 +2649,13 @@ } }, "node_modules/@graphql-tools/executor": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.4.7.tgz", - "integrity": "sha512-U0nK9jzJRP9/9Izf1+0Gggd6K6RNRsheFo1gC/VWzfnsr0qjcOSS9qTjY0OTC5iTPt4tQ+W5Zpw/uc7mebI6aA==", + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.4.9.tgz", + "integrity": "sha512-SAUlDT70JAvXeqV87gGzvDzUGofn39nvaVcVhNf12Dt+GfWHtNNO/RCn/Ea4VJaSLGzraUd41ObnN3i80EBU7w==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "@graphql-typed-document-node/core": "^3.2.0", "@repeaterjs/repeater": "^3.0.4", "@whatwg-node/disposablestack": "^0.0.6", @@ -2685,19 +2687,36 @@ } }, "node_modules/@graphql-tools/executor-graphql-ws": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-2.0.5.tgz", - "integrity": "sha512-gI/D9VUzI1Jt1G28GYpvm5ckupgJ5O8mi5Y657UyuUozX34ErfVdZ81g6oVcKFQZ60LhCzk7jJeykK48gaLhDw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-2.0.7.tgz", + "integrity": "sha512-J27za7sKF6RjhmvSOwOQFeNhNHyP4f4niqPnerJmq73OtLx9Y2PGOhkXOEB0PjhvPJceuttkD2O1yMgEkTGs3Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/executor-common": "^0.0.4", - "@graphql-tools/utils": "^10.8.1", + "@graphql-tools/executor-common": "^0.0.6", + "@graphql-tools/utils": "^10.9.1", "@whatwg-node/disposablestack": "^0.0.6", - "graphql-ws": "^6.0.3", + "graphql-ws": "^6.0.6", "isomorphic-ws": "^5.0.0", "tslib": "^2.8.1", - "ws": "^8.17.1" + "ws": "^8.18.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/executor-graphql-ws/node_modules/@graphql-tools/executor-common": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-common/-/executor-common-0.0.6.tgz", + "integrity": "sha512-JAH/R1zf77CSkpYATIJw+eOJwsbWocdDjY+avY7G+P5HCXxwQjAjWVkJI1QJBQYjPQDVxwf1fmTZlIN3VOadow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@envelop/core": "^5.3.0", + "@graphql-tools/utils": "^10.9.1" }, "engines": { "node": ">=18.0.0" @@ -2731,13 +2750,13 @@ } }, "node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.1.17.tgz", - "integrity": "sha512-TvltY6eL4DY1Vt66Z8kt9jVmNcI+WkvVPQZrPbMCM3rv2Jw/sWvSwzUBezRuWX0sIckMifYVh23VPcGBUKX/wg==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.1.19.tgz", + "integrity": "sha512-bEbv/SlEdhWQD0WZLUX1kOenEdVZk1yYtilrAWjRUgfHRZoEkY9s+oiqOxnth3z68wC2MWYx7ykkS5hhDamixg==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "@types/ws": "^8.0.0", "isomorphic-ws": "^5.0.0", "tslib": "^2.4.0", @@ -2751,14 +2770,14 @@ } }, "node_modules/@graphql-tools/git-loader": { - "version": "8.0.24", - "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.24.tgz", - "integrity": "sha512-ypLC9N2bKNC0QNbrEBTbWKwbV607f7vK2rSGi9uFeGr8E29tWplo6or9V/+TM0ZfIkUsNp/4QX/zKTgo8SbwQg==", + "version": "8.0.26", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.26.tgz", + "integrity": "sha512-0g+9eng8DaT4ZmZvUmPgjLTgesUa6M8xrDjNBltRldZkB055rOeUgJiKmL6u8PjzI5VxkkVsn0wtAHXhDI2UXQ==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.19", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/graphql-tag-pluck": "8.3.21", + "@graphql-tools/utils": "^10.9.1", "is-glob": "4.0.3", "micromatch": "^4.0.8", "tslib": "^2.4.0", @@ -2772,15 +2791,15 @@ } }, "node_modules/@graphql-tools/github-loader": { - "version": "8.0.20", - "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.20.tgz", - "integrity": "sha512-Icch8bKZ1iP3zXCB9I0ded1hda9NPskSSalw7ZM21kXvLiOR5nZhdqPF65gCFkIKo+O4NR4Bp51MkKj+wl+vpg==", + "version": "8.0.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.22.tgz", + "integrity": "sha512-uQ4JNcNPsyMkTIgzeSbsoT9hogLjYrZooLUYd173l5eUGUi49EAcsGdiBCKaKfEjanv410FE8hjaHr7fjSRkJw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-tools/executor-http": "^1.1.9", - "@graphql-tools/graphql-tag-pluck": "^8.3.19", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/graphql-tag-pluck": "^8.3.21", + "@graphql-tools/utils": "^10.9.1", "@whatwg-node/fetch": "^0.10.0", "@whatwg-node/promise-helpers": "^1.0.0", "sync-fetch": "0.6.0-2", @@ -2794,14 +2813,14 @@ } }, "node_modules/@graphql-tools/graphql-file-loader": { - "version": "8.0.20", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.20.tgz", - "integrity": "sha512-inds4My+JJxmg5mxKWYtMIJNRxa7MtX+XIYqqD/nu6G4LzQ5KGaBJg6wEl103KxXli7qNOWeVAUmEjZeYhwNEg==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.1.1.tgz", + "integrity": "sha512-5JaUE3zMHW21Oh3bGSNKcr/Mi6oZ9/QWlBCNYbGy+09U23EOZmhPn9a44zP3gXcnnj0C+YVEr8dsMaoaB3UVGQ==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/import": "7.0.19", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/import": "7.1.1", + "@graphql-tools/utils": "^10.9.1", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2814,9 +2833,9 @@ } }, "node_modules/@graphql-tools/graphql-tag-pluck": { - "version": "8.3.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.19.tgz", - "integrity": "sha512-LEw/6IYOUz48HjbWntZXDCzSXsOIM1AyWZrlLoJOrA8QAlhFd8h5Tny7opCypj8FO9VvpPFugWoNDh5InPOEQA==", + "version": "8.3.21", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.21.tgz", + "integrity": "sha512-TJhELNvR1tmghXMi6HVKp/Swxbx1rcSp/zdkuJZT0DCM3vOY11FXY6NW3aoxumcuYDNN3jqXcCPKstYGFPi5GQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2825,7 +2844,7 @@ "@babel/plugin-syntax-import-assertions": "^7.26.0", "@babel/traverse": "^7.26.10", "@babel/types": "^7.26.10", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "tslib": "^2.4.0" }, "engines": { @@ -2836,13 +2855,14 @@ } }, "node_modules/@graphql-tools/import": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.19.tgz", - "integrity": "sha512-Xtku8G4bxnrr6I3hVf8RrBFGYIbQ1OYVjl7jgcy092aBkNZvy1T6EDmXmYXn5F+oLd9Bks3K3WaMm8gma/nM/Q==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.1.1.tgz", + "integrity": "sha512-zhlhaUmeTfV76vMoLRn9xCVMVc7sLf10ve5GKEhXFFDcWA6+vEZGk9CCm1VlPf2kyKGlF7bwLVzfepb3ZoOU9Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", + "@theguild/federation-composition": "^0.19.0", "resolve-from": "5.0.0", "tslib": "^2.4.0" }, @@ -2854,13 +2874,13 @@ } }, "node_modules/@graphql-tools/json-file-loader": { - "version": "8.0.18", - "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.18.tgz", - "integrity": "sha512-JjjIxxewgk8HeMR3npR3YbOkB7fxmdgmqB9kZLWdkRKBxrRXVzhryyq+mhmI0Evzt6pNoHIc3vqwmSctG2sddg==", + "version": "8.0.20", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.20.tgz", + "integrity": "sha512-5v6W+ZLBBML5SgntuBDLsYoqUvwfNboAwL6BwPHi3z/hH1f8BS9/0+MCW9OGY712g7E4pc3y9KqS67mWF753eA==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2873,14 +2893,14 @@ } }, "node_modules/@graphql-tools/load": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.1.0.tgz", - "integrity": "sha512-OGfOm09VyXdNGJS/rLqZ6ztCiG2g6AMxhwtET8GZXTbnjptFc17GtKwJ3Jv5w7mjJ8dn0BHydvIuEKEUK4ciYw==", + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.1.2.tgz", + "integrity": "sha512-WhDPv25/jRND+0uripofMX0IEwo6mrv+tJg6HifRmDu8USCD7nZhufT0PP7lIcuutqjIQFyogqT70BQsy6wOgw==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/schema": "^10.0.23", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/schema": "^10.0.25", + "@graphql-tools/utils": "^10.9.1", "p-limit": "3.1.0", "tslib": "^2.4.0" }, @@ -2892,13 +2912,13 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "9.0.24", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.24.tgz", - "integrity": "sha512-NzWx/Afl/1qHT3Nm1bghGG2l4jub28AdvtG11PoUlmjcIjnFBJMv4vqL0qnxWe8A82peWo4/TkVdjJRLXwgGEw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.1.1.tgz", + "integrity": "sha512-BJ5/7Y7GOhTuvzzO5tSBFL4NGr7PVqTJY3KeIDlVTT8YLcTXtBR+hlrC3uyEym7Ragn+zyWdHeJ9ev+nRX1X2w==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "tslib": "^2.4.0" }, "engines": { @@ -2956,14 +2976,14 @@ } }, "node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.19.tgz", - "integrity": "sha512-xnjLpfzw63yIX1bo+BVh4j1attSwqEkUbpJ+HAhdiSUa3FOQFfpWgijRju+3i87CwhjBANqdTZbcsqLT1hEXig==", + "version": "7.0.21", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.21.tgz", + "integrity": "sha512-vMdU0+XfeBh9RCwPqRsr3A05hPA3MsahFn/7OAwXzMySA5EVnSH5R4poWNs3h1a0yT0tDPLhxORhK7qJdSWj2A==", "dev": true, "license": "MIT", "dependencies": { "@ardatan/relay-compiler": "^12.0.3", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/utils": "^10.9.1", "tslib": "^2.4.0" }, "engines": { @@ -2974,14 +2994,14 @@ } }, "node_modules/@graphql-tools/schema": { - "version": "10.0.23", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.23.tgz", - "integrity": "sha512-aEGVpd1PCuGEwqTXCStpEkmheTHNdMayiIKH1xDWqYp9i8yKv9FRDgkGrY4RD8TNxnf7iII+6KOBGaJ3ygH95A==", + "version": "10.0.25", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.25.tgz", + "integrity": "sha512-/PqE8US8kdQ7lB9M5+jlW8AyVjRGCKU7TSktuW3WNKSKmDO0MK1wakvb5gGdyT49MjAIb4a3LWxIpwo5VygZuw==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/merge": "^9.0.24", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/merge": "^9.1.1", + "@graphql-tools/utils": "^10.9.1", "tslib": "^2.4.0" }, "engines": { @@ -2992,16 +3012,16 @@ } }, "node_modules/@graphql-tools/url-loader": { - "version": "8.0.31", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.31.tgz", - "integrity": "sha512-QGP3py6DAdKERHO5D38Oi+6j+v0O3rkBbnLpyOo87rmIRbwE6sOkL5JeHegHs7EEJ279fBX6lMt8ry0wBMGtyA==", + "version": "8.0.33", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.33.tgz", + "integrity": "sha512-Fu626qcNHcqAj8uYd7QRarcJn5XZ863kmxsg1sm0fyjyfBJnsvC7ddFt6Hayz5kxVKfsnjxiDfPMXanvsQVBKw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-tools/executor-graphql-ws": "^2.0.1", "@graphql-tools/executor-http": "^1.1.9", - "@graphql-tools/executor-legacy-ws": "^1.1.17", - "@graphql-tools/utils": "^10.8.6", + "@graphql-tools/executor-legacy-ws": "^1.1.19", + "@graphql-tools/utils": "^10.9.1", "@graphql-tools/wrap": "^10.0.16", "@types/ws": "^8.0.0", "@whatwg-node/fetch": "^0.10.0", @@ -3019,9 +3039,9 @@ } }, "node_modules/@graphql-tools/utils": { - "version": "10.8.6", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.8.6.tgz", - "integrity": "sha512-Alc9Vyg0oOsGhRapfL3xvqh1zV8nKoFUdtLhXX7Ki4nClaIJXckrA86j+uxEuG3ic6j4jlM1nvcWXRn/71AVLQ==", + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.9.1.tgz", + "integrity": "sha512-B1wwkXk9UvU7LCBkPs8513WxOQ2H8Fo5p8HR1+Id9WmYE5+bd51vqN+MbrqvWczHCH2gwkREgHJN88tE0n1FCw==", "dev": true, "license": "MIT", "dependencies": { @@ -3039,15 +3059,15 @@ } }, "node_modules/@graphql-tools/wrap": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.1.0.tgz", - "integrity": "sha512-M7QolM/cJwM2PNAJS1vphT2/PDVSKtmg5m+fxHrFfKpp2RRosJSvYPzUD/PVPqF2rXTtnCwkgh1s5KIsOPCz+w==", + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.1.4.tgz", + "integrity": "sha512-7pyNKqXProRjlSdqOtrbnFRMQAVamCmEREilOXtZujxY6kYit3tvWWSjUrcIOheltTffoRh7EQSjpy2JDCzasg==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-tools/delegate": "^10.2.19", - "@graphql-tools/schema": "^10.0.11", - "@graphql-tools/utils": "^10.8.1", + "@graphql-tools/delegate": "^10.2.23", + "@graphql-tools/schema": "^10.0.25", + "@graphql-tools/utils": "^10.9.1", "@whatwg-node/promise-helpers": "^1.3.0", "tslib": "^2.8.1" }, @@ -3082,14 +3102,14 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.12.tgz", - "integrity": "sha512-dpq+ielV9/bqgXRUbNH//KsY6WEw9DrGPmipkpmgC1Y46cwuBTNx7PXFWTjc3MQ+urcc0QxoVHcMI0FW4Ok0hg==", + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", + "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.13", - "@inquirer/type": "^3.0.7" + "@inquirer/core": "^10.2.0", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -3104,14 +3124,14 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.13", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.13.tgz", - "integrity": "sha512-1viSxebkYN2nJULlzCxES6G9/stgHSepZ9LqqfdIGPHj5OHhiBUXVS0a6R0bEC2A+VL4D9w6QB66ebCr6HGllA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.12", - "@inquirer/type": "^3.0.7", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", @@ -3152,9 +3172,9 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.0.tgz", - "integrity": "sha512-5v3YXc5ZMfL6OJqXPrX9csb4l7NlQA2doO1yynUjpUChT9hg4JcuBVP0RbsEJ/3SL/sxWEyFjT2W69ZhtoBWqg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -3166,12 +3186,17 @@ }, "peerDependencies": { "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/@inquirer/figures": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.12.tgz", - "integrity": "sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", "dev": true, "license": "MIT", "engines": { @@ -3179,9 +3204,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.7.tgz", - "integrity": "sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", "dev": true, "license": "MIT", "engines": { @@ -3196,6 +3221,29 @@ } } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -3215,9 +3263,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, "license": "MIT", "engines": { @@ -3228,9 +3276,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -3266,9 +3314,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", "dev": true, "license": "MIT", "dependencies": { @@ -3314,6 +3362,7 @@ "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.6.1.tgz", "integrity": "sha512-J4BaTocTOYFkMHIra1JDWrMWpNmBl4EkplIwHEsV8aeUOtdWjwSnln9U7twjMFTAEB7mptNtSKyVi1Y2W9sDJw==", "dev": true, + "license": "MIT", "dependencies": { "glob": "^10.0.0", "magic-string": "^0.30.0", @@ -3330,10 +3379,11 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -3361,26 +3411,27 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@mdx-js/react": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", - "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", "dev": true, "license": "MIT", "dependencies": { @@ -3396,9 +3447,9 @@ } }, "node_modules/@mswjs/interceptors": { - "version": "0.39.2", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.2.tgz", - "integrity": "sha512-RuzCup9Ct91Y7V79xwCb146RaBRHZ7NBbrIUySumd1rpKqHL5OonaqrGIbug5hNwP/fRyxFMA6ISgw4FTtYFYg==", + "version": "0.39.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.6.tgz", + "integrity": "sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==", "dev": true, "license": "MIT", "dependencies": { @@ -3414,16 +3465,16 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz", - "integrity": "sha512-9DPkXtvHydrcOsopiYpUgPHpmj0HWZKMUnL2dZqpvC42lsratuBG06V5ipyno0fUek5VlFsNQ+AcFATSrJXgMA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.4.tgz", + "integrity": "sha512-+ZEtJPp8EF8h4kN6rLQECRor00H7jtDgBVtttIUoxuDkXLiQMaSBqju3LV/IEsMvqVG5pviUvR4jYhIA1xNm8w==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.9.0" + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -3489,10 +3540,38 @@ "dev": true, "license": "MIT" }, + "node_modules/@oxc-resolver/binding-android-arm-eabi": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.7.2.tgz", + "integrity": "sha512-ITflrd9l5pFPXW10w1gOGJqmyeO6LTO/yiXb3st4Uqr6bcPxCdsXZXAZop3QsSeE8DjjfGXv3Ws+Fb2KmYeCrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@oxc-resolver/binding-android-arm64": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.7.2.tgz", + "integrity": "sha512-mjEqCGOZHBpIkjSskW0jkhhVSnaREMmXYW5oDaJKBx86kFSiufEjo8duLTwjRekQ0JlwlEtWiXA759eO4TJ7/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.2.0.tgz", - "integrity": "sha512-ruKLkS+Dm/YIJaUhzEB7zPI+jh3EXxu0QnNV8I7t9jf0lpD2VnltuyRbhrbJEkksklZj//xCMyFFsILGjiU2Mg==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.7.2.tgz", + "integrity": "sha512-sXgElUiNredwvWshUXKL7RbBr6ovSthg3fCTQViY8/jfWKnDRKhUFZiCwABma0CWXC1X2Ij6EkZj40cufRM0bA==", "cpu": [ "arm64" ], @@ -3504,9 +3583,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.2.0.tgz", - "integrity": "sha512-0zhgNUm5bYezdSFOg3FYhtVP83bAq7FTV/3suGQDl/43MixfQG7+bl+hlrP4mz6WlD2SUb2u9BomnJWl1uey9w==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.7.2.tgz", + "integrity": "sha512-EOqYSn1+L5KsShn5lZ303eU9MqjxHNzA7GOHthIcVXfCPtJ+zL89wXh25F+J7mSwiDilp444+rR1hc5Lh+eEWg==", "cpu": [ "x64" ], @@ -3518,9 +3597,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.2.0.tgz", - "integrity": "sha512-SHOxfCcZV1axeIGfyeD1BkdLvfQgjmPy18tO0OUXGElcdScxD6MqU5rj/AVtiuBT+51GtFfOKlwl1+BdVwhD1A==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.7.2.tgz", + "integrity": "sha512-Dyvdj++qc5ANVN3JzqJVAlb+IMUtYLPyLaiPFW4+JfvAQFf/iYkpFQv7maeXhhR+GK3rI+PUQXP2HSIiPsClRg==", "cpu": [ "x64" ], @@ -3532,9 +3611,23 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.2.0.tgz", - "integrity": "sha512-mgEkYrJ+N90sgEDqEZ07zH+4I1D28WjqAhdzfW3aS2x2vynVpoY9jWfHuH8S62vZt3uATJrTKTRa8CjPWEsrdw==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.7.2.tgz", + "integrity": "sha512-wUSx/QqggWowrAiyTSci5YUdHvRFpeBbCn2pUwT8XwDoSY2CBuMYR5qzm68ijjzmrv/XyMhl9HxBLy8/UbczWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.7.2.tgz", + "integrity": "sha512-6w91XhCno0OMqv+UqiuMahasl87Ae8sdSSEFBLF2ic+ySZg+BPpFO5VYUBtdSFJ6gWy7R66JudB5HUJpMbMZlA==", "cpu": [ "arm" ], @@ -3546,9 +3639,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.2.0.tgz", - "integrity": "sha512-BhEzNLjn4HjP8+Q18D3/jeIDBxW7OgoJYIjw2CaaysnYneoTlij8hPTKxHfyqq4IGM3fFs9TLR/k338M3zkQ7g==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.7.2.tgz", + "integrity": "sha512-S2FQ4cYK7JgmTCy0ay5UIUiRTrQdtKUSaAoC+En9yqaoZwHxcQy9HJ53k5jiAPIJnDR0NgAaOl3q11PUxd58XQ==", "cpu": [ "arm64" ], @@ -3560,9 +3653,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.2.0.tgz", - "integrity": "sha512-yxbMYUgRmN2V8x8XoxmD/Qq6aG7YIW3ToMDILfmcfeeRRVieEJ3DOWBT0JSE+YgrOy79OyFDH/1lO8VnqLmDQQ==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.7.2.tgz", + "integrity": "sha512-4Dq8KAJZ4RNe7uSISsoP2/O7fc/rZWqxgkch/5eqa0N0gHMrHd9moGzvdV9Hi9oRSnuTmHzRQTqy02S5L3Rc/g==", "cpu": [ "arm64" ], @@ -3573,10 +3666,38 @@ "linux" ] }, + "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.7.2.tgz", + "integrity": "sha512-/w0wJkrtcjvPUNthhmhbG269ySFgxr/DQCYzhBxICKWbiafmNvJTnmYGtEZKoI+wwnukFL8TT7LWbu7hzdp7mw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.2.0.tgz", - "integrity": "sha512-QG1UfgC2N2qhW1tOnDCgB/26vn1RCshR5sYPhMeaxO1gMQ3kEKbZ3QyBXxrG1IX5qsXYj5hPDJLDYNYUjRcOpg==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.7.2.tgz", + "integrity": "sha512-sFg880S4QCzBw4yqgPDi48sAxGT1iRW6Gd+C/FW2WYXsDK7dnHgWQ8f6Rp509fHGkPAe+G2ZypjrgPhZP4Btew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.7.2.tgz", + "integrity": "sha512-dypXqqwA67fVVpVUedpmHNEYn5vRe/y6zoAvDTfy7Se8QIbkeRvrp1EOL+Q8tfxMM72tdMxgOrfyvJ5SPRgy9Q==", "cpu": [ "riscv64" ], @@ -3588,9 +3709,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.2.0.tgz", - "integrity": "sha512-uqTDsQdi6mrkSV1gvwbuT8jf/WFl6qVDVjNlx7IPSaAByrNiJfPrhTmH8b+Do58Dylz7QIRZgxQ8CHIZSyBUdg==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.7.2.tgz", + "integrity": "sha512-aYDSyViNixd3YpUNcPvfhxAYUiBIPNXfVriTTHEz1ftNg+PglYrOZl5IAssj9uveO6pn2PpNOp/zAezeTtlwmA==", "cpu": [ "s390x" ], @@ -3602,9 +3723,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.2.0.tgz", - "integrity": "sha512-GZdHXhJ7p6GaQg9MjRqLebwBf8BLvGIagccI6z5yMj4fV3LU4QuDfwSEERG+R6oQ/Su9672MBqWwncvKcKT68w==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.7.2.tgz", + "integrity": "sha512-/f5rmPZYeD2/d/siP6wvGGOQsupl074qtvPfSteQnWLIM5lWuUDa/53atjYMJHRHFhfQ7b4B3l84TaO8lszAkA==", "cpu": [ "x64" ], @@ -3616,9 +3737,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.2.0.tgz", - "integrity": "sha512-YBAC3GOicYznReG2twE7oFPSeK9Z1f507z1EYWKg6HpGYRYRlJyszViu7PrhMT85r/MumDTs429zm+CNqpFWOA==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.7.2.tgz", + "integrity": "sha512-5x9CGGTZfGWtemVnkNu4ZjqH4X9Oy+Ovm4wSlQTiKgpwCrSDjj0s4tITqiMif0mkWgoErxpdzfD8+hKQkOIgtw==", "cpu": [ "x64" ], @@ -3630,9 +3751,9 @@ ] }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.2.0.tgz", - "integrity": "sha512-+qlIg45CPVPy+Jn3vqU1zkxA/AAv6e/2Ax/ImX8usZa8Tr2JmQn/93bmSOOOnr9fXRV9d0n4JyqYzSWxWPYDEw==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.7.2.tgz", + "integrity": "sha512-UlUxMVChYfi8nmuT9h9I7rQOfini6b40Ud4zYSeel5Qk8GvUT6eysVXAb+AUCJHMnuFCo6jgGqtXYb3yB5CWEQ==", "cpu": [ "wasm32" ], @@ -3640,16 +3761,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@napi-rs/wasm-runtime": "^1.0.4" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.2.0.tgz", - "integrity": "sha512-AI4KIpS8Zf6vwfOPk0uQPSC0pQ1m5HU4hCbtrgL21JgJSlnJaeEu3/aoOBB45AXKiExBU9R+CDR7aSnW7uhc5A==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.7.2.tgz", + "integrity": "sha512-9S/VfFcl/Tty7TI/ijXgoh05YUzCwP1ApDZxPU8OPFoVTOqnFPQzR8ysR3i/ajQEcEaiCop0aIqXd0xt7wTxNg==", "cpu": [ "arm64" ], @@ -3660,10 +3781,24 @@ "win32" ] }, + "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.7.2.tgz", + "integrity": "sha512-6ruLagAgDx2CCYWVTJJofee4Lq9Oo9wBmKKZowNPwLgurSTGPO0zQDjPvytQ1PjJuOGisqCVLARBsMwbM20mvA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.2.0.tgz", - "integrity": "sha512-r19cQc7HaEJ76HFsMsbiKMTIV2YqFGSof8H5hB7e5Jkb/23Y8Isv1YrSzkDaGhcw02I/COsrPo+eEmjy35eFuA==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.7.2.tgz", + "integrity": "sha512-gp4xNjGkeeNPxjutTSB1AkYm7JQQof6s7wswzzAKuVZO82L1q4HcOz8QYa5PKPP+r2VHUAJAI+FO/X0pNfWn3w==", "cpu": [ "x64" ], @@ -3686,9 +3821,9 @@ } }, "node_modules/@radix-ui/primitive": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", - "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { @@ -3715,16 +3850,16 @@ } }, "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.11.tgz", - "integrity": "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" @@ -3801,14 +3936,14 @@ } }, "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.15.tgz", - "integrity": "sha512-UsQUMjcYTsBjTSXw0P3GO0werEQvUY2plgRQuKoCTtkNr45q1DiL51j4m7gxhABzZ0BadoXNsIbg7F3KwiUBbw==", + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" @@ -3829,20 +3964,20 @@ } }, "node_modules/@radix-ui/react-dialog": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", - "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.10", - "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", @@ -3880,12 +4015,12 @@ } }, "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", @@ -3907,16 +4042,16 @@ } }, "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", - "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, @@ -3936,9 +4071,9 @@ } }, "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", - "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3976,12 +4111,12 @@ } }, "node_modules/@radix-ui/react-form": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.7.tgz", - "integrity": "sha512-IXLKFnaYvFg/KkeV5QfOX7tRnwHXp127koOFUjLWMTrRv5Rny3DQcAtIFFeA/Cli4HHM8DuJCXAUsgnFVJndlw==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", @@ -4045,25 +4180,25 @@ } }, "node_modules/@radix-ui/react-menu": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", - "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.10", - "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", @@ -4085,9 +4220,9 @@ } }, "node_modules/@radix-ui/react-popper": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", - "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", @@ -4141,9 +4276,9 @@ } }, "node_modules/@radix-ui/react-presence": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", - "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -4212,12 +4347,12 @@ } }, "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", - "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", @@ -4425,9 +4560,9 @@ "license": "MIT" }, "node_modules/@rollup/pluginutils": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", - "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4448,9 +4583,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", - "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz", + "integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==", "cpu": [ "arm" ], @@ -4462,9 +4597,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", - "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz", + "integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==", "cpu": [ "arm64" ], @@ -4476,9 +4611,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", - "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz", + "integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==", "cpu": [ "arm64" ], @@ -4490,9 +4625,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", - "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz", + "integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==", "cpu": [ "x64" ], @@ -4504,9 +4639,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", - "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz", + "integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==", "cpu": [ "arm64" ], @@ -4518,9 +4653,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", - "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz", + "integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==", "cpu": [ "x64" ], @@ -4532,9 +4667,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", - "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz", + "integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==", "cpu": [ "arm" ], @@ -4546,9 +4681,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", - "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz", + "integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==", "cpu": [ "arm" ], @@ -4560,9 +4695,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", - "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz", + "integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==", "cpu": [ "arm64" ], @@ -4574,9 +4709,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", - "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz", + "integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==", "cpu": [ "arm64" ], @@ -4588,9 +4723,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", - "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz", + "integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==", "cpu": [ "loong64" ], @@ -4601,10 +4736,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", - "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz", + "integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==", "cpu": [ "ppc64" ], @@ -4616,9 +4751,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", - "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz", + "integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==", "cpu": [ "riscv64" ], @@ -4630,9 +4765,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", - "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz", + "integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==", "cpu": [ "riscv64" ], @@ -4644,9 +4779,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", - "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz", + "integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==", "cpu": [ "s390x" ], @@ -4658,9 +4793,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", - "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz", + "integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==", "cpu": [ "x64" ], @@ -4672,9 +4807,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", - "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz", + "integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==", "cpu": [ "x64" ], @@ -4685,10 +4820,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz", + "integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", - "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz", + "integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==", "cpu": [ "arm64" ], @@ -4700,9 +4849,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", - "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz", + "integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==", "cpu": [ "ia32" ], @@ -4714,9 +4863,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", - "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz", + "integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==", "cpu": [ "x64" ], @@ -5005,43 +5154,13 @@ "react-dom": ">=18.0.0 || >=19.0.0" } }, - "node_modules/@tanstack/react-router-devtools/node_modules/@tanstack/router-devtools-core": { - "version": "1.131.42", - "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.42.tgz", - "integrity": "sha512-o8jKTiwXcUSjmkozcMjIw1yhjVYeXcuQO7DtfgjKW3B85iveH6VzYK+bGEVU7wmLNMuUSe2eI/7RBzJ6a5+MCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1", - "goober": "^2.1.16", - "solid-js": "^1.9.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@tanstack/router-core": "^1.131.41", - "csstype": "^3.0.10", - "solid-js": ">=1.9.5", - "tiny-invariant": "^1.3.3" - }, - "peerDependenciesMeta": { - "csstype": { - "optional": true - } - } - }, "node_modules/@tanstack/react-store": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.1.tgz", - "integrity": "sha512-qUTEKdId6QPWGiWyKAPf/gkN29scEsz6EUSJ0C3HgLMgaqTAyBsQ2sMCfGVcqb+kkhEXAdjleCgH6LAPD6f2sA==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.5.tgz", + "integrity": "sha512-A+WZtEnHZpvbKXm8qR+xndNKywBLez2KKKKEQc7w0Qs45GvY1LpRI3BTZNmELwEVim8+Apf99iEDH2J+MUIzlQ==", "license": "MIT", "dependencies": { - "@tanstack/store": "0.7.1", + "@tanstack/store": "0.7.5", "use-sync-external-store": "^1.5.0" }, "funding": { @@ -5075,6 +5194,36 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/router-devtools-core": { + "version": "1.131.42", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.42.tgz", + "integrity": "sha512-o8jKTiwXcUSjmkozcMjIw1yhjVYeXcuQO7DtfgjKW3B85iveH6VzYK+bGEVU7wmLNMuUSe2eI/7RBzJ6a5+MCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16", + "solid-js": "^1.9.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.131.41", + "csstype": "^3.0.10", + "solid-js": ">=1.9.5", + "tiny-invariant": "^1.3.3" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, "node_modules/@tanstack/router-generator": { "version": "1.131.41", "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.41.tgz", @@ -5154,14 +5303,15 @@ } }, "node_modules/@tanstack/router-plugin/node_modules/unplugin": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz", - "integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==", + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.14.1", - "picomatch": "^4.0.2", + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" }, "engines": { @@ -5191,9 +5341,9 @@ } }, "node_modules/@tanstack/store": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.1.tgz", - "integrity": "sha512-PjUQKXEXhLYj2X5/6c1Xn/0/qKY0IVFxTJweopRfF26xfjVyb14yALydJrHupDh3/d+1WKmfEgZPBVCmDkzzwg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.5.tgz", + "integrity": "sha512-qd/OjkjaFRKqKU4Yjipaen/EOB9MyEg6Wr9fW103RBPACf1ZcKhbhcu2S5mj5IgdPib6xFIgCUti/mKVkl+fRw==", "license": "MIT", "funding": { "type": "github", @@ -5215,9 +5365,9 @@ } }, "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", "peer": true, @@ -5226,9 +5376,9 @@ "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", - "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", + "picocolors": "1.1.1", "pretty-format": "^27.0.2" }, "engines": { @@ -5304,10 +5454,29 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@theguild/federation-composition": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@theguild/federation-composition/-/federation-composition-0.19.1.tgz", + "integrity": "sha512-E4kllHSRYh+FsY0VR+fwl0rmWhDV8xUgWawLZTXmy15nCWQwj0BDsoEpdEXjPh7xes+75cRaeJcSbZ4jkBuSdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "constant-case": "^3.0.4", + "debug": "4.4.1", + "json5": "^2.2.3", + "lodash.sortby": "^4.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "graphql": "^16.0.0" + } + }, "node_modules/@tybys/wasm-util": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", - "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "dev": true, "license": "MIT", "optional": true, @@ -5359,13 +5528,13 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/chai": { @@ -5521,13 +5690,13 @@ } }, "node_modules/@vector-im/compound-web": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-8.2.0.tgz", - "integrity": "sha512-we+EQ/pw2YCEl7EMPdpeqP3HZpnQcCuOHoiAYKFwF4doXBDENLpTyA8ZdX0cViT3sqvExPT0RHZ2Nlt5Y6dQNQ==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@vector-im/compound-web/-/compound-web-8.2.4.tgz", + "integrity": "sha512-Fsb/99r98ICMdtNt/bFcWtLmjyngcye9Ugqm9VDapo1VnrO0wLFJHOcm+J+SvKZwTXCaSndBklygAr5FXk0E9w==", "license": "SEE LICENSE IN README.md", "dependencies": { "@floating-ui/react": "^0.27.0", - "@radix-ui/react-context-menu": "^2.2.1", + "@radix-ui/react-context-menu": "^2.2.16", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-form": "^0.1.0", "@radix-ui/react-progress": "^1.1.0", @@ -5540,7 +5709,7 @@ "@fontsource/inconsolata": "^5", "@fontsource/inter": "^5", "@types/react": "*", - "@vector-im/compound-design-tokens": ">=1.6.1 <6.0.0", + "@vector-im/compound-design-tokens": ">=1.6.1 <7.0.0", "react": "^18 || ^19.0.0" }, "peerDependenciesMeta": { @@ -5609,6 +5778,7 @@ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", "dev": true, + "license": "MIT", "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", @@ -5662,6 +5832,7 @@ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", "dev": true, + "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, @@ -5704,6 +5875,7 @@ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", "dev": true, + "license": "MIT", "dependencies": { "tinyspy": "^4.0.3" }, @@ -5716,6 +5888,7 @@ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", "dev": true, + "license": "MIT", "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", @@ -5740,13 +5913,13 @@ } }, "node_modules/@whatwg-node/fetch": { - "version": "0.10.8", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.8.tgz", - "integrity": "sha512-Rw9z3ctmeEj8QIB9MavkNJqekiu9usBCSMZa+uuAvM0lF3v70oQVCXNppMIqaV6OTZbdaHF1M2HLow58DEw+wg==", + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.10.tgz", + "integrity": "sha512-watz4i/Vv4HpoJ+GranJ7HH75Pf+OkPQ63NoVmru6Srgc8VezTArB00i/oQlnn0KWh14gM42F22Qcc9SU9mo/w==", "dev": true, "license": "MIT", "dependencies": { - "@whatwg-node/node-fetch": "^0.7.21", + "@whatwg-node/node-fetch": "^0.7.25", "urlpattern-polyfill": "^10.0.0" }, "engines": { @@ -5754,9 +5927,9 @@ } }, "node_modules/@whatwg-node/node-fetch": { - "version": "0.7.21", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.21.tgz", - "integrity": "sha512-QC16IdsEyIW7kZd77aodrMO7zAoDyyqRCTLg+qG4wqtP4JV9AA+p7/lgqMdD29XyiYdVvIdFrfI9yh7B1QvRvw==", + "version": "0.7.25", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.25.tgz", + "integrity": "sha512-szCTESNJV+Xd56zU6ShOi/JWROxE9IwCic8o5D9z5QECZloas6Ez5tUuKqXTAdu6fHFx1t6C+5gwj8smzOLjtg==", "dev": true, "license": "MIT", "dependencies": { @@ -5811,9 +5984,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", "engines": { @@ -5997,13 +6170,13 @@ } }, "node_modules/ast-v8-to-istanbul": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz", - "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.5.tgz", + "integrity": "sha512-9SdXjNheSiE8bALAQCQQuT6fgQaoxJh7IRYrRGZ8/9nv8WhJeC1aXAwN8TbaOssGOukUvyvnkgD9+Yuykvl1aA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", + "@jridgewell/trace-mapping": "^0.3.30", "estree-walker": "^3.0.3", "js-tokens": "^9.0.1" } @@ -6087,11 +6260,19 @@ } }, "node_modules/b4a": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", - "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.1.tgz", + "integrity": "sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==", "dev": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } }, "node_modules/babel-dead-code-elimination": { "version": "1.0.10", @@ -6160,9 +6341,9 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", - "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", + "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", "dev": true, "license": "Apache-2.0", "optional": true @@ -6188,6 +6369,16 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.2.tgz", + "integrity": "sha512-NvcIedLxrs9llVpX7wI+Jz4Hn9vJQkCPKrTaHIE0sW/Rj1iq6Fzby4NbyTZjQJNoypBXNaG7tEHkTgONZpwgxQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/better-opn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", @@ -6406,9 +6597,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", - "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "version": "4.26.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.0.tgz", + "integrity": "sha512-P9go2WrP9FiPwLv3zqRD/Uoxo0RSHjzFCiQz7d4vbmwNqQFo9T9WCeP/Qn5EbcKQY6DBbkxEXNcpJOmncNrb7A==", "dev": true, "funding": [ { @@ -6426,9 +6617,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", - "node-releases": "^2.0.19", + "baseline-browser-mapping": "^2.8.2", + "caniuse-lite": "^1.0.30001741", + "electron-to-chromium": "^1.5.218", + "node-releases": "^2.0.21", "update-browserslist-db": "^1.1.3" }, "bin": { @@ -6544,9 +6736,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001722", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001722.tgz", - "integrity": "sha512-DCQHBBZtiK6JVkAGw7drvAMK0Q0POD/xZvEmDp6baiMMP6QXXk9HpD6mNYBZWhOPG6LvIDb82ITqtWjhDckHCA==", + "version": "1.0.30001741", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz", + "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==", "dev": true, "funding": [ { @@ -6577,9 +6769,9 @@ } }, "node_modules/chai": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", - "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", "dev": true, "license": "MIT", "dependencies": { @@ -6590,7 +6782,7 @@ "pathval": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/chalk": { @@ -6668,9 +6860,9 @@ } }, "node_modules/cheerio": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.0.tgz", - "integrity": "sha512-+0hMx9eYhJvWbgpKV9hN7jg0JcwydpopZE4hgi+KvQtByZXPp04NiCWU0LzcAbP63abZckIHkTQaXVF52mX3xQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz", + "integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==", "dev": true, "license": "MIT", "dependencies": { @@ -6678,16 +6870,16 @@ "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", - "encoding-sniffer": "^0.2.0", + "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", - "undici": "^7.10.0", + "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">=18.17" + "node": ">=20.18.1" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -6711,16 +6903,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cheerio/node_modules/undici": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.10.0.tgz", - "integrity": "sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } - }, "node_modules/cheerio/node_modules/whatwg-mimetype": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", @@ -6974,7 +7156,8 @@ "node_modules/cookie-es": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", - "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==" + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" }, "node_modules/core-util-is": { "version": "1.0.3", @@ -7049,9 +7232,9 @@ } }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -7066,9 +7249,9 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -7375,9 +7558,9 @@ } }, "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -7405,9 +7588,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.166", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.166.tgz", - "integrity": "sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==", + "version": "1.5.218", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz", + "integrity": "sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==", "dev": true, "license": "ISC" }, @@ -7477,9 +7660,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", - "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7490,31 +7673,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/esbuild-register": { @@ -7582,9 +7766,9 @@ } }, "node_modules/expect-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", - "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -7766,16 +7950,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -7794,9 +7968,9 @@ } }, "node_modules/formatly": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.2.4.tgz", - "integrity": "sha512-lIN7GpcvX/l/i24r/L9bnJ0I8Qn01qijWpQpDDvTLL29nKqSaJJu4h20+7VJ6m2CAhQ2/En/GbxDiHCzq/0MyA==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/formatly/-/formatly-0.3.0.tgz", + "integrity": "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==", "dev": true, "license": "MIT", "dependencies": { @@ -7837,9 +8011,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "dev": true, "license": "MIT", "dependencies": { @@ -8072,16 +8246,6 @@ "node": ">=10.13.0" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -8163,9 +8327,9 @@ } }, "node_modules/graphql-config/node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "license": "MIT", "bin": { @@ -8203,9 +8367,9 @@ } }, "node_modules/graphql-ws": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.5.tgz", - "integrity": "sha512-HzYw057ch0hx2gZjkbgk1pur4kAtgljlWRP+Gccudqm3BRrTpExjWCQ9OHdIsq47Y6lHL++1lTvuQHhgRRcevw==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-6.0.6.tgz", + "integrity": "sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==", "dev": true, "license": "MIT", "engines": { @@ -8259,9 +8423,9 @@ } }, "node_modules/happy-dom/node_modules/@types/node": { - "version": "20.19.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.0.tgz", - "integrity": "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==", + "version": "20.19.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.13.tgz", + "integrity": "sha512-yCAeZl7a0DxgNVteXFHt9+uyFbqXGy/ShC4BlcHkoE0AfGXYv/BUiplV72DjMYXHDBXFjhvr6DD1NiRVfB4j8g==", "dev": true, "license": "MIT", "dependencies": { @@ -8977,9 +9141,10 @@ "license": "MIT" }, "node_modules/isbot": { - "version": "5.1.28", - "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.28.tgz", - "integrity": "sha512-qrOp4g3xj8YNse4biorv6O5ZShwsJM0trsoda4y7j/Su7ZtTTfVXFzbKkpgcSoDrHS8FcTuUwcU04YimZlZOxw==", + "version": "5.1.30", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.30.tgz", + "integrity": "sha512-3wVJEonAns1OETX83uWsk5IAne2S5zfDcntD2hbtU23LelSqNXzXs9zKjMPOLMzroCgIjCfjYAEHrd2D6FOkiA==", + "license": "Unlicense", "engines": { "node": ">=18" } @@ -9042,9 +9207,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9159,9 +9324,9 @@ } }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", "dependencies": { @@ -9172,9 +9337,9 @@ } }, "node_modules/knip": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/knip/-/knip-5.62.0.tgz", - "integrity": "sha512-hfTUVzmrMNMT1khlZfAYmBABeehwWUUrizLQoLamoRhSFkygsGIXWx31kaWKBgEaIVL77T3Uz7IxGvSw+CvQ6A==", + "version": "5.63.1", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.63.1.tgz", + "integrity": "sha512-wSznedUAzcU4o9e0O2WPqDnP7Jttu8cesq/R23eregRY8QYQ9NLJ3aGt9fadJfRzPBoU4tRyutwVQu6chhGDlA==", "dev": true, "funding": [ { @@ -9184,26 +9349,22 @@ { "type": "opencollective", "url": "https://opencollective.com/knip" - }, - { - "type": "polar", - "url": "https://polar.sh/webpro-nl" } ], "license": "ISC", "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", - "formatly": "^0.2.4", - "jiti": "^2.4.2", + "formatly": "^0.3.0", + "jiti": "^2.5.1", "js-yaml": "^4.1.0", "minimist": "^1.2.8", - "oxc-resolver": "^11.1.0", + "oxc-resolver": "^11.6.2", "picocolors": "^1.1.1", "picomatch": "^4.0.1", - "smol-toml": "^1.3.4", + "smol-toml": "^1.4.1", "strip-json-comments": "5.0.2", - "zod": "^3.22.4", + "zod": "^3.25.0", "zod-validation-error": "^3.0.3" }, "bin": { @@ -9219,9 +9380,9 @@ } }, "node_modules/knip/node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "license": "MIT", "bin": { @@ -9402,9 +9563,9 @@ } }, "node_modules/loupe": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz", - "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", "dev": true, "license": "MIT" }, @@ -9450,13 +9611,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/magicast": { @@ -9487,6 +9648,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -9559,9 +9733,9 @@ } }, "node_modules/meros": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.1.tgz", - "integrity": "sha512-eV7dRObfTrckdmAz4/n7pT1njIsIJXRIZkgCiX43xEsPNy4gjXQzOYYxmGcolAMtF7HyfqRuDBh3Lgs4hmhVEw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.2.tgz", + "integrity": "sha512-Q3mobPbvEx7XbwhnC1J1r60+5H6EZyNccdzSz0eGexJRwouUtTZxPVRGdqKtxlpD84ScK4+tIGldkqDtCKdI0A==", "dev": true, "license": "MIT", "engines": { @@ -9786,6 +9960,22 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-postinstall": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz", + "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -9847,9 +10037,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", + "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", "dev": true, "license": "MIT" }, @@ -10002,28 +10192,38 @@ "license": "MIT" }, "node_modules/oxc-resolver": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.2.0.tgz", - "integrity": "sha512-3iJYyIdDZMDoj0ZSVBrI1gUvPBMkDC4gxonBG+7uqUyK5EslG0mCwnf6qhxK8oEU7jLHjbRBNyzflPSd3uvH7Q==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.7.2.tgz", + "integrity": "sha512-abgiTgtJ7FLVPdg5x+rcfoSqz5kpgS/j1Rk/BFNVlLbpAI56VXCj/MM7NyfQb+aVlQDBum0omdz4uFrOYEjNIw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, "funding": { "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-darwin-arm64": "11.2.0", - "@oxc-resolver/binding-darwin-x64": "11.2.0", - "@oxc-resolver/binding-freebsd-x64": "11.2.0", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.2.0", - "@oxc-resolver/binding-linux-arm64-gnu": "11.2.0", - "@oxc-resolver/binding-linux-arm64-musl": "11.2.0", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.2.0", - "@oxc-resolver/binding-linux-s390x-gnu": "11.2.0", - "@oxc-resolver/binding-linux-x64-gnu": "11.2.0", - "@oxc-resolver/binding-linux-x64-musl": "11.2.0", - "@oxc-resolver/binding-wasm32-wasi": "11.2.0", - "@oxc-resolver/binding-win32-arm64-msvc": "11.2.0", - "@oxc-resolver/binding-win32-x64-msvc": "11.2.0" + "@oxc-resolver/binding-android-arm-eabi": "11.7.2", + "@oxc-resolver/binding-android-arm64": "11.7.2", + "@oxc-resolver/binding-darwin-arm64": "11.7.2", + "@oxc-resolver/binding-darwin-x64": "11.7.2", + "@oxc-resolver/binding-freebsd-x64": "11.7.2", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.7.2", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.7.2", + "@oxc-resolver/binding-linux-arm64-gnu": "11.7.2", + "@oxc-resolver/binding-linux-arm64-musl": "11.7.2", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.7.2", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.7.2", + "@oxc-resolver/binding-linux-riscv64-musl": "11.7.2", + "@oxc-resolver/binding-linux-s390x-gnu": "11.7.2", + "@oxc-resolver/binding-linux-x64-gnu": "11.7.2", + "@oxc-resolver/binding-linux-x64-musl": "11.7.2", + "@oxc-resolver/binding-wasm32-wasi": "11.7.2", + "@oxc-resolver/binding-win32-arm64-msvc": "11.7.2", + "@oxc-resolver/binding-win32-ia32-msvc": "11.7.2", + "@oxc-resolver/binding-win32-x64-msvc": "11.7.2" } }, "node_modules/p-limit": { @@ -10254,13 +10454,13 @@ } }, "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/path-is-absolute": { @@ -10369,9 +10569,9 @@ "license": "MIT" }, "node_modules/pathval": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", - "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", "dev": true, "license": "MIT", "engines": { @@ -10611,9 +10811,9 @@ "license": "MIT" }, "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", "bin": { @@ -10786,17 +10986,17 @@ } }, "node_modules/react-docgen": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.0.tgz", - "integrity": "sha512-kmob/FOTwep7DUWf9KjuenKX0vyvChr3oTdvvPt09V60Iz75FJp+T/0ZeHMbAfJj2WaVWqAPP5Hmm3PYzSPPKg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.1.tgz", + "integrity": "sha512-kQKsqPLplY3Hx4jGnM3jpQcG3FQDt7ySz32uTHt3C9HAe45kNXG+3o16Eqn3Fw1GtMfHoN3b4J/z2e6cZJCmqQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.18.9", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", - "@types/babel__core": "^7.18.0", - "@types/babel__traverse": "^7.18.0", + "@babel/core": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@types/babel__core": "^7.20.5", + "@types/babel__traverse": "^7.20.7", "@types/doctrine": "^0.0.9", "@types/resolve": "^1.20.2", "doctrine": "^3.0.0", @@ -10812,6 +11012,7 @@ "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", "dev": true, + "license": "MIT", "peerDependencies": { "typescript": ">= 4.3.x" } @@ -11229,39 +11430,16 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/balanced-match": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz", - "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz", - "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^3.0.0" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/rimraf/node_modules/glob": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", - "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" @@ -11293,9 +11471,9 @@ } }, "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.1.tgz", + "integrity": "sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==", "dev": true, "license": "ISC", "engines": { @@ -11303,13 +11481,13 @@ } }, "node_modules/rimraf/node_modules/minimatch": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.2.tgz", - "integrity": "sha512-+9TJCIYXgZ2Dm5LxVCFsa8jOm+evMwXHFI0JM1XROmkfkpz8/iLLDh+TwSmyIBrs6C6Xu9294/fq8cBA+P6AqA==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^4.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { "node": "20 || >=22" @@ -11336,13 +11514,13 @@ } }, "node_modules/rollup": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", - "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", + "version": "4.50.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz", + "integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -11352,36 +11530,30 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.43.0", - "@rollup/rollup-android-arm64": "4.43.0", - "@rollup/rollup-darwin-arm64": "4.43.0", - "@rollup/rollup-darwin-x64": "4.43.0", - "@rollup/rollup-freebsd-arm64": "4.43.0", - "@rollup/rollup-freebsd-x64": "4.43.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", - "@rollup/rollup-linux-arm-musleabihf": "4.43.0", - "@rollup/rollup-linux-arm64-gnu": "4.43.0", - "@rollup/rollup-linux-arm64-musl": "4.43.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-musl": "4.43.0", - "@rollup/rollup-linux-s390x-gnu": "4.43.0", - "@rollup/rollup-linux-x64-gnu": "4.43.0", - "@rollup/rollup-linux-x64-musl": "4.43.0", - "@rollup/rollup-win32-arm64-msvc": "4.43.0", - "@rollup/rollup-win32-ia32-msvc": "4.43.0", - "@rollup/rollup-win32-x64-msvc": "4.43.0", + "@rollup/rollup-android-arm-eabi": "4.50.1", + "@rollup/rollup-android-arm64": "4.50.1", + "@rollup/rollup-darwin-arm64": "4.50.1", + "@rollup/rollup-darwin-x64": "4.50.1", + "@rollup/rollup-freebsd-arm64": "4.50.1", + "@rollup/rollup-freebsd-x64": "4.50.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.1", + "@rollup/rollup-linux-arm-musleabihf": "4.50.1", + "@rollup/rollup-linux-arm64-gnu": "4.50.1", + "@rollup/rollup-linux-arm64-musl": "4.50.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.1", + "@rollup/rollup-linux-ppc64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-gnu": "4.50.1", + "@rollup/rollup-linux-riscv64-musl": "4.50.1", + "@rollup/rollup-linux-s390x-gnu": "4.50.1", + "@rollup/rollup-linux-x64-gnu": "4.50.1", + "@rollup/rollup-linux-x64-musl": "4.50.1", + "@rollup/rollup-openharmony-arm64": "4.50.1", + "@rollup/rollup-win32-arm64-msvc": "4.50.1", + "@rollup/rollup-win32-ia32-msvc": "4.50.1", + "@rollup/rollup-win32-x64-msvc": "4.50.1", "fsevents": "~2.3.2" } }, - "node_modules/rollup/node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -11478,16 +11650,13 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/sentence-case": { @@ -11506,14 +11675,16 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", "integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==", + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/seroval-plugins": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.2.tgz", - "integrity": "sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.3.3.tgz", + "integrity": "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==", + "license": "MIT", "engines": { "node": ">=10" }, @@ -11624,9 +11795,9 @@ } }, "node_modules/smol-toml": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz", - "integrity": "sha512-UOPtVuYkzYGee0Bd2Szz8d2G3RfMfJ2t3qVdZUAozZyAk+a0Sxa+QKix0YCwjL/A1RR0ar44nCxaoN9FxdJGwA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.4.2.tgz", + "integrity": "sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -11803,6 +11974,19 @@ "storybook": "^9.0.0" } }, + "node_modules/storybook/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/stream-composer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz", @@ -11920,14 +12104,11 @@ } }, "node_modules/strip-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", - "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.0.tgz", + "integrity": "sha512-OA95x+JPmL7kc7zCu+e+TeYxEiaIyndRx0OrBcK2QPPH09oAndr2ALvymxWA+Lx1PYYvFUm4O63pRkdJAaW96w==", "dev": true, "license": "MIT", - "dependencies": { - "min-indent": "^1.0.1" - }, "engines": { "node": ">=12" }, @@ -12028,9 +12209,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.27.1.tgz", - "integrity": "sha512-oGtpYO3lnoaqyGtlJalvryl7TwzgRuxpOVWqEHx8af0YXI+Kt+4jMpLdgMtMcmWmuQ0QTCHLKExwrBFMSxvAUA==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.29.0.tgz", + "integrity": "sha512-gqs7Md3AxP4mbpXAq31o5QW+wGUZsUzVatg70yXpUR245dfIis5jAzufBd+UQM/w2xSfrhvA1eqsrgnl2PbezQ==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" @@ -12373,6 +12554,7 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -12388,22 +12570,22 @@ } }, "node_modules/tldts": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.12.tgz", - "integrity": "sha512-M9ZQBPp6FyqhMcl233vHYyYRkxXOA1SKGlnq13S0mJdUhRSwr2w6I8rlchPL73wBwRlyIZpFvpu2VcdSMWLYXw==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.14.tgz", + "integrity": "sha512-lMNHE4aSI3LlkMUMicTmAG3tkkitjOQGDTFboPJwAg2kJXKP1ryWEyqujktg5qhrFZOkk5YFzgkxg3jErE+i5w==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^7.0.12" + "tldts-core": "^7.0.14" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.12.tgz", - "integrity": "sha512-3K76aXywJFduGRsOYoY5JzINLs/WMlOkeDwPL+8OCPq2Rh39gkSDtWAxdJQlWjpun/xF/LHf29yqCi6VC/rHDA==", + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.14.tgz", + "integrity": "sha512-viZGNK6+NdluOJWwTO9olaugx0bkKhscIdriQQ+lNNhwitIKvb+SvhbYgnCz6j9p7dX3cJntt4agQAKMXLjJ5g==", "dev": true, "license": "MIT" }, @@ -12499,9 +12681,9 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.20.2", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.2.tgz", - "integrity": "sha512-He0ZWr41gLa4vD30Au3yuwpe0HXaCZbclvl8RBieUiJ9aFnPMWUPIyvw3RU8+1Crjfcrauvitae2a4tUzRAGsw==", + "version": "4.20.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz", + "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==", "dev": true, "license": "MIT", "dependencies": { @@ -12546,9 +12728,9 @@ } }, "node_modules/ua-parser-js": { - "version": "1.0.40", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz", - "integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==", + "version": "1.0.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", + "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==", "dev": true, "funding": [ { @@ -12596,6 +12778,16 @@ "node": "*" } }, + "node_modules/undici": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz", + "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", @@ -13360,9 +13552,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", - "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", "engines": { @@ -13409,9 +13601,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", "bin": { @@ -13471,9 +13663,9 @@ } }, "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "dev": true, "license": "MIT", "engines": { @@ -13484,9 +13676,9 @@ } }, "node_modules/zod": { - "version": "3.25.63", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.63.tgz", - "integrity": "sha512-3ttCkqhtpncYXfP0f6dsyabbYV/nEUW+Xlu89jiXbTBifUfjaSqXOG6JnQPLtqt87n7KAmnMqcjay6c0Wq0Vbw==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", "funding": { @@ -13494,16 +13686,16 @@ } }, "node_modules/zod-validation-error": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.0.tgz", - "integrity": "sha512-IWK6O51sRkq0YsnYD2oLDuK2BNsIjYUlR0+1YSd4JyBzm6/892IWroUnLc7oW4FU+b0f6948BHi6H8MDcqpOGw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.3.tgz", + "integrity": "sha512-OT5Y8lbUadqVZCsnyFaTQ4/O2mys4tj7PqhdbBCp7McPwvIEKfPtdA6QfPeFQK2/Rz5LgwmAXRJTugBNBi0btw==", "dev": true, "license": "MIT", "engines": { "node": ">=18.0.0" }, "peerDependencies": { - "zod": "^3.25.0" + "zod": "^3.25.0 || ^4.0.0" } } } diff --git a/frontend/package.json b/frontend/package.json index 18c530891..295e7aa49 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,12 +20,12 @@ "dependencies": { "@fontsource/inconsolata": "^5.2.7", "@fontsource/inter": "^5.2.6", - "@radix-ui/react-collapsible": "^1.1.11", - "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", "@tanstack/react-router": "^1.131.41", "@vector-im/compound-design-tokens": "6.0.0", - "@vector-im/compound-web": "^8.2.0", + "@vector-im/compound-web": "^8.2.4", "@zxcvbn-ts/core": "^3.0.4", "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", @@ -34,7 +34,7 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^15.7.3", - "swagger-ui-dist": "^5.27.1", + "swagger-ui-dist": "^5.29.0", "valibot": "^1.1.0", "vaul": "^1.1.2" }, @@ -65,14 +65,14 @@ "graphql": "^16.11.0", "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", - "knip": "^5.62.0", + "knip": "^5.63.1", "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", "postcss-nesting": "^13.0.2", "rimraf": "^6.0.1", - "storybook": "^9.0.1", + "storybook": "^9.1.5", "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", @@ -80,7 +80,7 @@ "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.6.3", "vite-plugin-manifest-sri": "^0.2.0", - "vitest": "^3.2.3" + "vitest": "^3.2.4" }, "msw": { "workerDirectory": [ From a2172a02baa2c65fe8e531d65ead8ba349372123 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 15 Sep 2025 10:15:59 +0200 Subject: [PATCH 049/296] Surface the user guest flag in the admin API --- crates/data-model/src/users.rs | 2 + crates/handlers/src/admin/model.rs | 7 ++++ .../handlers/src/admin/v1/users/deactivate.rs | 6 ++- crates/handlers/src/rate_limit.rs | 2 + ...05461c3c1f43f966fee3a80ae42540783f08.json} | 10 ++++- ...0f24afb3d6a1925a80a1b6d35b9a8258a0ce.json} | 10 ++++- ...28e8eebd99036255b62d688ac02b5bd74b40.json} | 10 ++++- crates/storage-pg/src/iden.rs | 1 + crates/storage-pg/src/user/mod.rs | 9 +++++ crates/storage-pg/src/user/session.rs | 7 ++++ docs/api/spec.json | 38 +++++++++++++------ 11 files changed, 83 insertions(+), 19 deletions(-) rename crates/storage-pg/.sqlx/{query-d2a4f5c01603463b78198529d295f7f121769ea5730d01c20c0ddbcdc79a5716.json => query-23d5fcd8bf611dc7279bef0d66ce05461c3c1f43f966fee3a80ae42540783f08.json} (74%) rename crates/storage-pg/.sqlx/{query-cc332eda5965715607ffa4eeeacc1b6532cbd8fe49904ccdb1afe315804d348d.json => query-4dad1838536c10ba723adc0fb6da0f24afb3d6a1925a80a1b6d35b9a8258a0ce.json} (75%) rename crates/storage-pg/.sqlx/{query-f924db60febad26c9fff24881b05dd1e1f7ba288d7b2f2f8e30a1ea43e98b8c8.json => query-572ead41d62cfbe40e6f0c8edf6928e8eebd99036255b62d688ac02b5bd74b40.json} (84%) diff --git a/crates/data-model/src/users.rs b/crates/data-model/src/users.rs index 920726ef8..5221f4867 100644 --- a/crates/data-model/src/users.rs +++ b/crates/data-model/src/users.rs @@ -21,6 +21,7 @@ pub struct User { pub locked_at: Option>, pub deactivated_at: Option>, pub can_request_admin: bool, + pub is_guest: bool, } impl User { @@ -43,6 +44,7 @@ impl User { locked_at: None, deactivated_at: None, can_request_admin: false, + is_guest: false, }] } } diff --git a/crates/handlers/src/admin/model.rs b/crates/handlers/src/admin/model.rs index 62065dfe4..2f6648402 100644 --- a/crates/handlers/src/admin/model.rs +++ b/crates/handlers/src/admin/model.rs @@ -52,6 +52,9 @@ pub struct User { /// Whether the user can request admin privileges. admin: bool, + + /// Whether the user was a guest before migrating to MAS, + legacy_guest: bool, } impl User { @@ -65,6 +68,7 @@ impl User { locked_at: None, deactivated_at: None, admin: false, + legacy_guest: false, }, Self { id: Ulid::from_bytes([0x02; 16]), @@ -73,6 +77,7 @@ impl User { locked_at: None, deactivated_at: None, admin: true, + legacy_guest: false, }, Self { id: Ulid::from_bytes([0x03; 16]), @@ -81,6 +86,7 @@ impl User { locked_at: Some(DateTime::default()), deactivated_at: None, admin: false, + legacy_guest: true, }, ] } @@ -95,6 +101,7 @@ impl From for User { locked_at: user.locked_at, deactivated_at: user.deactivated_at, admin: user.can_request_admin, + legacy_guest: user.is_guest, } } } diff --git a/crates/handlers/src/admin/v1/users/deactivate.rs b/crates/handlers/src/admin/v1/users/deactivate.rs index 8a135fadc..b963b73d5 100644 --- a/crates/handlers/src/admin/v1/users/deactivate.rs +++ b/crates/handlers/src/admin/v1/users/deactivate.rs @@ -209,7 +209,8 @@ mod tests { "created_at": "2022-01-16T14:40:00Z", "locked_at": null, "deactivated_at": "2022-01-16T14:40:00Z", - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E" @@ -289,7 +290,8 @@ mod tests { "created_at": "2022-01-16T14:40:00Z", "locked_at": "2022-01-16T14:40:00Z", "deactivated_at": "2022-01-16T14:41:00Z", - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E" diff --git a/crates/handlers/src/rate_limit.rs b/crates/handlers/src/rate_limit.rs index 8b2485941..0471e6351 100644 --- a/crates/handlers/src/rate_limit.rs +++ b/crates/handlers/src/rate_limit.rs @@ -328,6 +328,7 @@ mod tests { locked_at: None, deactivated_at: None, can_request_admin: false, + is_guest: true, }; let bob = User { @@ -338,6 +339,7 @@ mod tests { locked_at: None, deactivated_at: None, can_request_admin: false, + is_guest: true, }; // Three times the same IP address should be allowed diff --git a/crates/storage-pg/.sqlx/query-d2a4f5c01603463b78198529d295f7f121769ea5730d01c20c0ddbcdc79a5716.json b/crates/storage-pg/.sqlx/query-23d5fcd8bf611dc7279bef0d66ce05461c3c1f43f966fee3a80ae42540783f08.json similarity index 74% rename from crates/storage-pg/.sqlx/query-d2a4f5c01603463b78198529d295f7f121769ea5730d01c20c0ddbcdc79a5716.json rename to crates/storage-pg/.sqlx/query-23d5fcd8bf611dc7279bef0d66ce05461c3c1f43f966fee3a80ae42540783f08.json index 171a83623..28391d844 100644 --- a/crates/storage-pg/.sqlx/query-d2a4f5c01603463b78198529d295f7f121769ea5730d01c20c0ddbcdc79a5716.json +++ b/crates/storage-pg/.sqlx/query-23d5fcd8bf611dc7279bef0d66ce05461c3c1f43f966fee3a80ae42540783f08.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT user_id\n , username\n , created_at\n , locked_at\n , deactivated_at\n , can_request_admin\n FROM users\n WHERE LOWER(username) = LOWER($1)\n ", + "query": "\n SELECT user_id\n , username\n , created_at\n , locked_at\n , deactivated_at\n , can_request_admin\n , is_guest\n FROM users\n WHERE LOWER(username) = LOWER($1)\n ", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "ordinal": 5, "name": "can_request_admin", "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "is_guest", + "type_info": "Bool" } ], "parameters": { @@ -45,8 +50,9 @@ false, true, true, + false, false ] }, - "hash": "d2a4f5c01603463b78198529d295f7f121769ea5730d01c20c0ddbcdc79a5716" + "hash": "23d5fcd8bf611dc7279bef0d66ce05461c3c1f43f966fee3a80ae42540783f08" } diff --git a/crates/storage-pg/.sqlx/query-cc332eda5965715607ffa4eeeacc1b6532cbd8fe49904ccdb1afe315804d348d.json b/crates/storage-pg/.sqlx/query-4dad1838536c10ba723adc0fb6da0f24afb3d6a1925a80a1b6d35b9a8258a0ce.json similarity index 75% rename from crates/storage-pg/.sqlx/query-cc332eda5965715607ffa4eeeacc1b6532cbd8fe49904ccdb1afe315804d348d.json rename to crates/storage-pg/.sqlx/query-4dad1838536c10ba723adc0fb6da0f24afb3d6a1925a80a1b6d35b9a8258a0ce.json index 6603fa37d..6c8cdbe88 100644 --- a/crates/storage-pg/.sqlx/query-cc332eda5965715607ffa4eeeacc1b6532cbd8fe49904ccdb1afe315804d348d.json +++ b/crates/storage-pg/.sqlx/query-4dad1838536c10ba723adc0fb6da0f24afb3d6a1925a80a1b6d35b9a8258a0ce.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT user_id\n , username\n , created_at\n , locked_at\n , deactivated_at\n , can_request_admin\n FROM users\n WHERE user_id = $1\n ", + "query": "\n SELECT user_id\n , username\n , created_at\n , locked_at\n , deactivated_at\n , can_request_admin\n , is_guest\n FROM users\n WHERE user_id = $1\n ", "describe": { "columns": [ { @@ -32,6 +32,11 @@ "ordinal": 5, "name": "can_request_admin", "type_info": "Bool" + }, + { + "ordinal": 6, + "name": "is_guest", + "type_info": "Bool" } ], "parameters": { @@ -45,8 +50,9 @@ false, true, true, + false, false ] }, - "hash": "cc332eda5965715607ffa4eeeacc1b6532cbd8fe49904ccdb1afe315804d348d" + "hash": "4dad1838536c10ba723adc0fb6da0f24afb3d6a1925a80a1b6d35b9a8258a0ce" } diff --git a/crates/storage-pg/.sqlx/query-f924db60febad26c9fff24881b05dd1e1f7ba288d7b2f2f8e30a1ea43e98b8c8.json b/crates/storage-pg/.sqlx/query-572ead41d62cfbe40e6f0c8edf6928e8eebd99036255b62d688ac02b5bd74b40.json similarity index 84% rename from crates/storage-pg/.sqlx/query-f924db60febad26c9fff24881b05dd1e1f7ba288d7b2f2f8e30a1ea43e98b8c8.json rename to crates/storage-pg/.sqlx/query-572ead41d62cfbe40e6f0c8edf6928e8eebd99036255b62d688ac02b5bd74b40.json index 1ddb0acc8..155277181 100644 --- a/crates/storage-pg/.sqlx/query-f924db60febad26c9fff24881b05dd1e1f7ba288d7b2f2f8e30a1ea43e98b8c8.json +++ b/crates/storage-pg/.sqlx/query-572ead41d62cfbe40e6f0c8edf6928e8eebd99036255b62d688ac02b5bd74b40.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT s.user_session_id\n , s.created_at AS \"user_session_created_at\"\n , s.finished_at AS \"user_session_finished_at\"\n , s.user_agent AS \"user_session_user_agent\"\n , s.last_active_at AS \"user_session_last_active_at\"\n , s.last_active_ip AS \"user_session_last_active_ip: IpAddr\"\n , u.user_id\n , u.username AS \"user_username\"\n , u.created_at AS \"user_created_at\"\n , u.locked_at AS \"user_locked_at\"\n , u.deactivated_at AS \"user_deactivated_at\"\n , u.can_request_admin AS \"user_can_request_admin\"\n FROM user_sessions s\n INNER JOIN users u\n USING (user_id)\n WHERE s.user_session_id = $1\n ", + "query": "\n SELECT s.user_session_id\n , s.created_at AS \"user_session_created_at\"\n , s.finished_at AS \"user_session_finished_at\"\n , s.user_agent AS \"user_session_user_agent\"\n , s.last_active_at AS \"user_session_last_active_at\"\n , s.last_active_ip AS \"user_session_last_active_ip: IpAddr\"\n , u.user_id\n , u.username AS \"user_username\"\n , u.created_at AS \"user_created_at\"\n , u.locked_at AS \"user_locked_at\"\n , u.deactivated_at AS \"user_deactivated_at\"\n , u.can_request_admin AS \"user_can_request_admin\"\n , u.is_guest AS \"user_is_guest\"\n FROM user_sessions s\n INNER JOIN users u\n USING (user_id)\n WHERE s.user_session_id = $1\n ", "describe": { "columns": [ { @@ -62,6 +62,11 @@ "ordinal": 11, "name": "user_can_request_admin", "type_info": "Bool" + }, + { + "ordinal": 12, + "name": "user_is_guest", + "type_info": "Bool" } ], "parameters": { @@ -81,8 +86,9 @@ false, true, true, + false, false ] }, - "hash": "f924db60febad26c9fff24881b05dd1e1f7ba288d7b2f2f8e30a1ea43e98b8c8" + "hash": "572ead41d62cfbe40e6f0c8edf6928e8eebd99036255b62d688ac02b5bd74b40" } diff --git a/crates/storage-pg/src/iden.rs b/crates/storage-pg/src/iden.rs index e6c03acc4..a861f59c7 100644 --- a/crates/storage-pg/src/iden.rs +++ b/crates/storage-pg/src/iden.rs @@ -39,6 +39,7 @@ pub enum Users { LockedAt, DeactivatedAt, CanRequestAdmin, + IsGuest, } #[derive(sea_query::Iden)] diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index 8af61b61c..c88c60d3d 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -73,6 +73,7 @@ mod priv_ { pub(super) locked_at: Option>, pub(super) deactivated_at: Option>, pub(super) can_request_admin: bool, + pub(super) is_guest: bool, } } @@ -89,6 +90,7 @@ impl From for User { locked_at: value.locked_at, deactivated_at: value.deactivated_at, can_request_admin: value.can_request_admin, + is_guest: value.is_guest, } } } @@ -140,6 +142,7 @@ impl UserRepository for PgUserRepository<'_> { , locked_at , deactivated_at , can_request_admin + , is_guest FROM users WHERE user_id = $1 "#, @@ -176,6 +179,7 @@ impl UserRepository for PgUserRepository<'_> { , locked_at , deactivated_at , can_request_admin + , is_guest FROM users WHERE LOWER(username) = LOWER($1) "#, @@ -249,6 +253,7 @@ impl UserRepository for PgUserRepository<'_> { locked_at: None, deactivated_at: None, can_request_admin: false, + is_guest: false, }) } @@ -487,6 +492,10 @@ impl UserRepository for PgUserRepository<'_> { Expr::col((Users::Table, Users::CanRequestAdmin)), UserLookupIden::CanRequestAdmin, ) + .expr_as( + Expr::col((Users::Table, Users::IsGuest)), + UserLookupIden::IsGuest, + ) .from(Users::Table) .apply_filter(filter) .generate_pagination((Users::Table, Users::UserId), pagination) diff --git a/crates/storage-pg/src/user/session.rs b/crates/storage-pg/src/user/session.rs index a8c5ab458..54645b3cb 100644 --- a/crates/storage-pg/src/user/session.rs +++ b/crates/storage-pg/src/user/session.rs @@ -61,6 +61,7 @@ struct SessionLookup { user_locked_at: Option>, user_deactivated_at: Option>, user_can_request_admin: bool, + user_is_guest: bool, } impl TryFrom for BrowserSession { @@ -76,6 +77,7 @@ impl TryFrom for BrowserSession { locked_at: value.user_locked_at, deactivated_at: value.user_deactivated_at, can_request_admin: value.user_can_request_admin, + is_guest: value.user_is_guest, }; Ok(BrowserSession { @@ -201,6 +203,7 @@ impl BrowserSessionRepository for PgBrowserSessionRepository<'_> { , u.locked_at AS "user_locked_at" , u.deactivated_at AS "user_deactivated_at" , u.can_request_admin AS "user_can_request_admin" + , u.is_guest AS "user_is_guest" FROM user_sessions s INNER JOIN users u USING (user_id) @@ -391,6 +394,10 @@ impl BrowserSessionRepository for PgBrowserSessionRepository<'_> { Expr::col((Users::Table, Users::CanRequestAdmin)), SessionLookupIden::UserCanRequestAdmin, ) + .expr_as( + Expr::col((Users::Table, Users::IsGuest)), + SessionLookupIden::UserIsGuest, + ) .from(UserSessions::Table) .inner_join( Users::Table, diff --git a/docs/api/spec.json b/docs/api/spec.json index ab8e7f2ec..37ad58e05 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -937,7 +937,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -951,7 +952,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": true + "admin": true, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/02081040G2081040G2081040G2" @@ -965,7 +967,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": "1970-01-01T00:00:00Z", "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": true }, "links": { "self": "/api/admin/v1/users/030C1G60R30C1G60R30C1G60R3" @@ -1017,7 +1020,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -1103,7 +1107,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -1260,7 +1265,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -1340,7 +1346,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": true + "admin": true, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/02081040G2081040G2081040G2" @@ -1419,7 +1426,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": "1970-01-01T00:00:00Z", "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": true }, "links": { "self": "/api/admin/v1/users/030C1G60R30C1G60R30C1G60R3" @@ -1489,7 +1497,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -1559,7 +1568,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": "1970-01-01T00:00:00Z", "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": true }, "links": { "self": "/api/admin/v1/users/030C1G60R30C1G60R30C1G60R3" @@ -1629,7 +1639,8 @@ "created_at": "1970-01-01T00:00:00Z", "locked_at": null, "deactivated_at": null, - "admin": false + "admin": false, + "legacy_guest": false }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" @@ -3941,6 +3952,7 @@ "required": [ "admin", "created_at", + "legacy_guest", "username" ], "properties": { @@ -3968,6 +3980,10 @@ "admin": { "description": "Whether the user can request admin privileges.", "type": "boolean" + }, + "legacy_guest": { + "description": "Whether the user was a guest before migrating to MAS,", + "type": "boolean" } } }, From b7015c0b3d79195225f633e58acc27dbb649588f Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 15 Sep 2025 10:37:34 +0200 Subject: [PATCH 050/296] Allow filtering guest/non-guest users --- crates/handlers/src/admin/v1/users/list.rs | 14 +++++++++++++ crates/storage-pg/src/user/mod.rs | 4 ++++ crates/storage/src/user/mod.rs | 23 ++++++++++++++++++++++ docs/api/spec.json | 16 +++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/crates/handlers/src/admin/v1/users/list.rs b/crates/handlers/src/admin/v1/users/list.rs index 021e39f37..17b652c82 100644 --- a/crates/handlers/src/admin/v1/users/list.rs +++ b/crates/handlers/src/admin/v1/users/list.rs @@ -54,6 +54,10 @@ pub struct FilterParams { #[serde(rename = "filter[admin]")] admin: Option, + /// Retrieve users with (or without) the `legacy_guest` flag set + #[serde(rename = "filter[legacy-guest]")] + legacy_guest: Option, + /// Retrieve the items with the given status /// /// Defaults to retrieve all users, including locked ones. @@ -75,6 +79,10 @@ impl std::fmt::Display for FilterParams { write!(f, "{sep}filter[admin]={admin}")?; sep = '&'; } + if let Some(legacy_guest) = self.legacy_guest { + write!(f, "{sep}filter[legacy-guest]={legacy_guest}")?; + sep = '&'; + } if let Some(status) = self.status { write!(f, "{sep}filter[status]={status}")?; sep = '&'; @@ -143,6 +151,12 @@ pub async fn handler( None => filter, }; + let filter = match params.legacy_guest { + Some(true) => filter.guest_only(), + Some(false) => filter.non_guest_only(), + None => filter, + }; + let filter = match params.status { Some(UserStatus::Active) => filter.active_only(), Some(UserStatus::Locked) => filter.locked_only(), diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index c88c60d3d..1af09a455 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -116,6 +116,10 @@ impl Filter for UserFilter<'_> { .add_option(self.can_request_admin().map(|can_request_admin| { Expr::col((Users::Table, Users::CanRequestAdmin)).eq(can_request_admin) })) + .add_option( + self.is_guest() + .map(|is_guest| Expr::col((Users::Table, Users::IsGuest)).eq(is_guest)), + ) } } diff --git a/crates/storage/src/user/mod.rs b/crates/storage/src/user/mod.rs index 0294d83b4..8a5949e81 100644 --- a/crates/storage/src/user/mod.rs +++ b/crates/storage/src/user/mod.rs @@ -75,6 +75,7 @@ impl UserState { pub struct UserFilter<'a> { state: Option, can_request_admin: Option, + is_guest: Option, _phantom: std::marker::PhantomData<&'a ()>, } @@ -120,6 +121,20 @@ impl UserFilter<'_> { self } + /// Filter for guest users + #[must_use] + pub fn guest_only(mut self) -> Self { + self.is_guest = Some(true); + self + } + + /// Filter for non-guest users + #[must_use] + pub fn non_guest_only(mut self) -> Self { + self.is_guest = Some(false); + self + } + /// Get the state filter /// /// Returns [`None`] if no state filter was set @@ -135,6 +150,14 @@ impl UserFilter<'_> { pub fn can_request_admin(&self) -> Option { self.can_request_admin } + + /// Get the is guest filter + /// + /// Returns [`None`] if no is guest filter was set + #[must_use] + pub fn is_guest(&self) -> Option { + self.is_guest + } } /// A [`UserRepository`] helps interacting with [`User`] saved in the storage diff --git a/docs/api/spec.json b/docs/api/spec.json index 37ad58e05..0e8acdded 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -904,6 +904,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "filter[legacy-guest]", + "description": "Retrieve users with (or without) the `legacy_guest` flag set", + "schema": { + "description": "Retrieve users with (or without) the `legacy_guest` flag set", + "type": "boolean", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[status]", @@ -3877,6 +3888,11 @@ "type": "boolean", "nullable": true }, + "filter[legacy-guest]": { + "description": "Retrieve users with (or without) the `legacy_guest` flag set", + "type": "boolean", + "nullable": true + }, "filter[status]": { "description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users (includes deactivated users)\n\n* `deactivated`: Only retrieve deactivated users", "$ref": "#/components/schemas/UserStatus", From cb8c40848955ff748cbd7d24cb3a02d06aa0a36e Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 15 Sep 2025 12:37:48 +0200 Subject: [PATCH 051/296] Admin API filter to search users by username --- crates/handlers/src/admin/v1/users/list.rs | 16 ++++++++++++++++ .../20250915092000_pgtrgm_extension.sql | 10 ++++++++++ ...20250915092635_users_username_trgm_idx.sql | 10 ++++++++++ crates/storage-pg/src/user/mod.rs | 5 ++++- crates/storage-pg/src/user/tests.rs | 13 +++++++++++++ crates/storage/src/user/mod.rs | 19 +++++++++++++++++-- docs/api/spec.json | 16 ++++++++++++++++ 7 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 crates/storage-pg/migrations/20250915092000_pgtrgm_extension.sql create mode 100644 crates/storage-pg/migrations/20250915092635_users_username_trgm_idx.sql diff --git a/crates/handlers/src/admin/v1/users/list.rs b/crates/handlers/src/admin/v1/users/list.rs index 17b652c82..da70e5807 100644 --- a/crates/handlers/src/admin/v1/users/list.rs +++ b/crates/handlers/src/admin/v1/users/list.rs @@ -58,6 +58,13 @@ pub struct FilterParams { #[serde(rename = "filter[legacy-guest]")] legacy_guest: Option, + /// Retrieve users where the username matches contains the given string + /// + /// Note that this doesn't change the ordering of the result, which are + /// still ordered by ID. + #[serde(rename = "filter[search]")] + search: Option, + /// Retrieve the items with the given status /// /// Defaults to retrieve all users, including locked ones. @@ -83,6 +90,10 @@ impl std::fmt::Display for FilterParams { write!(f, "{sep}filter[legacy-guest]={legacy_guest}")?; sep = '&'; } + if let Some(search) = &self.search { + write!(f, "{sep}filter[search]={search}")?; + sep = '&'; + } if let Some(status) = self.status { write!(f, "{sep}filter[status]={status}")?; sep = '&'; @@ -157,6 +168,11 @@ pub async fn handler( None => filter, }; + let filter = match params.search.as_deref() { + Some(search) => filter.matching_search(search), + None => filter, + }; + let filter = match params.status { Some(UserStatus::Active) => filter.active_only(), Some(UserStatus::Locked) => filter.locked_only(), diff --git a/crates/storage-pg/migrations/20250915092000_pgtrgm_extension.sql b/crates/storage-pg/migrations/20250915092000_pgtrgm_extension.sql new file mode 100644 index 000000000..2ebc26d25 --- /dev/null +++ b/crates/storage-pg/migrations/20250915092000_pgtrgm_extension.sql @@ -0,0 +1,10 @@ +-- no-transaction +-- Copyright 2025 New Vector Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE in the repository root for full details. + +-- This enables the pg_trgm extension, which is used for search filters +-- Starting Posgres 16, this extension is marked as "trusted", meaning it can be +-- installed by non-superusers +CREATE EXTENSION IF NOT EXISTS pg_trgm; diff --git a/crates/storage-pg/migrations/20250915092635_users_username_trgm_idx.sql b/crates/storage-pg/migrations/20250915092635_users_username_trgm_idx.sql new file mode 100644 index 000000000..5f007d750 --- /dev/null +++ b/crates/storage-pg/migrations/20250915092635_users_username_trgm_idx.sql @@ -0,0 +1,10 @@ +-- no-transaction +-- Copyright 2025 New Vector Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE in the repository root for full details. + +-- This adds an index on the username field for ILIKE '%search%' operations, +-- enabling fuzzy searches of usernames +CREATE INDEX CONCURRENTLY users_username_trgm_idx + ON users USING gin(username gin_trgm_ops); diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index 1af09a455..0be594556 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -11,7 +11,7 @@ use async_trait::async_trait; use mas_data_model::{Clock, User}; use mas_storage::user::{UserFilter, UserRepository}; use rand::RngCore; -use sea_query::{Expr, PostgresQueryBuilder, Query}; +use sea_query::{Expr, PostgresQueryBuilder, Query, extension::postgres::PgExpr as _}; use sea_query_binder::SqlxBinder; use sqlx::PgConnection; use ulid::Ulid; @@ -120,6 +120,9 @@ impl Filter for UserFilter<'_> { self.is_guest() .map(|is_guest| Expr::col((Users::Table, Users::IsGuest)).eq(is_guest)), ) + .add_option(self.search().map(|search| { + Expr::col((Users::Table, Users::Username)).ilike(format!("%{search}%")) + })) } } diff --git a/crates/storage-pg/src/user/tests.rs b/crates/storage-pg/src/user/tests.rs index 0880c1032..0ee978914 100644 --- a/crates/storage-pg/src/user/tests.rs +++ b/crates/storage-pg/src/user/tests.rs @@ -174,6 +174,19 @@ async fn test_user_repo(pool: PgPool) { assert_eq!(repo.user().count(locked).await.unwrap(), 0); assert_eq!(repo.user().count(deactivated).await.unwrap(), 1); + // Test the search filter + assert_eq!( + repo.user() + .count(all.matching_search("alice")) + .await + .unwrap(), + 0 + ); + assert_eq!( + repo.user().count(all.matching_search("JO")).await.unwrap(), + 1 + ); + // Check the list method let list = repo.user().list(all, Pagination::first(10)).await.unwrap(); assert_eq!(list.edges.len(), 1); diff --git a/crates/storage/src/user/mod.rs b/crates/storage/src/user/mod.rs index 8a5949e81..657909ef4 100644 --- a/crates/storage/src/user/mod.rs +++ b/crates/storage/src/user/mod.rs @@ -76,10 +76,10 @@ pub struct UserFilter<'a> { state: Option, can_request_admin: Option, is_guest: Option, - _phantom: std::marker::PhantomData<&'a ()>, + search: Option<&'a str>, } -impl UserFilter<'_> { +impl<'a> UserFilter<'a> { /// Create a new [`UserFilter`] with default values #[must_use] pub fn new() -> Self { @@ -135,6 +135,13 @@ impl UserFilter<'_> { self } + /// Filter for users that match the given search string + #[must_use] + pub fn matching_search(mut self, search: &'a str) -> Self { + self.search = Some(search); + self + } + /// Get the state filter /// /// Returns [`None`] if no state filter was set @@ -158,6 +165,14 @@ impl UserFilter<'_> { pub fn is_guest(&self) -> Option { self.is_guest } + + /// Get the search filter + /// + /// Returns [`None`] if no search filter was set + #[must_use] + pub fn search(&self) -> Option<&'a str> { + self.search + } } /// A [`UserRepository`] helps interacting with [`User`] saved in the storage diff --git a/docs/api/spec.json b/docs/api/spec.json index 0e8acdded..3348cf722 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -915,6 +915,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "filter[search]", + "description": "Retrieve users where the username matches contains the given string\n\nNote that this doesn't change the ordering of the result, which are still ordered by ID.", + "schema": { + "description": "Retrieve users where the username matches contains the given string\n\nNote that this doesn't change the ordering of the result, which are still ordered by ID.", + "type": "string", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[status]", @@ -3893,6 +3904,11 @@ "type": "boolean", "nullable": true }, + "filter[search]": { + "description": "Retrieve users where the username matches contains the given string\n\nNote that this doesn't change the ordering of the result, which are still ordered by ID.", + "type": "string", + "nullable": true + }, "filter[status]": { "description": "Retrieve the items with the given status\n\nDefaults to retrieve all users, including locked ones.\n\n* `active`: Only retrieve active users\n\n* `locked`: Only retrieve locked users (includes deactivated users)\n\n* `deactivated`: Only retrieve deactivated users", "$ref": "#/components/schemas/UserStatus", From ec4e0ced6b20bbfdbc9f52465b013da109a1fab2 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Mon, 15 Sep 2025 14:27:17 +0100 Subject: [PATCH 052/296] Add references to MSC for account management account= query param So that we know where these values have come from and when they can be removed. --- frontend/src/routes/_account.index.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/src/routes/_account.index.tsx b/frontend/src/routes/_account.index.tsx index 4b21b326c..a4cdc2aa0 100644 --- a/frontend/src/routes/_account.index.tsx +++ b/frontend/src/routes/_account.index.tsx @@ -93,16 +93,16 @@ export const Route = createFileRoute({ beforeLoad({ search }) { switch (search.action) { - case "profile": - case "org.matrix.profile": + case "profile": // This is an unspecced alias for org.matrix.profile that can be removed + case "org.matrix.profile": // This is from unstable MSC4191 throw redirect({ to: "/", search: {} }); - case "sessions_list": - case "org.matrix.sessions_list": + case "sessions_list": // This is an unspecced alias for org.matrix.sessions_list that can be removed + case "org.matrix.sessions_list": // This is from unstable MSC4191 throw redirect({ to: "/sessions" }); - case "session_view": - case "org.matrix.session_view": + case "session_view": // This is an unspecced alias for org.matrix.session_view that can be removed + case "org.matrix.session_view": // This is from unstable MSC4191 if (search.device_id) throw redirect({ to: "/devices/$", @@ -110,8 +110,8 @@ export const Route = createFileRoute({ }); throw redirect({ to: "/sessions" }); - case "session_end": - case "org.matrix.session_end": + case "session_end": // This is the unstable MSC3824 alias for org.matrix.session_end + case "org.matrix.session_end": // This is from unstable MSC4191 if (search.device_id) throw redirect({ to: "/devices/$", @@ -119,12 +119,13 @@ export const Route = createFileRoute({ }); throw redirect({ to: "/sessions" }); - case "org.matrix.cross_signing_reset": + case "org.matrix.cross_signing_reset": // This is from unstable MSC4191 throw redirect({ to: "/reset-cross-signing", search: { deepLink: true }, }); case "org.matrix.plan_management": { + // This is an unspecced experimental value // We don't both checking if the plan management iframe is actually available and // instead rely on the plan tab handling it. throw redirect({ to: "/plan" }); From 020e6647b48b15667adb9d632da9f441bc27bdb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 13:33:26 +0000 Subject: [PATCH 053/296] build(deps): bump sigstore/cosign-installer from 3.9.2 to 3.10.0 Bumps [sigstore/cosign-installer](https://github.com/sigstore/cosign-installer) from 3.9.2 to 3.10.0. - [Release notes](https://github.com/sigstore/cosign-installer/releases) - [Commits](https://github.com/sigstore/cosign-installer/compare/v3.9.2...v3.10.0) --- updated-dependencies: - dependency-name: sigstore/cosign-installer dependency-version: 3.10.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 4ee4ca9f2..e51df6f56 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -258,7 +258,7 @@ jobs: type=sha - name: Setup Cosign - uses: sigstore/cosign-installer@v3.9.2 + uses: sigstore/cosign-installer@v3.10.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3.11.1 From ce86038ac257e31d9852e0a4b08121f1d6b56fa7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:10:05 +0000 Subject: [PATCH 054/296] build(deps-dev): bump the storybook group in /frontend with 3 updates Bumps the storybook group in /frontend with 3 updates: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite) and [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core). Updates `@storybook/addon-docs` from 9.1.5 to 9.1.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.6/code/addons/docs) Updates `@storybook/react-vite` from 9.1.5 to 9.1.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.6/code/frameworks/react-vite) Updates `storybook` from 9.1.5 to 9.1.6 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.6/code/core) --- updated-dependencies: - dependency-name: "@storybook/addon-docs" dependency-version: 9.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/react-vite" dependency-version: 9.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-version: 9.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 70 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dabbd635d..18b3d8c3a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,8 +36,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.5", - "@storybook/react-vite": "^9.1.5", + "@storybook/addon-docs": "^9.1.6", + "@storybook/react-vite": "^9.1.6", "@tanstack/react-query-devtools": "^5.87.4", "@tanstack/react-router-devtools": "^1.131.42", "@tanstack/router-plugin": "^1.131.41", @@ -4884,16 +4884,16 @@ "license": "Apache-2.0" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.5.tgz", - "integrity": "sha512-q1j5RRElxFSnHOh60eS3dS2TAyAHzcQeH/2B9UXo6MUHu7HmhNpw3qt2YibIw0zEogHCvZhLNx6TNzSy+7wRUw==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.6.tgz", + "integrity": "sha512-4ZE/T2Ayw77/v2ersAk/VM7vlvqV2zCNFwt0uvOzUR1VZ9VqZCHhsfy/IyBPeKt6Otax3EpfE1LkH4slfceB0g==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.5", + "@storybook/csf-plugin": "9.1.6", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.5", + "@storybook/react-dom-shim": "9.1.6", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -4903,17 +4903,17 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.5" + "storybook": "^9.1.6" } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.5.tgz", - "integrity": "sha512-sgt/9+Yl/5O7Bj5hdbHfadN8e/e4CNiDZKDcbLOMpOjKKoqF8vm19I1QocWIAiKjTOhF+4E9v9LddjtAGnfqHQ==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.6.tgz", + "integrity": "sha512-AUoSjXr4MvtkFQkfFfZSXrqVM0z80DX0sebm80nODu/qFhsJIU5trNP+XDYY8ClODERXd5QSZJyOyH9nOz60SA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.5", + "@storybook/csf-plugin": "9.1.6", "ts-dedent": "^2.0.0" }, "funding": { @@ -4921,14 +4921,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.5", + "storybook": "^9.1.6", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.5.tgz", - "integrity": "sha512-PmHuF+j11Z7BxAI2/4wQYn0gH1d67gNvycyR+EWgp4P/AWam9wFbuI/T1R45CRQTV2/VrfGdts/tFrvo5kXWig==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.6.tgz", + "integrity": "sha512-cz4Y+OYCtuovFNwoLkIKk0T62clrRTYf26Bbo1gdIGuX/W3JPP/LnN97sP2/0nfF6heZqCdEwb47k7RubkxXZg==", "dev": true, "license": "MIT", "dependencies": { @@ -4939,7 +4939,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.5" + "storybook": "^9.1.6" } }, "node_modules/@storybook/global": { @@ -4964,14 +4964,14 @@ } }, "node_modules/@storybook/react": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.5.tgz", - "integrity": "sha512-fBVP7Go09gzpImtaMcZ2DipLEWdWeTmz7BrACr3Z8uCyKcoH8/d1Wv0JgIiBo1UKDh5ZgYx5pLafaPNqmVAepg==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.6.tgz", + "integrity": "sha512-BGf3MQaXj6LmYnYpSwHUoWH0RP6kaqBoPc2u5opSU2ajw34enIL5w2sFaXzL+k2ap0aHnCYYlyBINBBvtD6NIA==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "9.1.5" + "@storybook/react-dom-shim": "9.1.6" }, "engines": { "node": ">=20.0.0" @@ -4983,7 +4983,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.5", + "storybook": "^9.1.6", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -4993,9 +4993,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.5.tgz", - "integrity": "sha512-blSq9uzSYnfgEYPHYKgM5O14n8hbXNiXx2GiVJyDSg8QPNicbsBg+lCb1TC7/USfV26pNZr/lGNNKGkcCEN6Gw==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.6.tgz", + "integrity": "sha512-Px4duzPMTPqI3kes6eUyYjWpEeJ0AOCCeSDCBDm9rzlf4a+eXlxfhkcVWft3viCDiIkc0vtYagb2Yu7bcSIypg==", "dev": true, "license": "MIT", "funding": { @@ -5005,20 +5005,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.5" + "storybook": "^9.1.6" } }, "node_modules/@storybook/react-vite": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.5.tgz", - "integrity": "sha512-OYbkHHNCrn8MNPd+4KxMjcSR4M/YHa84h8sWDUHhKRTRtZFmj8i/QDW3E8tGx2BRLxXw3dTYe9J5UYBhJDDxFA==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.6.tgz", + "integrity": "sha512-YNKQZcz5Vtv8OdHUJ65Wx4PbfZMrPPbtL+OYAR0We+EEoTDofi3VogXyOUw99Jppp1HIq5IiDF5qyZPEpC5k0A==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "9.1.5", - "@storybook/react": "9.1.5", + "@storybook/builder-vite": "9.1.6", + "@storybook/react": "9.1.6", "find-up": "^7.0.0", "magic-string": "^0.30.0", "react-docgen": "^8.0.0", @@ -5035,7 +5035,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.5", + "storybook": "^9.1.6", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -11908,9 +11908,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.5.tgz", - "integrity": "sha512-cGwJ2AE6nxlwqQlOiI+HKX5qa7+FOV7Ha7Qa+GoASBIQSSnLfbY6UldgAxHCJGJOFtgW/wuqfDtNvni6sj1/OQ==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.6.tgz", + "integrity": "sha512-iIcMaDKkjR5nN+JYBy9hhoxZhjX4TXhyJgUBed+toJOlfrl+QvxpBjImAi7qKyLR3hng3uoigEP0P8+vYtXpOg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 295e7aa49..9e34afca9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,8 +46,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.5", - "@storybook/react-vite": "^9.1.5", + "@storybook/addon-docs": "^9.1.6", + "@storybook/react-vite": "^9.1.6", "@tanstack/react-query-devtools": "^5.87.4", "@tanstack/react-router-devtools": "^1.131.42", "@tanstack/router-plugin": "^1.131.41", From 9789fa3385577ccb7d2544479fe354219d5d9a4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:11:54 +0000 Subject: [PATCH 055/296] build(deps): bump @fontsource/inter in /frontend in the fontsource group Bumps the fontsource group in /frontend with 1 update: [@fontsource/inter](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/inter). Updates `@fontsource/inter` from 5.2.6 to 5.2.7 - [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md) - [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/inter) --- updated-dependencies: - dependency-name: "@fontsource/inter" dependency-version: 5.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fontsource ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dabbd635d..c09dfb102 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@fontsource/inconsolata": "^5.2.7", - "@fontsource/inter": "^5.2.6", + "@fontsource/inter": "^5.2.7", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", @@ -1871,9 +1871,9 @@ } }, "node_modules/@fontsource/inter": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.6.tgz", - "integrity": "sha512-CZs9S1CrjD0jPwsNy9W6j0BhsmRSQrgwlTNkgQXTsAeDRM42LBRLo3eo9gCzfH4GvV7zpyf78Ozfl773826csw==", + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.7.tgz", + "integrity": "sha512-sfE4VQglV9B05DuJ+RD2RHY42FiVTdCf/dJtVkugRVkygoDigLM4SuNcBrCeo+zoGiC/IudmVcE6QKqW7S1Gkg==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" diff --git a/frontend/package.json b/frontend/package.json index 295e7aa49..2982d2e7d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@fontsource/inconsolata": "^5.2.7", - "@fontsource/inter": "^5.2.6", + "@fontsource/inter": "^5.2.7", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", From 71a19bd389b358197670a06cbcfd9c0c29202ef8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:12:25 +0000 Subject: [PATCH 056/296] build(deps): bump the tanstack-router group in /frontend with 3 updates Bumps the tanstack-router group in /frontend with 3 updates: [@tanstack/react-router](https://github.com/TanStack/router/tree/HEAD/packages/react-router), [@tanstack/react-router-devtools](https://github.com/TanStack/router/tree/HEAD/packages/react-router-devtools) and [@tanstack/router-plugin](https://github.com/TanStack/router/tree/HEAD/packages/router-plugin). Updates `@tanstack/react-router` from 1.131.41 to 1.131.44 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.44/packages/react-router) Updates `@tanstack/react-router-devtools` from 1.131.42 to 1.131.44 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.44/packages/react-router-devtools) Updates `@tanstack/router-plugin` from 1.131.41 to 1.131.44 - [Release notes](https://github.com/TanStack/router/releases) - [Commits](https://github.com/TanStack/router/commits/v1.131.44/packages/router-plugin) --- updated-dependencies: - dependency-name: "@tanstack/react-router" dependency-version: 1.131.44 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: tanstack-router - dependency-name: "@tanstack/react-router-devtools" dependency-version: 1.131.44 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: tanstack-router - dependency-name: "@tanstack/router-plugin" dependency-version: 1.131.44 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: tanstack-router ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 110 ++++++++++++++++++------------------- frontend/package.json | 6 +- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dabbd635d..4e98c5595 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13,7 +13,7 @@ "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", - "@tanstack/react-router": "^1.131.41", + "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", "@zxcvbn-ts/core": "^3.0.4", @@ -39,8 +39,8 @@ "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.87.4", - "@tanstack/react-router-devtools": "^1.131.42", - "@tanstack/router-plugin": "^1.131.41", + "@tanstack/react-router-devtools": "^1.131.44", + "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", @@ -5108,14 +5108,14 @@ } }, "node_modules/@tanstack/react-router": { - "version": "1.131.41", - "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.41.tgz", - "integrity": "sha512-QEbTYpAosiD8e4qEZRr9aJipGSb8pQc+pfZwK6NCD2Tcxwu2oF6MVtwv0bIDLRpZP0VJMBpxXlTRISUDNMNqIA==", + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.131.44.tgz", + "integrity": "sha512-LREJfrl8lSedXHCRAAt0HvnHFP9ikAQWnVhYRM++B26w4ZYQBbLvgCT1BCDZVY7MR6rslcd4OfgpZMOyVhNzFg==", "license": "MIT", "dependencies": { "@tanstack/history": "1.131.2", "@tanstack/react-store": "^0.7.0", - "@tanstack/router-core": "1.131.41", + "@tanstack/router-core": "1.131.44", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" @@ -5133,13 +5133,13 @@ } }, "node_modules/@tanstack/react-router-devtools": { - "version": "1.131.42", - "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.131.42.tgz", - "integrity": "sha512-7pymFB1CCimRHot2Zp0ZekQjd1iN812V88n9NLPSeiv9sVRtRVIaLphJjDeudx1NNgkfSJPx2lOhz6K38cuZog==", + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/react-router-devtools/-/react-router-devtools-1.131.44.tgz", + "integrity": "sha512-JGICSLe3ZIqayo2Pz9bpCBLrK8NIruYSQoe/JkZimSGltV3HU+uPb1dohw0CpyxVuhx+tDqFBzq4cDPCABs4/w==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/router-devtools-core": "1.131.42" + "@tanstack/router-devtools-core": "1.131.44" }, "engines": { "node": ">=12" @@ -5149,11 +5149,41 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-router": "^1.131.41", + "@tanstack/react-router": "^1.131.44", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, + "node_modules/@tanstack/react-router-devtools/node_modules/@tanstack/router-devtools-core": { + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.44.tgz", + "integrity": "sha512-ZpQfRERLAjZ2NBdFOWjlrbMzQ+23aGs+9324KVdLzZkcd1lc0ztpLb5HAGtqLXfncvO60TfiRz106ygjKsaJow==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1", + "goober": "^2.1.16", + "solid-js": "^1.9.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/router-core": "^1.131.44", + "csstype": "^3.0.10", + "solid-js": ">=1.9.5", + "tiny-invariant": "^1.3.3" + }, + "peerDependenciesMeta": { + "csstype": { + "optional": true + } + } + }, "node_modules/@tanstack/react-store": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.5.tgz", @@ -5173,9 +5203,9 @@ } }, "node_modules/@tanstack/router-core": { - "version": "1.131.41", - "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.41.tgz", - "integrity": "sha512-VoLly00DWM0abKuVPRm8wiwGtRBHOKs6K896fy48Q/KYoDVLs8kRCRjFGS7rGnYC2FIkmmvHqYRqNg7jgCx2yg==", + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/router-core/-/router-core-1.131.44.tgz", + "integrity": "sha512-Npi9xB3GSYZhRW8+gPhP6bEbyx0vNc8ZNwsi0JapdiFpIiszgRJ57pesy/rklruv46gYQjLVA5KDOsuaCT/urA==", "license": "MIT", "dependencies": { "@tanstack/history": "1.131.2", @@ -5194,44 +5224,14 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@tanstack/router-devtools-core": { - "version": "1.131.42", - "resolved": "https://registry.npmjs.org/@tanstack/router-devtools-core/-/router-devtools-core-1.131.42.tgz", - "integrity": "sha512-o8jKTiwXcUSjmkozcMjIw1yhjVYeXcuQO7DtfgjKW3B85iveH6VzYK+bGEVU7wmLNMuUSe2eI/7RBzJ6a5+MCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1", - "goober": "^2.1.16", - "solid-js": "^1.9.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@tanstack/router-core": "^1.131.41", - "csstype": "^3.0.10", - "solid-js": ">=1.9.5", - "tiny-invariant": "^1.3.3" - }, - "peerDependenciesMeta": { - "csstype": { - "optional": true - } - } - }, "node_modules/@tanstack/router-generator": { - "version": "1.131.41", - "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.41.tgz", - "integrity": "sha512-HsDkBU1u/KvHrzn76v/9oeyMFuxvVlE3dfIu4fldZbPy/i903DWBwODIDGe6fVUsYtzPPrRvNtbjV18HVz5GCA==", + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.131.44.tgz", + "integrity": "sha512-CnrlRkGatdQXdvTteflOTMANupb1z59CO3DSV+UzBkTG+g+vfWgJeKQ0EkfwZ2QuS6Su2v5r5EMHs/AookeZZw==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/router-core": "1.131.41", + "@tanstack/router-core": "1.131.44", "@tanstack/router-utils": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2", "prettier": "^3.5.0", @@ -5249,9 +5249,9 @@ } }, "node_modules/@tanstack/router-plugin": { - "version": "1.131.41", - "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.41.tgz", - "integrity": "sha512-MENVYQwvhKFIPZ/YO/CGCwbh3Ba3TRvUYZ2y2KiU6aa1CWao4KHDRsungzv34AbbUBSmzbc8mKVeqd+G+E9cDQ==", + "version": "1.131.44", + "resolved": "https://registry.npmjs.org/@tanstack/router-plugin/-/router-plugin-1.131.44.tgz", + "integrity": "sha512-CvheUPlB8vxXf23RSDz6q97l1EI5H3f+1qJ/LEBvy7bhls8vYouJ3xyTeu4faz8bEEieLUoVQrCcr+xFY0lkuw==", "dev": true, "license": "MIT", "dependencies": { @@ -5261,8 +5261,8 @@ "@babel/template": "^7.27.2", "@babel/traverse": "^7.27.7", "@babel/types": "^7.27.7", - "@tanstack/router-core": "1.131.41", - "@tanstack/router-generator": "1.131.41", + "@tanstack/router-core": "1.131.44", + "@tanstack/router-generator": "1.131.44", "@tanstack/router-utils": "1.131.2", "@tanstack/virtual-file-routes": "1.131.2", "babel-dead-code-elimination": "^1.0.10", @@ -5279,7 +5279,7 @@ }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", - "@tanstack/react-router": "^1.131.41", + "@tanstack/react-router": "^1.131.44", "vite": ">=5.0.0 || >=6.0.0", "vite-plugin-solid": "^2.11.2", "webpack": ">=5.92.0" diff --git a/frontend/package.json b/frontend/package.json index 295e7aa49..61453f6fb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,7 +23,7 @@ "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.87.4", - "@tanstack/react-router": "^1.131.41", + "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", "@zxcvbn-ts/core": "^3.0.4", @@ -49,8 +49,8 @@ "@storybook/addon-docs": "^9.1.5", "@storybook/react-vite": "^9.1.5", "@tanstack/react-query-devtools": "^5.87.4", - "@tanstack/react-router-devtools": "^1.131.42", - "@tanstack/router-plugin": "^1.131.41", + "@tanstack/react-router-devtools": "^1.131.44", + "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", From 467984ab3af71cc7b9eb183935c896b42bb95073 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:12:40 +0000 Subject: [PATCH 057/296] build(deps-dev): bump the types group in /frontend with 2 updates Bumps the types group in /frontend with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). Updates `@types/node` from 24.3.1 to 24.4.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/react` from 19.1.12 to 19.1.13 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.4.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: types - dependency-name: "@types/react" dependency-version: 19.1.13 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dabbd635d..6ec7933d9 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,8 +44,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.3.1", - "@types/react": "19.1.12", + "@types/node": "^24.4.0", + "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.2", @@ -5597,19 +5597,19 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.3.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz", - "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==", + "version": "24.4.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz", + "integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.10.0" + "undici-types": "~7.11.0" } }, "node_modules/@types/react": { - "version": "19.1.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz", - "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==", + "version": "19.1.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", + "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12789,9 +12789,9 @@ } }, "node_modules/undici-types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", - "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz", + "integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index 295e7aa49..3d4d4fcbf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.3.1", - "@types/react": "19.1.12", + "@types/node": "^24.4.0", + "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.2", From 868fe3aa9d726f7539c6ad31793da608b702febb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:16:08 +0000 Subject: [PATCH 058/296] build(deps): bump camino from 1.1.12 to 1.2.0 Bumps [camino](https://github.com/camino-rs/camino) from 1.1.12 to 1.2.0. - [Release notes](https://github.com/camino-rs/camino/releases) - [Changelog](https://github.com/camino-rs/camino/blob/main/CHANGELOG.md) - [Commits](https://github.com/camino-rs/camino/compare/camino-1.1.12...camino-1.2.0) --- updated-dependencies: - dependency-name: camino dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 24 +++++++++++++++++------- Cargo.toml | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdc880b94..efaf996f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -825,11 +825,11 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.12" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" +checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -5534,18 +5534,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 2b89b5e53..dd01402ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ version = "1.10.1" # UTF-8 paths [workspace.dependencies.camino] -version = "1.1.12" +version = "1.2.0" features = ["serde1"] # ChaCha20Poly1305 AEAD From 8fa693b934731a42c6b30cb5ad2e44c46fad240f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:16:54 +0000 Subject: [PATCH 059/296] build(deps): bump hyper-util from 0.1.16 to 0.1.17 Bumps [hyper-util](https://github.com/hyperium/hyper-util) from 0.1.16 to 0.1.17. - [Release notes](https://github.com/hyperium/hyper-util/releases) - [Changelog](https://github.com/hyperium/hyper-util/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/hyper-util/compare/v0.1.16...v0.1.17) --- updated-dependencies: - dependency-name: hyper-util dependency-version: 0.1.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdc880b94..c7ed0b24c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2341,9 +2341,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64", "bytes", diff --git a/Cargo.toml b/Cargo.toml index 2b89b5e53..9e2f55789 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -274,7 +274,7 @@ features = ["client", "server", "http1", "http2"] # Additional Hyper utilties [workspace.dependencies.hyper-util] -version = "0.1.16" +version = "0.1.17" features = [ "client", "server", From dc8662548f7717144e3284a3989eaecd37899b65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Sep 2025 14:23:35 +0000 Subject: [PATCH 060/296] build(deps): bump serde from 1.0.219 to 1.0.223 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.219 to 1.0.223. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.219...v1.0.223) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.223 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 18 ++++++++++++++---- Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdc880b94..b373c0421 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5534,18 +5534,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.223" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.223" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 2b89b5e53..2420d5eb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -582,7 +582,7 @@ version = "0.42.0" # Serialization and deserialization [workspace.dependencies.serde] -version = "1.0.219" +version = "1.0.223" features = ["derive"] # Most of the time, if we need serde, we need derive # JSON serialization and deserialization From 6e230fa3541692bc53e0b895be4d8de9f3830281 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 10:25:15 +0000 Subject: [PATCH 061/296] build(deps): bump serde_json from 1.0.143 to 1.0.145 Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.143 to 1.0.145. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.143...v1.0.145) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.145 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25001a3f7..7fd4e9ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5588,15 +5588,16 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "indexmap 2.11.1", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8a7fec53e..156d5f150 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -587,7 +587,7 @@ features = ["derive"] # Most of the time, if we need serde, we need derive # JSON serialization and deserialization [workspace.dependencies.serde_json] -version = "1.0.143" +version = "1.0.145" features = ["preserve_order"] # URL encoded form serialization From 1644b418948a9ea2997a61ffb6fb1671f33e489c Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 16 Sep 2025 12:42:32 +0200 Subject: [PATCH 062/296] Simple CLI commands to manage server admins --- crates/cli/src/commands/manage.rs | 92 ++++++++++++++++++++++++++++++- docs/reference/cli/manage.md | 26 +++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/commands/manage.rs b/crates/cli/src/commands/manage.rs index a6a8e67a0..0b0121078 100644 --- a/crates/cli/src/commands/manage.rs +++ b/crates/cli/src/commands/manage.rs @@ -19,14 +19,17 @@ use mas_data_model::{Clock, Device, SystemClock, TokenType, Ulid, UpstreamOAuthP use mas_email::Address; use mas_matrix::HomeserverConnection; use mas_storage::{ - RepositoryAccess, + Pagination, RepositoryAccess, compat::{CompatAccessTokenRepository, CompatSessionFilter, CompatSessionRepository}, oauth2::OAuth2SessionFilter, queue::{ DeactivateUserJob, ProvisionUserJob, QueueJobRepositoryExt as _, ReactivateUserJob, SyncDevicesJob, }, - user::{BrowserSessionFilter, UserEmailRepository, UserPasswordRepository, UserRepository}, + user::{ + BrowserSessionFilter, UserEmailRepository, UserFilter, UserPasswordRepository, + UserRepository, + }, }; use mas_storage_pg::{DatabaseError, PgRepository}; use rand::{ @@ -85,6 +88,15 @@ enum Subcommand { ignore_complexity: bool, }, + /// Make a user admin + PromoteAdmin { username: String }, + + /// Make a user non-admin + DemoteAdmin { username: String }, + + /// List all users with admin privileges + ListAdminUsers, + /// Issue a compatibility token IssueCompatibilityToken { /// User for which to issue the token @@ -315,6 +327,82 @@ impl Options { Ok(ExitCode::SUCCESS) } + SC::PromoteAdmin { username } => { + let _span = + info_span!("cli.manage.promote_admin", user.username = username,).entered(); + + let database_config = DatabaseConfig::extract_or_default(figment) + .map_err(anyhow::Error::from_boxed)?; + let mut conn = database_connection_from_config(&database_config).await?; + let txn = conn.begin().await?; + let mut repo = PgRepository::from_conn(txn); + + let user = repo + .user() + .find_by_username(&username) + .await? + .context("User not found")?; + + let user = repo.user().set_can_request_admin(user, true).await?; + + repo.into_inner().commit().await?; + info!(%user.id, %user.username, "User promoted to admin"); + + Ok(ExitCode::SUCCESS) + } + + SC::DemoteAdmin { username } => { + let _span = + info_span!("cli.manage.demote_admin", user.username = username,).entered(); + + let database_config = DatabaseConfig::extract_or_default(figment) + .map_err(anyhow::Error::from_boxed)?; + let mut conn = database_connection_from_config(&database_config).await?; + let txn = conn.begin().await?; + let mut repo = PgRepository::from_conn(txn); + + let user = repo + .user() + .find_by_username(&username) + .await? + .context("User not found")?; + + let user = repo.user().set_can_request_admin(user, false).await?; + + repo.into_inner().commit().await?; + info!(%user.id, %user.username, "User is no longer admin"); + + Ok(ExitCode::SUCCESS) + } + + SC::ListAdminUsers => { + let _span = info_span!("cli.manage.list_admins").entered(); + let database_config = DatabaseConfig::extract_or_default(figment) + .map_err(anyhow::Error::from_boxed)?; + let mut conn = database_connection_from_config(&database_config).await?; + let txn = conn.begin().await?; + let mut repo = PgRepository::from_conn(txn); + + let mut cursor = Pagination::first(1000); + let filter = UserFilter::new().can_request_admin_only(); + let total = repo.user().count(filter).await?; + + info!("The following users can request admin privileges ({total} total):"); + loop { + let page = repo.user().list(filter, cursor).await?; + for user in page.edges { + info!(%user.id, username = %user.username); + cursor = cursor.after(user.id); + } + + if !page.has_next_page { + break; + } + } + + Ok(ExitCode::SUCCESS) + } + SC::IssueCompatibilityToken { username, admin, diff --git a/docs/reference/cli/manage.md b/docs/reference/cli/manage.md index 0f14f1773..5b107cd52 100644 --- a/docs/reference/cli/manage.md +++ b/docs/reference/cli/manage.md @@ -23,6 +23,32 @@ $ mas-cli manage add-email $ mas-cli manage verify-email ``` +## `manage promote-admin` + +Make a user admin. + +``` +$ mas-cli manage promote-admin +``` + +**This doesn't make all the users sessions admin, but rather lets the user request admin access in administration tools.** + +## `manage demote-admin` + +Make a user non-admin. + +``` +$ mas-cli manage demote-admin +``` + +## `manage list-admin-users` + +List all users with admin privileges. + +``` +$ mas-cli manage list-admins +``` + ## `manage set-password` Set a user password. From 317186043d5ddccf8e19fc46db9c05b74dbd1a5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:15:06 +0000 Subject: [PATCH 063/296] build(deps): bump the tanstack-query group in /frontend with 2 updates Bumps the tanstack-query group in /frontend with 2 updates: [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) and [@tanstack/react-query-devtools](https://github.com/TanStack/query/tree/HEAD/packages/react-query-devtools). Updates `@tanstack/react-query` from 5.87.4 to 5.89.0 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.89.0/packages/react-query) Updates `@tanstack/react-query-devtools` from 5.87.4 to 5.89.0 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.89.0/packages/react-query-devtools) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.89.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: tanstack-query - dependency-name: "@tanstack/react-query-devtools" dependency-version: 5.89.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: tanstack-query ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 26 +++++++++++++------------- frontend/package.json | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bd32b4a55..17ad8def8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,7 @@ "@fontsource/inter": "^5.2.7", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", - "@tanstack/react-query": "^5.87.4", + "@tanstack/react-query": "^5.89.0", "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", @@ -38,7 +38,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.6", "@storybook/react-vite": "^9.1.6", - "@tanstack/react-query-devtools": "^5.87.4", + "@tanstack/react-query-devtools": "^5.89.0", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", @@ -5053,9 +5053,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.87.4", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.87.4.tgz", - "integrity": "sha512-uNsg6zMxraEPDVO2Bn+F3/ctHi+Zsk+MMpcN8h6P7ozqD088F6mFY5TfGM7zuyIrL7HKpDyu6QHfLWiDxh3cuw==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz", + "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==", "license": "MIT", "funding": { "type": "github", @@ -5074,12 +5074,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.87.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.87.4.tgz", - "integrity": "sha512-T5GT/1ZaNsUXf5I3RhcYuT17I4CPlbZgyLxc/ZGv7ciS6esytlbjb3DgUFO6c8JWYMDpdjSWInyGZUErgzqhcA==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz", + "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.87.4" + "@tanstack/query-core": "5.89.0" }, "funding": { "type": "github", @@ -5090,9 +5090,9 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.87.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.87.4.tgz", - "integrity": "sha512-JYcnVJBBW1DCPyNGM0S2CyrLpe6KFiL2gpYd/k9tAp62Du7+Y27zkzd+dKFyxpFadYaTxsx4kUA7YvnkMLVUoQ==", + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.89.0.tgz", + "integrity": "sha512-Syc4UjZeIJCkXCRGyQcWwlnv89JNb98MMg/DAkFCV3rwOcknj98+nG3Nm6xLXM6ne9sK6RZeDJMPLKZUh6NUGA==", "dev": true, "license": "MIT", "dependencies": { @@ -5103,7 +5103,7 @@ "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.87.4", + "@tanstack/react-query": "^5.89.0", "react": "^18 || ^19" } }, diff --git a/frontend/package.json b/frontend/package.json index 3cc3ff80b..38e8f0257 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,7 +22,7 @@ "@fontsource/inter": "^5.2.7", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", - "@tanstack/react-query": "^5.87.4", + "@tanstack/react-query": "^5.89.0", "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", @@ -48,7 +48,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.6", "@storybook/react-vite": "^9.1.6", - "@tanstack/react-query-devtools": "^5.87.4", + "@tanstack/react-query-devtools": "^5.89.0", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", From ee58086b0f59a4c53e95bb8d657ae6b8bf310f22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:15:16 +0000 Subject: [PATCH 064/296] build(deps-dev): bump @types/node in /frontend in the types group Bumps the types group in /frontend with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node). Updates `@types/node` from 24.4.0 to 24.5.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.5.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bd32b4a55..47e0c3419 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,7 +44,7 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.4.0", + "@types/node": "^24.5.0", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", @@ -5597,13 +5597,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.4.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz", - "integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==", + "version": "24.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.0.tgz", + "integrity": "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.11.0" + "undici-types": "~7.12.0" } }, "node_modules/@types/react": { @@ -12789,9 +12789,9 @@ } }, "node_modules/undici-types": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz", - "integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", + "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index 3cc3ff80b..ed8e3d529 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,7 +54,7 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.4.0", + "@types/node": "^24.5.0", "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", From 78fd391949fd07c92ae92519ded648c4a29954b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:17:46 +0000 Subject: [PATCH 065/296] build(deps): bump indexmap from 2.11.1 to 2.11.3 Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.11.1 to 2.11.3. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.11.1...2.11.3) --- updated-dependencies: - dependency-name: indexmap dependency-version: 2.11.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 49 +++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e07885537..09f950d6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ dependencies = [ "bytes", "cfg-if", "http", - "indexmap 2.11.1", + "indexmap 2.11.3", "schemars 0.8.22", "serde", "serde_json", @@ -310,7 +310,7 @@ dependencies = [ "futures-timer", "futures-util", "http", - "indexmap 2.11.1", + "indexmap 2.11.3", "mime", "multer", "num-traits", @@ -362,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ecdaff7c9cffa3614a9f9999bf9ee4c3078fe3ce4d6a6e161736b56febf2de" dependencies = [ "bytes", - "indexmap 2.11.1", + "indexmap 2.11.3", "serde", "serde_json", ] @@ -2052,7 +2052,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", - "indexmap 2.11.1", + "indexmap 2.11.3", "stable_deref_trait", ] @@ -2118,7 +2118,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.1", + "indexmap 2.11.3", "slab", "tokio", "tokio-util", @@ -2726,13 +2726,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" dependencies = [ "equivalent", "hashbrown 0.15.4", "serde", + "serde_core", ] [[package]] @@ -3321,7 +3322,7 @@ dependencies = [ "hex", "hyper", "icu_normalizer", - "indexmap 2.11.1", + "indexmap 2.11.3", "insta", "lettre", "mas-axum-utils", @@ -4029,7 +4030,7 @@ dependencies = [ "assert_matches", "base64ct", "chrono", - "indexmap 2.11.1", + "indexmap 2.11.3", "insta", "language-tags", "mas-iana", @@ -4050,7 +4051,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.4", - "indexmap 2.11.1", + "indexmap 2.11.3", "memchr", ] @@ -4532,7 +4533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64", - "indexmap 2.11.1", + "indexmap 2.11.3", "quick-xml", "serde", "time", @@ -5028,7 +5029,7 @@ dependencies = [ "base64", "bytes", "form_urlencoded", - "indexmap 2.11.1", + "indexmap 2.11.3", "js_int", "percent-encoding", "regex", @@ -5266,7 +5267,7 @@ dependencies = [ "chrono", "dyn-clone", "indexmap 1.9.3", - "indexmap 2.11.1", + "indexmap 2.11.3", "schemars_derive", "serde", "serde_json", @@ -5580,7 +5581,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" dependencies = [ "form_urlencoded", - "indexmap 2.11.1", + "indexmap 2.11.3", "itoa", "ryu", "serde", @@ -5592,7 +5593,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.3", "itoa", "memchr", "ryu", @@ -5654,7 +5655,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.1", + "indexmap 2.11.3", "schemars 0.9.0", "schemars 1.0.4", "serde", @@ -5682,7 +5683,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.3", "itoa", "ryu", "serde", @@ -5868,7 +5869,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.4", "hashlink", - "indexmap 2.11.1", + "indexmap 2.11.3", "ipnetwork", "log", "memchr", @@ -6443,7 +6444,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.3", "serde", "serde_spanned", "toml_datetime", @@ -7011,7 +7012,7 @@ checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", "hashbrown 0.15.4", - "indexmap 2.11.1", + "indexmap 2.11.3", "semver", "serde", ] @@ -7041,7 +7042,7 @@ dependencies = [ "cc", "cfg-if", "hashbrown 0.15.4", - "indexmap 2.11.1", + "indexmap 2.11.3", "libc", "log", "mach2", @@ -7081,7 +7082,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.1", + "indexmap 2.11.3", "log", "object", "postcard", @@ -7226,7 +7227,7 @@ checksum = "1ae057d44a5b60e6ec529b0c21809a9d1fc92e91ef6e0f6771ed11dd02a94a08" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.1", + "indexmap 2.11.3", "wit-parser", ] @@ -7747,7 +7748,7 @@ checksum = "0a1f95a87d03a33e259af286b857a95911eb46236a0f726cbaec1227b3dfc67a" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.1", + "indexmap 2.11.3", "log", "semver", "serde", diff --git a/Cargo.toml b/Cargo.toml index 2e92f0df0..3cca5a4a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -321,7 +321,7 @@ features = ["std"] # HashMap which preserves insertion order [workspace.dependencies.indexmap] -version = "2.11.1" +version = "2.11.3" features = ["serde"] # Indented string literals From 2cd89d7552c1d8f8726d4a46daa99dd26a602471 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 11:28:38 +0000 Subject: [PATCH 066/296] build(deps): bump serde from 1.0.223 to 1.0.225 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.223 to 1.0.225. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.223...v1.0.225) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.225 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09f950d6c..41e8046fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5535,9 +5535,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a505d71960adde88e293da5cb5eda57093379f64e61cf77bf0e6a63af07a7bac" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ "serde_core", "serde_derive", @@ -5545,18 +5545,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20f57cbd357666aa7b3ac84a90b4ea328f1d4ddb6772b430caa5d9e1309bb9e9" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.223" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d428d07faf17e306e699ec1e91996e5a165ba5d6bce5b5155173e91a8a01a56" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3cca5a4a2..48168a60d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -582,7 +582,7 @@ version = "0.42.0" # Serialization and deserialization [workspace.dependencies.serde] -version = "1.0.223" +version = "1.0.225" features = ["derive"] # Most of the time, if we need serde, we need derive # JSON serialization and deserialization From b2c0191b2c412e5f0b0f004eb109e5604f49af0f Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 16 Sep 2025 13:28:56 +0200 Subject: [PATCH 067/296] Bump locked dependencies --- Cargo.lock | 514 +++++++++++++++++++++++++---------------------------- deny.toml | 6 - 2 files changed, 247 insertions(+), 273 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 41e8046fd..f138cfe3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -164,22 +164,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -190,9 +190,9 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "arbitrary" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" dependencies = [ "async-task", "concurrent-queue", @@ -369,38 +369,38 @@ dependencies = [ [[package]] name = "async-io" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" dependencies = [ - "async-lock", + "autocfg", "cfg-if", "concurrent-queue", "futures-io", "futures-lite", "parking", "polling", - "rustix 1.0.8", + "rustix", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] name = "async-lock" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] [[package]] name = "async-process" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65daa13722ad51e6ab1a1b9c01299142bc75135b337923cfa10e79bbbd669f00" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ "async-channel 2.5.0", "async-io", @@ -409,16 +409,16 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.4.0", + "event-listener 5.4.1", "futures-lite", - "rustix 1.0.8", + "rustix", ] [[package]] name = "async-signal" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f567af260ef69e1d52c2b560ce0ea230763e6fbb9214a85d768760a920e3e3c1" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" dependencies = [ "async-io", "async-lock", @@ -426,17 +426,17 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 1.0.8", + "rustix", "signal-hook-registry", "slab", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] name = "async-std" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" dependencies = [ "async-channel 1.9.0", "async-global-executor", @@ -530,9 +530,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" dependencies = [ "aws-lc-sys", "zeroize", @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" dependencies = [ "bindgen", "cc", @@ -688,25 +688,22 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", "syn", - "which", ] [[package]] @@ -794,9 +791,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" [[package]] name = "byteorder" @@ -852,10 +849,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -878,9 +876,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chacha20" @@ -1217,11 +1215,11 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "log", "pulley-interpreter", "regalloc2", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "smallvec", "target-lexicon", @@ -1483,11 +1481,12 @@ dependencies = [ [[package]] name = "deadpool" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" dependencies = [ "deadpool-runtime", + "lazy_static", "num_cpus", "tokio", ] @@ -1521,9 +1520,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" dependencies = [ "powerfmt", "serde", @@ -1625,7 +1624,7 @@ checksum = "eb333721800c025e363e902b293040778f8ac79913db4f013abf1f1d7d382fd7" dependencies = [ "rust_decimal", "thiserror 2.0.16", - "winnow 0.7.12", + "winnow 0.7.13", ] [[package]] @@ -1729,12 +1728,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -1756,9 +1755,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "5.4.0" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ "concurrent-queue", "parking", @@ -1771,7 +1770,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.0", + "event-listener 5.4.1", "pin-project-lite", ] @@ -1824,6 +1823,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" + [[package]] name = "fixed_decimal" version = "0.5.6" @@ -1934,9 +1939,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ "fastrand", "futures-core", @@ -2032,7 +2037,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -2058,9 +2063,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "gloo-timers" @@ -2085,7 +2090,7 @@ dependencies = [ "futures-sink", "futures-timer", "futures-util", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "nonzero_ext", "parking_lot", "portable-atomic", @@ -2108,9 +2113,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -2143,9 +2148,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", @@ -2159,7 +2164,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.15.4", + "hashbrown 0.15.5", ] [[package]] @@ -2365,9 +2370,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2731,7 +2736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "serde", "serde_core", ] @@ -2744,9 +2749,9 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" [[package]] name = "inherent" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13" +checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" dependencies = [ "proc-macro2", "quote", @@ -2783,9 +2788,9 @@ dependencies = [ [[package]] name = "io-uring" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ "bitflags", "cfg-if", @@ -2824,15 +2829,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2881,9 +2877,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.3", "libc", @@ -2891,9 +2887,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" dependencies = [ "once_cell", "wasm-bindgen", @@ -2971,12 +2967,6 @@ dependencies = [ "spin", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -3016,9 +3006,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" @@ -3036,6 +3026,17 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -3048,15 +3049,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "listenfd" @@ -3093,9 +3088,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" dependencies = [ "value-bag", ] @@ -3800,11 +3795,11 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memfd" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 0.38.44", + "rustix", ] [[package]] @@ -4050,7 +4045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "indexmap 2.11.3", "memchr", ] @@ -4528,9 +4523,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.7.4" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64", "indexmap 2.11.3", @@ -4541,16 +4536,16 @@ dependencies = [ [[package]] name = "polling" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee9b2fa7a4517d2c91ff5bc6c297a427a96749d15f98fcdbb22c05571a4d4b7" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" dependencies = [ "cfg-if", "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix", + "windows-sys 0.61.0", ] [[package]] @@ -4611,9 +4606,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.36" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", @@ -4639,9 +4634,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -4746,9 +4741,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.0" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" dependencies = [ "memchr", ] @@ -4835,18 +4830,18 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.5.0" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ "bitflags", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -4854,9 +4849,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -4899,9 +4894,9 @@ checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "log", - "rustc-hash 2.1.1", + "rustc-hash", "smallvec", ] @@ -4919,9 +4914,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -4930,9 +4925,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "reqwest" @@ -5074,9 +5069,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.2" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" +checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0" dependencies = [ "arrayvec", "num-traits", @@ -5088,12 +5083,6 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -5111,28 +5100,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys", + "windows-sys 0.61.0", ] [[package]] @@ -5209,9 +5185,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" dependencies = [ "aws-lc-rs", "ring", @@ -5221,9 +5197,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -5251,11 +5227,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -5390,9 +5366,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" dependencies = [ "bitflags", "core-foundation", @@ -5403,9 +5379,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -5419,9 +5395,9 @@ checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "sentry" @@ -5576,15 +5552,15 @@ dependencies = [ [[package]] name = "serde_html_form" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2de91cf02bbc07cde38891769ccd5d4f073d22a40683aa4bc7a95781aaa2c4" +checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" dependencies = [ "form_urlencoded", "indexmap 2.11.3", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] @@ -5603,12 +5579,13 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -5735,9 +5712,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -5862,12 +5839,12 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener 5.4.0", + "event-listener 5.4.1", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "hashlink", "indexmap 2.11.3", "ipnetwork", @@ -6115,9 +6092,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -6147,7 +6124,7 @@ dependencies = [ "opentelemetry-semantic-conventions", "rand 0.8.5", "rand_chacha 0.3.1", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_json", "sqlx", @@ -6183,21 +6160,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "tempfile" -version = "3.20.0" +version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.8", - "windows-sys 0.59.0", + "rustix", + "windows-sys 0.61.0", ] [[package]] @@ -6282,12 +6259,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -6299,15 +6275,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -6325,9 +6301,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -6448,7 +6424,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.7.12", + "winnow 0.7.13", ] [[package]] @@ -6703,9 +6679,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-normalization" @@ -6910,11 +6886,20 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", ] [[package]] @@ -6925,21 +6910,22 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", "log", @@ -6951,9 +6937,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" dependencies = [ "cfg-if", "js-sys", @@ -6964,9 +6950,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6974,9 +6960,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", @@ -6987,9 +6973,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" dependencies = [ "unicode-ident", ] @@ -7011,7 +6997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "indexmap 2.11.3", "semver", "serde", @@ -7041,7 +7027,7 @@ dependencies = [ "bumpalo", "cc", "cfg-if", - "hashbrown 0.15.4", + "hashbrown 0.15.5", "indexmap 2.11.3", "libc", "log", @@ -7052,7 +7038,7 @@ dependencies = [ "postcard", "pulley-interpreter", "rayon", - "rustix 1.0.8", + "rustix", "serde", "serde_derive", "smallvec", @@ -7162,7 +7148,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "rustix 1.0.8", + "rustix", "wasmtime-internal-asm-macros", "wasmtime-internal-versioned-export-macros", "windows-sys 0.59.0", @@ -7233,9 +7219,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" dependencies = [ "js-sys", "wasm-bindgen", @@ -7278,33 +7264,21 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", ] [[package]] name = "wildmatch" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce1ab1f8c62655ebe1350f589c61e505cf94d385bc6a12899442d9081e71fd" +checksum = "39b7d07a236abaef6607536ccfaf19b396dbe3f5110ddb73d39f4562902ed382" [[package]] name = "winapi" @@ -7324,11 +7298,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -7339,13 +7313,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", + "windows-link 0.2.0", "windows-result", "windows-strings", ] @@ -7386,20 +7360,20 @@ checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", ] [[package]] @@ -7447,6 +7421,15 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -7701,9 +7684,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -7732,13 +7715,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "wit-parser" @@ -7815,18 +7795,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/deny.toml b/deny.toml index 0d09c790f..a0d6a8e03 100644 --- a/deny.toml +++ b/deny.toml @@ -59,8 +59,6 @@ deny = [ multiple-versions = "deny" skip = [ - { name = "regex-syntax", version = "0.6.29" }, # tracing-subscriber[env-filter] -> matchers depends on the old version - { name = "regex-automata", version = "0.1.10" }, # ^ { name = "itertools", version = "0.13.0" }, # zxcvbn depends on this old version { name = "indexmap", version = "1.9.3" }, # schemars depends on this old version { name = "hashbrown", version = "0.12.3" }, # schemars -> indexmap depends on this old version @@ -75,10 +73,6 @@ skip = [ # cron depends on this old version # https://github.com/zslayton/cron/pull/137 { name = "winnow", version = "0.6.20" }, - # opa-wasm -> wasmtime -> memfd depends on this old version - # https://github.com/lucab/memfd-rs/pull/72 - { name = "rustix", version = "0.38.44" }, - { name = "linux-raw-sys", version = "0.9.4" }, # We are still mainly using rand 0.8 { name = "rand", version = "0.8.5" }, From e7e4ece2defc28cef1dbefafec8775d8240fb20a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:19:38 +0000 Subject: [PATCH 068/296] Translations updates --- frontend/.storybook/locales.ts | 62 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts index 3c370a041..090812bf0 100644 --- a/frontend/.storybook/locales.ts +++ b/frontend/.storybook/locales.ts @@ -27,7 +27,7 @@ export type LocalazyMetadata = { }; const localazyMetadata: LocalazyMetadata = { - projectUrl: "https://localazy.com/p/matrix-authentication-service!v1.2", + projectUrl: "https://localazy.com/p/matrix-authentication-service", baseLocale: "en", languages: [ { @@ -172,21 +172,21 @@ const localazyMetadata: LocalazyMetadata = { file: "frontend.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", - "da": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", - "de": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", - "en": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", - "et": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", - "fi": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", - "fr": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", - "hu": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", - "nb_NO": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", - "nl": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", - "pt": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", - "ru": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", - "sv": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", - "uk": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", - "zh#Hans": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" + "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", + "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", + "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", + "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", + "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", + "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", + "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", + "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", + "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", + "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", + "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", + "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", + "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", + "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" } }, { @@ -194,21 +194,21 @@ const localazyMetadata: LocalazyMetadata = { file: "file.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", - "da": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", - "de": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", - "en": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", - "et": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", - "fi": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", - "fr": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", - "hu": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", - "nb_NO": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", - "nl": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", - "pt": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", - "ru": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", - "sv": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", - "uk": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", - "zh#Hans": "https://delivery.localazy.com/_a6821010713418053635c3353a0f/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" + "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", + "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", + "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", + "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", + "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", + "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", + "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", + "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", + "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", + "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", + "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", + "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", + "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", + "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" } } ] From cf23688939ee7276f930432b56f7309bcb8d1679 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 16 Sep 2025 13:33:28 +0000 Subject: [PATCH 069/296] 1.3.0-rc.0 --- Cargo.lock | 56 +++++++++++++++++++++++++------------------------- Cargo.toml | 60 +++++++++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f138cfe3b..1c00b8a00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3106,7 +3106,7 @@ dependencies = [ [[package]] name = "mas-axum-utils" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "axum", @@ -3140,7 +3140,7 @@ dependencies = [ [[package]] name = "mas-cli" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "axum", @@ -3213,7 +3213,7 @@ dependencies = [ [[package]] name = "mas-config" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "camino", @@ -3245,7 +3245,7 @@ dependencies = [ [[package]] name = "mas-context" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "console", "opentelemetry", @@ -3261,7 +3261,7 @@ dependencies = [ [[package]] name = "mas-data-model" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "base64ct", "chrono", @@ -3284,7 +3284,7 @@ dependencies = [ [[package]] name = "mas-email" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "async-trait", "lettre", @@ -3295,7 +3295,7 @@ dependencies = [ [[package]] name = "mas-handlers" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "aide", "anyhow", @@ -3375,7 +3375,7 @@ dependencies = [ [[package]] name = "mas-http" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "futures-util", "headers", @@ -3396,7 +3396,7 @@ dependencies = [ [[package]] name = "mas-i18n" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "camino", "icu_calendar", @@ -3418,7 +3418,7 @@ dependencies = [ [[package]] name = "mas-i18n-scan" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "camino", "clap", @@ -3432,7 +3432,7 @@ dependencies = [ [[package]] name = "mas-iana" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "schemars 0.8.22", "serde", @@ -3440,7 +3440,7 @@ dependencies = [ [[package]] name = "mas-iana-codegen" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "async-trait", @@ -3456,7 +3456,7 @@ dependencies = [ [[package]] name = "mas-jose" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "base64ct", "chrono", @@ -3486,7 +3486,7 @@ dependencies = [ [[package]] name = "mas-keystore" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "aead", "base64ct", @@ -3514,7 +3514,7 @@ dependencies = [ [[package]] name = "mas-listener" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "bytes", @@ -3539,7 +3539,7 @@ dependencies = [ [[package]] name = "mas-matrix" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "async-trait", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "mas-matrix-synapse" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "async-trait", @@ -3566,7 +3566,7 @@ dependencies = [ [[package]] name = "mas-oidc-client" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "assert_matches", "async-trait", @@ -3602,7 +3602,7 @@ dependencies = [ [[package]] name = "mas-policy" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "arc-swap", @@ -3619,7 +3619,7 @@ dependencies = [ [[package]] name = "mas-router" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "axum", "serde", @@ -3630,7 +3630,7 @@ dependencies = [ [[package]] name = "mas-spa" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "camino", "serde", @@ -3639,7 +3639,7 @@ dependencies = [ [[package]] name = "mas-storage" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "async-trait", "chrono", @@ -3661,7 +3661,7 @@ dependencies = [ [[package]] name = "mas-storage-pg" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "async-trait", "chrono", @@ -3688,7 +3688,7 @@ dependencies = [ [[package]] name = "mas-tasks" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "async-trait", @@ -3720,7 +3720,7 @@ dependencies = [ [[package]] name = "mas-templates" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "arc-swap", @@ -3750,7 +3750,7 @@ dependencies = [ [[package]] name = "mas-tower" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "http", "opentelemetry", @@ -4020,7 +4020,7 @@ dependencies = [ [[package]] name = "oauth2-types" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "assert_matches", "base64ct", @@ -6103,7 +6103,7 @@ dependencies = [ [[package]] name = "syn2mas" -version = "1.2.0" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index 48168a60d..b99c6aa31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = ["crates/*"] resolver = "2" # Updated in the CI with a `sed` command -package.version = "1.2.0" +package.version = "1.3.0-rc.0" package.license = "AGPL-3.0-only OR LicenseRef-Element-Commercial" package.authors = ["Element Backend Team"] package.edition = "2024" @@ -34,35 +34,35 @@ broken_intra_doc_links = "deny" [workspace.dependencies] # Workspace crates -mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.2.0" } -mas-cli = { path = "./crates/cli/", version = "=1.2.0" } -mas-config = { path = "./crates/config/", version = "=1.2.0" } -mas-context = { path = "./crates/context/", version = "=1.2.0" } -mas-data-model = { path = "./crates/data-model/", version = "=1.2.0" } -mas-email = { path = "./crates/email/", version = "=1.2.0" } -mas-graphql = { path = "./crates/graphql/", version = "=1.2.0" } -mas-handlers = { path = "./crates/handlers/", version = "=1.2.0" } -mas-http = { path = "./crates/http/", version = "=1.2.0" } -mas-i18n = { path = "./crates/i18n/", version = "=1.2.0" } -mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.2.0" } -mas-iana = { path = "./crates/iana/", version = "=1.2.0" } -mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.2.0" } -mas-jose = { path = "./crates/jose/", version = "=1.2.0" } -mas-keystore = { path = "./crates/keystore/", version = "=1.2.0" } -mas-listener = { path = "./crates/listener/", version = "=1.2.0" } -mas-matrix = { path = "./crates/matrix/", version = "=1.2.0" } -mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.2.0" } -mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.2.0" } -mas-policy = { path = "./crates/policy/", version = "=1.2.0" } -mas-router = { path = "./crates/router/", version = "=1.2.0" } -mas-spa = { path = "./crates/spa/", version = "=1.2.0" } -mas-storage = { path = "./crates/storage/", version = "=1.2.0" } -mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.2.0" } -mas-tasks = { path = "./crates/tasks/", version = "=1.2.0" } -mas-templates = { path = "./crates/templates/", version = "=1.2.0" } -mas-tower = { path = "./crates/tower/", version = "=1.2.0" } -oauth2-types = { path = "./crates/oauth2-types/", version = "=1.2.0" } -syn2mas = { path = "./crates/syn2mas", version = "=1.2.0" } +mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.3.0-rc.0" } +mas-cli = { path = "./crates/cli/", version = "=1.3.0-rc.0" } +mas-config = { path = "./crates/config/", version = "=1.3.0-rc.0" } +mas-context = { path = "./crates/context/", version = "=1.3.0-rc.0" } +mas-data-model = { path = "./crates/data-model/", version = "=1.3.0-rc.0" } +mas-email = { path = "./crates/email/", version = "=1.3.0-rc.0" } +mas-graphql = { path = "./crates/graphql/", version = "=1.3.0-rc.0" } +mas-handlers = { path = "./crates/handlers/", version = "=1.3.0-rc.0" } +mas-http = { path = "./crates/http/", version = "=1.3.0-rc.0" } +mas-i18n = { path = "./crates/i18n/", version = "=1.3.0-rc.0" } +mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.3.0-rc.0" } +mas-iana = { path = "./crates/iana/", version = "=1.3.0-rc.0" } +mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.3.0-rc.0" } +mas-jose = { path = "./crates/jose/", version = "=1.3.0-rc.0" } +mas-keystore = { path = "./crates/keystore/", version = "=1.3.0-rc.0" } +mas-listener = { path = "./crates/listener/", version = "=1.3.0-rc.0" } +mas-matrix = { path = "./crates/matrix/", version = "=1.3.0-rc.0" } +mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.3.0-rc.0" } +mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.3.0-rc.0" } +mas-policy = { path = "./crates/policy/", version = "=1.3.0-rc.0" } +mas-router = { path = "./crates/router/", version = "=1.3.0-rc.0" } +mas-spa = { path = "./crates/spa/", version = "=1.3.0-rc.0" } +mas-storage = { path = "./crates/storage/", version = "=1.3.0-rc.0" } +mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.3.0-rc.0" } +mas-tasks = { path = "./crates/tasks/", version = "=1.3.0-rc.0" } +mas-templates = { path = "./crates/templates/", version = "=1.3.0-rc.0" } +mas-tower = { path = "./crates/tower/", version = "=1.3.0-rc.0" } +oauth2-types = { path = "./crates/oauth2-types/", version = "=1.3.0-rc.0" } +syn2mas = { path = "./crates/syn2mas", version = "=1.3.0-rc.0" } # OpenAPI schema generation and validation [workspace.dependencies.aide] From 4760129fa65e32c07488c19fa4a644c7fc5378ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 13:18:58 +0000 Subject: [PATCH 070/296] build(deps): bump tokio-rustls from 0.26.2 to 0.26.3 Bumps [tokio-rustls](https://github.com/rustls/tokio-rustls) from 0.26.2 to 0.26.3. - [Release notes](https://github.com/rustls/tokio-rustls/releases) - [Commits](https://github.com/rustls/tokio-rustls/compare/v/0.26.2...v/0.26.3) --- updated-dependencies: - dependency-name: tokio-rustls dependency-version: 0.26.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c00b8a00..854355da1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6347,9 +6347,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" dependencies = [ "rustls", "tokio", diff --git a/Cargo.toml b/Cargo.toml index b99c6aa31..67c8e730f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -652,7 +652,7 @@ version = "0.1.17" # Tokio rustls integration [workspace.dependencies.tokio-rustls] -version = "0.26.2" +version = "0.26.3" # Tokio test utilities [workspace.dependencies.tokio-test] From 93d109c9edfaa81ab80a0965b4468c24d3708fa3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:14:20 +0000 Subject: [PATCH 071/296] build(deps-dev): bump the vite group across 1 directory with 3 updates Bumps the vite group with 3 updates in the /frontend directory: [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [vite-plugin-graphql-codegen](https://github.com/danielwaltz/vite-plugin-graphql-codegen). Updates `@vitejs/plugin-react` from 5.0.2 to 5.0.3 - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.0.3/packages/plugin-react) Updates `vite` from 7.1.5 to 7.1.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.1.6/packages/vite) Updates `vite-plugin-graphql-codegen` from 3.6.3 to 3.7.0 - [Release notes](https://github.com/danielwaltz/vite-plugin-graphql-codegen/releases) - [Changelog](https://github.com/danielwaltz/vite-plugin-graphql-codegen/blob/main/CHANGELOG.md) - [Commits](https://github.com/danielwaltz/vite-plugin-graphql-codegen/compare/v3.6.3...v3.7.0) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 5.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite - dependency-name: vite dependency-version: 7.1.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite - dependency-name: vite-plugin-graphql-codegen dependency-version: 3.7.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: vite ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 36 ++++++++++++++++++------------------ frontend/package.json | 6 +++--- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 91d7c0771..dc60ee1c3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -48,7 +48,7 @@ "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^5.0.2", + "@vitejs/plugin-react": "^5.0.3", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -66,9 +66,9 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.5", + "vite": "7.1.6", "vite-plugin-compression": "^0.5.1", - "vite-plugin-graphql-codegen": "^3.6.3", + "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", "vitest": "^3.2.4" } @@ -4553,9 +4553,9 @@ "license": "MIT" }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.34", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz", - "integrity": "sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==", + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz", + "integrity": "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==", "dev": true, "license": "MIT" }, @@ -5719,16 +5719,16 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.2.tgz", - "integrity": "sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz", + "integrity": "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.3", + "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.34", + "@rolldown/pluginutils": "1.0.0-beta.35", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, @@ -13124,9 +13124,9 @@ } }, "node_modules/vite": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.5.tgz", - "integrity": "sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.6.tgz", + "integrity": "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13252,13 +13252,13 @@ } }, "node_modules/vite-plugin-graphql-codegen": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/vite-plugin-graphql-codegen/-/vite-plugin-graphql-codegen-3.6.3.tgz", - "integrity": "sha512-A6C5fEGg26jG4bUhxTRH3KegFXNJ4Vxy4x/F/UKTfl73wOeb64qA3/rJFybyambvjNFndyameNazyeUglfH4Qg==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/vite-plugin-graphql-codegen/-/vite-plugin-graphql-codegen-3.7.0.tgz", + "integrity": "sha512-6TXkpUPZunV+RHP+A5R6ohar6WWjfWxTN8OpBsrZmGlJlVEpwc+2FaquAtUwO1B6kzxEomqJ7q5Idnns57hTxg==", "dev": true, "license": "MIT", "peerDependencies": { - "@graphql-codegen/cli": ">=1.0.0 <6.0.0", + "@graphql-codegen/cli": ">=1.0.0 <7.0.0", "graphql": ">=14.0.0 <17.0.0", "vite": ">=2.7.0 <8.0.0" } diff --git a/frontend/package.json b/frontend/package.json index ec8af886b..8cf53912b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -58,7 +58,7 @@ "@types/react": "19.1.13", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^5.0.2", + "@vitejs/plugin-react": "^5.0.3", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -76,9 +76,9 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.5", + "vite": "7.1.6", "vite-plugin-compression": "^0.5.1", - "vite-plugin-graphql-codegen": "^3.6.3", + "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", "vitest": "^3.2.4" }, From ef106ca074128c8cef6875c5f199db1d5bcc5ae7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Sep 2025 13:26:23 +0000 Subject: [PATCH 072/296] build(deps-dev): bump the graphql-codegen group Bumps the graphql-codegen group in /frontend with 2 updates: [@graphql-codegen/cli](https://github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/graphql-codegen-cli) and [@graphql-codegen/client-preset](https://github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/presets/client). Updates `@graphql-codegen/cli` from 5.0.7 to 6.0.0 - [Release notes](https://github.com/dotansimha/graphql-code-generator/releases) - [Changelog](https://github.com/dotansimha/graphql-code-generator/blob/master/packages/graphql-codegen-cli/CHANGELOG.md) - [Commits](https://github.com/dotansimha/graphql-code-generator/commits/@graphql-codegen/cli@6.0.0/packages/graphql-codegen-cli) Updates `@graphql-codegen/client-preset` from 4.8.3 to 5.0.0 - [Release notes](https://github.com/dotansimha/graphql-code-generator/releases) - [Changelog](https://github.com/dotansimha/graphql-code-generator/blob/master/packages/presets/client/CHANGELOG.md) - [Commits](https://github.com/dotansimha/graphql-code-generator/commits/@graphql-codegen/client-preset@5.0.0/packages/presets/client) --- updated-dependencies: - dependency-name: "@graphql-codegen/cli" dependency-version: 6.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: graphql-codegen - dependency-name: "@graphql-codegen/client-preset" dependency-version: 5.0.0 dependency-type: direct:development update-type: version-update:semver-major dependency-group: graphql-codegen ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 1348 ++++++++++++++++++++---------------- frontend/package.json | 4 +- 2 files changed, 765 insertions(+), 587 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dc60ee1c3..b2c1f7d90 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -33,8 +33,8 @@ "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", - "@graphql-codegen/cli": "^5.0.7", - "@graphql-codegen/client-preset": "^4.8.3", + "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/client-preset": "^5.0.1", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.6", "@storybook/react-vite": "^9.1.6", @@ -1880,15 +1880,18 @@ } }, "node_modules/@graphql-codegen/add": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.3.tgz", - "integrity": "sha512-SxXPmramkth8XtBlAHu4H4jYcYXM/o3p01+psU+0NADQowA8jtYkK6MW5rV6T+CxkEaNZItfSmZRPgIuypcqnA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-6.0.0.tgz", + "integrity": "sha512-biFdaURX0KTwEJPQ1wkT6BRgNasqgQ5KbCI1a3zwtLtO7XTo7/vKITPylmiU27K5DSOWYnY/1jfSqUAEBuhZrQ==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/plugin-helpers": "^6.0.0", "tslib": "~2.6.0" }, + "engines": { + "node": ">=16" + }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } @@ -1901,18 +1904,18 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/cli": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.7.tgz", - "integrity": "sha512-h/sxYvSaWtxZxo8GtaA8SvcHTyViaaPd7dweF/hmRDpaQU1o3iU3EZxlcJ+oLTunU0tSMFsnrIXm/mhXxI11Cw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-6.0.0.tgz", + "integrity": "sha512-tvchLVCMtorDE+UwgQbrjyaQK16GCZA+QomTxZazRx64ixtgmbEiQV7GhCBy0y0Bo7/tcTJb6sy9G/TL/BgiOg==", "dev": true, "license": "MIT", "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", "@babel/types": "^7.18.13", - "@graphql-codegen/client-preset": "^4.8.2", - "@graphql-codegen/core": "^4.0.2", - "@graphql-codegen/plugin-helpers": "^5.1.1", + "@graphql-codegen/client-preset": "^5.0.0", + "@graphql-codegen/core": "^5.0.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-tools/apollo-engine-loader": "^8.0.0", "@graphql-tools/code-file-loader": "^8.0.0", "@graphql-tools/git-loader": "^8.0.0", @@ -1920,20 +1923,19 @@ "@graphql-tools/graphql-file-loader": "^8.0.0", "@graphql-tools/json-file-loader": "^8.0.0", "@graphql-tools/load": "^8.1.0", - "@graphql-tools/prisma-loader": "^8.0.0", "@graphql-tools/url-loader": "^8.0.0", "@graphql-tools/utils": "^10.0.0", + "@inquirer/prompts": "^7.8.2", "@whatwg-node/fetch": "^0.10.0", "chalk": "^4.1.0", - "cosmiconfig": "^8.1.3", - "debounce": "^1.2.0", + "cosmiconfig": "^9.0.0", + "debounce": "^2.0.0", "detect-indent": "^6.0.0", "graphql-config": "^5.1.1", - "inquirer": "^8.0.0", "is-glob": "^4.0.1", - "jiti": "^1.17.1", + "jiti": "^2.3.0", "json-to-pretty-yaml": "^1.2.2", - "listr2": "^4.0.5", + "listr2": "^9.0.0", "log-symbols": "^4.0.0", "micromatch": "^4.0.5", "shell-quote": "^1.7.3", @@ -1962,22 +1964,66 @@ } } }, + "node_modules/@graphql-codegen/cli/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@graphql-codegen/cli/node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@graphql-codegen/cli/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true, + "license": "0BSD" + }, "node_modules/@graphql-codegen/client-preset": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.8.3.tgz", - "integrity": "sha512-QpEsPSO9fnRxA6Z66AmBuGcwHjZ6dYSxYo5ycMlYgSPzAbyG8gn/kWljofjJfWqSY+T/lRn+r8IXTH14ml24vQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.0.1.tgz", + "integrity": "sha512-3dXS7Sh/AkV+Ewq/HB1DSCb0tZBOIdTL8zkGQjRKWaf14x21h2f/xKl2zhRh6KlXjcCrIpX+AxHAhQxs6cXwVw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", - "@graphql-codegen/add": "^5.0.3", - "@graphql-codegen/gql-tag-operations": "4.0.17", - "@graphql-codegen/plugin-helpers": "^5.1.1", - "@graphql-codegen/typed-document-node": "^5.1.2", - "@graphql-codegen/typescript": "^4.1.6", - "@graphql-codegen/typescript-operations": "^4.6.1", - "@graphql-codegen/visitor-plugin-common": "^5.8.0", + "@graphql-codegen/add": "^6.0.0", + "@graphql-codegen/gql-tag-operations": "5.0.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", + "@graphql-codegen/typed-document-node": "^6.0.0", + "@graphql-codegen/typescript": "^5.0.0", + "@graphql-codegen/typescript-operations": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "^6.0.0", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -2004,17 +2050,20 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/core": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.2.tgz", - "integrity": "sha512-IZbpkhwVqgizcjNiaVzNAzm/xbWT6YnGgeOLwVjm4KbJn3V2jchVtuzHH09G5/WkkLSk2wgbXNdwjM41JxO6Eg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-5.0.0.tgz", + "integrity": "sha512-vLTEW0m8LbE4xgRwbFwCdYxVkJ1dBlVJbQyLb9Q7bHnVFgHAP982Xo8Uv7FuPBmON+2IbTjkCqhFLHVZbqpvjQ==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-tools/schema": "^10.0.0", "@graphql-tools/utils": "^10.0.0", "tslib": "~2.6.0" }, + "engines": { + "node": ">=16" + }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } @@ -2027,14 +2076,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.17.tgz", - "integrity": "sha512-2pnvPdIG6W9OuxkrEZ6hvZd142+O3B13lvhrZ48yyEBh2ujtmKokw0eTwDHtlXUqjVS0I3q7+HB2y12G/m69CA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.0.0.tgz", + "integrity": "sha512-kC2pc/tyzVc1laZtlfuQHqYxF4UqB4YXzAboFfeY1cxrxCh/+H70jHnfA1O4vhPndiRd+XZA8wxPv0hIqDXYaA==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.0", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" @@ -2054,9 +2103,9 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/plugin-helpers": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.1.1.tgz", - "integrity": "sha512-28GHODK2HY1NhdyRcPP3sCz0Kqxyfiz7boIZ8qIxFYmpLYnlDgiYok5fhFLVSZihyOpCs4Fa37gVHf/Q4I2FEg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-6.0.0.tgz", + "integrity": "sha512-Z7P89vViJvQakRyMbq/JF2iPLruRFOwOB6IXsuSvV/BptuuEd7fsGPuEf8bdjjDxUY0pJZnFN8oC7jIQ8p9GKA==", "dev": true, "license": "MIT", "dependencies": { @@ -2082,16 +2131,19 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/schema-ast": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-4.1.0.tgz", - "integrity": "sha512-kZVn0z+th9SvqxfKYgztA6PM7mhnSZaj4fiuBWvMTqA+QqQ9BBed6Pz41KuD/jr0gJtnlr2A4++/0VlpVbCTmQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-5.0.0.tgz", + "integrity": "sha512-jn7Q3PKQc0FxXjbpo9trxzlz/GSFQWxL042l0iC8iSbM/Ar+M7uyBwMtXPsev/3Razk+osQyreghIz0d2+6F7Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.0.3", + "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-tools/utils": "^10.0.0", "tslib": "~2.6.0" }, + "engines": { + "node": ">=16" + }, "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } @@ -2104,14 +2156,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.1.2.tgz", - "integrity": "sha512-jaxfViDqFRbNQmfKwUY8hDyjnLTw2Z7DhGutxoOiiAI0gE/LfPe0LYaVFKVmVOOD7M3bWxoWfu4slrkbWbUbEw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.0.0.tgz", + "integrity": "sha512-OYmbadwvjq19yCZjioy901pLI9YV6i7A0fP3MpcJlo2uQVY27RJPcN2NeLfFzXdHr6f5bm9exqB6X1iKimfA2Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -2131,15 +2183,15 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.6.tgz", - "integrity": "sha512-vpw3sfwf9A7S+kIUjyFxuvrywGxd4lmwmyYnnDVjVE4kSQ6Td3DpqaPTy8aNQ6O96vFoi/bxbZS2BW49PwSUUA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.0.tgz", + "integrity": "sha512-u90SGM6+Rdc3Je1EmVQOrGk5fl7hK1cLR4y5Q1MeUenj0aZFxKno65DCW7RcQpcfebvkPsVGA6y3oS02wPFj6Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/schema-ast": "^4.0.2", - "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", + "@graphql-codegen/schema-ast": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2468,15 +2520,15 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.6.1.tgz", - "integrity": "sha512-k92laxhih7s0WZ8j5WMIbgKwhe64C0As6x+PdcvgZFMudDJ7rPJ/hFqJ9DCRxNjXoHmSjnr6VUuQZq4lT1RzCA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.0.tgz", + "integrity": "sha512-mqgp/lp5v7w+RYj5AJ/BVquP+sgje3EAgg++62ciolOB5zzWT8en09cRdNq4UZfszCYTOtlhCG7NQAAcSae37A==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/typescript": "^4.1.6", - "@graphql-codegen/visitor-plugin-common": "5.8.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", + "@graphql-codegen/typescript": "^5.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2508,19 +2560,19 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.8.0.tgz", - "integrity": "sha512-lC1E1Kmuzi3WZUlYlqB4fP6+CvbKH9J+haU1iWmgsBx5/sO2ROeXJG4Dmt8gP03bI2BwjiwV5WxCEMlyeuzLnA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.0.0.tgz", + "integrity": "sha512-K05Jv2elOeFstH3i+Ah0Pi9do6NYUvrbdhEkP+UvP9fmIro1hCKwcIEP7j4VFz8mt3gAC3dB5KVJDoyaPUgi4Q==", "dev": true, "license": "MIT", "dependencies": { - "@graphql-codegen/plugin-helpers": "^5.1.0", + "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-tools/optimize": "^2.0.0", "@graphql-tools/relay-operation-optimizer": "^7.0.0", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", - "dependency-graph": "^0.11.0", + "dependency-graph": "^1.0.0", "graphql-tag": "^2.11.0", "parse-filepath": "^1.0.2", "tslib": "~2.6.0" @@ -2532,6 +2584,16 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/dependency-graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -2944,37 +3006,6 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/prisma-loader": { - "version": "8.0.17", - "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.17.tgz", - "integrity": "sha512-fnuTLeQhqRbA156pAyzJYN0KxCjKYRU5bz1q/SKOwElSnAU4k7/G1kyVsWLh7fneY78LoMNH5n+KlFV8iQlnyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-tools/url-loader": "^8.0.15", - "@graphql-tools/utils": "^10.5.6", - "@types/js-yaml": "^4.0.0", - "@whatwg-node/fetch": "^0.10.0", - "chalk": "^4.1.0", - "debug": "^4.3.1", - "dotenv": "^16.0.0", - "graphql-request": "^6.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "jose": "^5.0.0", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "scuid": "^1.1.0", - "tslib": "^2.4.0", - "yaml-ast-parser": "^0.0.43" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/@graphql-tools/relay-operation-optimizer": { "version": "7.0.21", "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.21.tgz", @@ -3101,14 +3132,49 @@ "node": ">=10.13.0" } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", - "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", + "node_modules/@inquirer/ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz", + "integrity": "sha512-JWaTfCxI1eTmJ1BIv86vUfjVatOdxwD0DAVKYevY8SazeUUZtW+tNbsdejVO1GYE0GXJW1N1ahmiC3TFd+7wZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.4.tgz", + "integrity": "sha512-2n9Vgf4HSciFq8ttKXk+qy+GsyTXPV1An6QAwe/8bkbbqvG4VW1I/ZY1pNu2rf+h9bdzMLPbRSfcNxkHBy/Ydw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.18.tgz", + "integrity": "sha512-MilmWOzHa3Ks11tzvuAmFoAd/wRuaP3SwlT1IZhyMke31FKLxPiuDWcGXhU+PKveNOpAc4axzAgrgxuIJJRmLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", "@inquirer/type": "^3.0.8" }, "engines": { @@ -3124,15 +3190,15 @@ } }, "node_modules/@inquirer/core": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", - "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.2.tgz", + "integrity": "sha512-yXq/4QUnk4sHMtmbd7irwiepjB8jXU0kkFRL4nr/aDBA2mDz13cMakEWdDwX3eSCTkk03kwcndD1zfRAIlELxA==", "dev": true, "license": "MIT", "dependencies": { + "@inquirer/ansi": "^1.0.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", @@ -3151,35 +3217,16 @@ } } }, - "node_modules/@inquirer/core/node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/@inquirer/core/node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", - "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "node_modules/@inquirer/editor": { + "version": "4.2.20", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.20.tgz", + "integrity": "sha512-7omh5y5bK672Q+Brk4HBbnHNowOZwrb/78IFXdrEB9PfdxL3GudQyDk8O9vQ188wj3xrEebS2M9n18BjJoI83g==", "dev": true, "license": "MIT", "dependencies": { - "chardet": "^2.1.0", - "iconv-lite": "^0.6.3" + "@inquirer/core": "^10.2.2", + "@inquirer/external-editor": "^1.0.2", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -3193,6 +3240,68 @@ } } }, + "node_modules/@inquirer/expand": { + "version": "4.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.20.tgz", + "integrity": "sha512-Dt9S+6qUg94fEvgn54F2Syf0Z3U8xmnBI9ATq2f5h9xt09fs2IJXSCIXyyVHwvggKWFXEY/7jATRo2K6Dkn6Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", + "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@inquirer/figures": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", @@ -3203,6 +3312,175 @@ "node": ">=18" } }, + "node_modules/@inquirer/input": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.4.tgz", + "integrity": "sha512-cwSGpLBMwpwcZZsc6s1gThm0J+it/KIJ+1qFL2euLmSKUMGumJ5TcbMgxEjMjNHRGadouIYbiIgruKoDZk7klw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.20.tgz", + "integrity": "sha512-bbooay64VD1Z6uMfNehED2A2YOPHSJnQLs9/4WNiV/EK+vXczf/R988itL2XLDGTgmhMF2KkiWZo+iEZmc4jqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.20", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.20.tgz", + "integrity": "sha512-nxSaPV2cPvvoOmRygQR+h0B+Av73B01cqYLcr7NXcGXhbmsYfUb8fDdw2Us1bI2YsX+VvY7I7upgFYsyf8+Nug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.8.6", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.6.tgz", + "integrity": "sha512-68JhkiojicX9SBUD8FE/pSKbOKtwoyaVj1kwqLfvjlVXZvOy3iaSWX4dCLsZyYx/5Ur07Fq+yuDNOen+5ce6ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.2.4", + "@inquirer/confirm": "^5.1.18", + "@inquirer/editor": "^4.2.20", + "@inquirer/expand": "^4.0.20", + "@inquirer/input": "^4.2.4", + "@inquirer/number": "^3.0.20", + "@inquirer/password": "^4.0.20", + "@inquirer/rawlist": "^4.1.8", + "@inquirer/search": "^3.1.3", + "@inquirer/select": "^4.3.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.8.tgz", + "integrity": "sha512-CQ2VkIASbgI2PxdzlkeeieLRmniaUU1Aoi5ggEdm6BIyqopE9GuDXdDOj9XiwOqK5qm72oI2i6J+Gnjaa26ejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.3.tgz", + "integrity": "sha512-D5T6ioybJJH0IiSUK/JXcoRrrm8sXwzrVMjibuPs+AgxmogKslaafy1oxFiorNI4s3ElSkeQZbhYQgLqiL8h6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.4.tgz", + "integrity": "sha512-Qp20nySRmfbuJBBsgPU7E/cL62Hf250vMZRzYDcBHty2zdD1kKCnoDFWRr0WO2ZzaXp3R7a4esaVGJUx0E6zvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.0", + "@inquirer/core": "^10.2.2", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@inquirer/type": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", @@ -5575,13 +5853,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/mdx": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", @@ -5983,41 +6254,17 @@ "node": ">=0.4.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.0.tgz", + "integrity": "sha512-YdhtCd19sKRKfAAUsrcC1wzm4JuzJoiX4pOJqIoW2qmKj5WzG/dL8uUJ0361zaXtHqK7gEhOwtAtz7t3Yq3X5g==", "dev": true, "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "environment": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6198,16 +6445,6 @@ "dev": true, "license": "MIT" }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/auto-bind": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-4.0.0.tgz", @@ -6405,18 +6642,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -6659,31 +6884,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -6944,67 +7144,93 @@ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", "license": "MIT" }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.0.tgz", + "integrity": "sha512-7JDGG+4Zp0CsknDCedl0DYdaeOhc46QNpXi3NLQblkZpXXgA6LncLDUUyvrjSvZeF3VRQa+KiMGomazQrC1V8g==", "dev": true, "license": "MIT", "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" }, "engines": { - "node": ">=8" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "license": "ISC", "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/cliui": { @@ -7316,11 +7542,17 @@ } }, "node_modules/debounce": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-2.2.0.tgz", + "integrity": "sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/debug": { "version": "4.4.1", @@ -7360,29 +7592,6 @@ "node": ">=6" } }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defaults/node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -7557,19 +7766,6 @@ "tslib": "^2.0.3" } }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/dset": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", @@ -7635,6 +7831,29 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eol": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/eol/-/eol-0.9.1.tgz", @@ -7724,16 +7943,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -7765,6 +7974,13 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -7903,22 +8119,6 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -8157,6 +8357,19 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-nonce": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", @@ -8336,20 +8549,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/graphql-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", - "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@graphql-typed-document-node/core": "^3.2.0", - "cross-fetch": "^3.1.5" - }, - "peerDependencies": { - "graphql": "14 - 16" - } - }, "node_modules/graphql-tag": { "version": "2.12.6", "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", @@ -8574,34 +8773,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/i18next": { "version": "25.5.2", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.2.tgz", @@ -8855,33 +9026,6 @@ "dev": true, "license": "ISC" }, - "node_modules/inquirer": { - "version": "8.2.7", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz", - "integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/external-editor": "^1.0.0", - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -8991,16 +9135,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", @@ -9246,16 +9380,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/jose": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", - "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9420,46 +9544,103 @@ "license": "MIT" }, "node_modules/listr2": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", - "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.4.tgz", + "integrity": "sha512-1wd/kpAdKRLwv7/3OKC8zZ5U8e/fajCfWMxacUvB79S5nLrYGPtUI/8chMQhn3LQjsRVErTb9i1ECAwW0ZIHnQ==", "dev": true, "license": "MIT", "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.5", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" }, "engines": { "node": ">=12" }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/listr2/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9513,40 +9694,108 @@ } }, "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/loose-envify": { @@ -9777,14 +10026,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/min-indent": { @@ -9923,11 +10175,14 @@ } }, "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, "node_modules/mz": { "version": "2.7.0", @@ -10127,16 +10382,16 @@ } }, "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-function": "^5.0.0" }, "engines": { - "node": ">=6" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -10160,30 +10415,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/outvariant": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", @@ -10287,22 +10518,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -11365,26 +11580,22 @@ } }, "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/rettime": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/rettime/-/rettime-0.7.0.tgz", @@ -11564,16 +11775,6 @@ "node": "6.* || >= 7.*" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11598,16 +11799,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -11642,13 +11833,6 @@ "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "license": "MIT" }, - "node_modules/scuid": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", - "integrity": "sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==", - "dev": true, - "license": "MIT" - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -11780,18 +11964,49 @@ } }, "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/smol-toml": { @@ -12425,13 +12640,6 @@ "node": ">=0.8" } }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, - "license": "MIT" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -12700,19 +12908,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", @@ -13402,16 +13597,6 @@ "node": "20 || >=22" } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -13613,13 +13798,6 @@ "node": ">= 14.6" } }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 8cf53912b..59928fad8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -43,8 +43,8 @@ "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", - "@graphql-codegen/cli": "^5.0.7", - "@graphql-codegen/client-preset": "^4.8.3", + "@graphql-codegen/cli": "^6.0.0", + "@graphql-codegen/client-preset": "^5.0.1", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.6", "@storybook/react-vite": "^9.1.6", From 0057d5bd3377b2626429d16b957ff33b1ff89e54 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 18 Sep 2025 15:38:39 +0200 Subject: [PATCH 073/296] Update generate GraphQL types --- frontend/src/gql/graphql.ts | 133 +++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 41 deletions(-) diff --git a/frontend/src/gql/graphql.ts b/frontend/src/gql/graphql.ts index b6f357170..583ebfc5d 100644 --- a/frontend/src/gql/graphql.ts +++ b/frontend/src/gql/graphql.ts @@ -2,7 +2,7 @@ import type { DocumentTypeDecoration } from '@graphql-typed-document-node/core'; import { graphql, type GraphQLResponseResolver, type RequestHandlerOptions } from 'msw' export type Maybe = T | null; -export type InputMaybe = Maybe; +export type InputMaybe = T | null | undefined; export type Exact = { [K in keyof T]: T[K] }; export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; @@ -1838,10 +1838,13 @@ export type UserEmailListQueryVariables = Exact<{ }>; -export type UserEmailListQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | { __typename: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number, edges: Array<{ __typename?: 'UserEmailEdge', cursor: string, node: ( - { __typename?: 'UserEmail' } - & { ' $fragmentRefs'?: { 'UserEmail_EmailFragment': UserEmail_EmailFragment } } - ) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } }; +export type UserEmailListQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous' } + | { __typename: 'User', emails: { __typename?: 'UserEmailConnection', totalCount: number, edges: Array<{ __typename?: 'UserEmailEdge', cursor: string, node: ( + { __typename?: 'UserEmail' } + & { ' $fragmentRefs'?: { 'UserEmail_EmailFragment': UserEmail_EmailFragment } } + ) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } + }; export type UserEmailList_UserFragment = { __typename?: 'User', hasPassword: boolean } & { ' $fragmentName'?: 'UserEmailList_UserFragment' }; @@ -1852,10 +1855,14 @@ export type BrowserSessionsOverview_UserFragment = { __typename?: 'User', id: st export type UserProfileQueryVariables = Exact<{ [key: string]: never; }>; -export type UserProfileQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: ( - { __typename?: 'User', hasPassword: boolean, emails: { __typename?: 'UserEmailConnection', totalCount: number } } - & { ' $fragmentRefs'?: { 'AddEmailForm_UserFragment': AddEmailForm_UserFragment;'UserEmailList_UserFragment': UserEmailList_UserFragment;'AccountDeleteButton_UserFragment': AccountDeleteButton_UserFragment } } - ) } | { __typename: 'Oauth2Session' }, siteConfig: ( +export type UserProfileQuery = { __typename?: 'Query', viewerSession: + | { __typename: 'Anonymous' } + | { __typename: 'BrowserSession', id: string, user: ( + { __typename?: 'User', hasPassword: boolean, emails: { __typename?: 'UserEmailConnection', totalCount: number } } + & { ' $fragmentRefs'?: { 'AddEmailForm_UserFragment': AddEmailForm_UserFragment;'UserEmailList_UserFragment': UserEmailList_UserFragment;'AccountDeleteButton_UserFragment': AccountDeleteButton_UserFragment } } + ) } + | { __typename: 'Oauth2Session' } + , siteConfig: ( { __typename?: 'SiteConfig', emailChangeAllowed: boolean, passwordLoginEnabled: boolean, accountDeactivationAllowed: boolean } & { ' $fragmentRefs'?: { 'AddEmailForm_SiteConfigFragment': AddEmailForm_SiteConfigFragment;'UserEmailList_SiteConfigFragment': UserEmailList_SiteConfigFragment;'PasswordChange_SiteConfigFragment': PasswordChange_SiteConfigFragment;'AccountDeleteButton_SiteConfigFragment': AccountDeleteButton_SiteConfigFragment } } ) }; @@ -1874,18 +1881,25 @@ export type BrowserSessionListQueryVariables = Exact<{ }>; -export type BrowserSessionListQuery = { __typename?: 'Query', viewerSession: { __typename: 'Anonymous' } | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', id: string, browserSessions: { __typename?: 'BrowserSessionConnection', totalCount: number, edges: Array<{ __typename?: 'BrowserSessionEdge', cursor: string, node: ( - { __typename?: 'BrowserSession', id: string } - & { ' $fragmentRefs'?: { 'BrowserSession_SessionFragment': BrowserSession_SessionFragment } } - ) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } | { __typename: 'Oauth2Session' } }; +export type BrowserSessionListQuery = { __typename?: 'Query', viewerSession: + | { __typename: 'Anonymous' } + | { __typename: 'BrowserSession', id: string, user: { __typename?: 'User', id: string, browserSessions: { __typename?: 'BrowserSessionConnection', totalCount: number, edges: Array<{ __typename?: 'BrowserSessionEdge', cursor: string, node: ( + { __typename?: 'BrowserSession', id: string } + & { ' $fragmentRefs'?: { 'BrowserSession_SessionFragment': BrowserSession_SessionFragment } } + ) }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } + | { __typename: 'Oauth2Session' } + }; export type SessionsOverviewQueryVariables = Exact<{ [key: string]: never; }>; -export type SessionsOverviewQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | ( - { __typename: 'User', id: string } - & { ' $fragmentRefs'?: { 'BrowserSessionsOverview_UserFragment': BrowserSessionsOverview_UserFragment } } - ) }; +export type SessionsOverviewQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous' } + | ( + { __typename: 'User', id: string } + & { ' $fragmentRefs'?: { 'BrowserSessionsOverview_UserFragment': BrowserSessionsOverview_UserFragment } } + ) + }; export type AppSessionsListQueryVariables = Exact<{ before?: InputMaybe; @@ -1896,21 +1910,30 @@ export type AppSessionsListQueryVariables = Exact<{ }>; -export type AppSessionsListQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | { __typename: 'User', id: string, appSessions: { __typename?: 'AppSessionConnection', totalCount: number, edges: Array<{ __typename?: 'AppSessionEdge', cursor: string, node: ( - { __typename: 'CompatSession' } - & { ' $fragmentRefs'?: { 'CompatSession_SessionFragment': CompatSession_SessionFragment } } - ) | ( - { __typename: 'Oauth2Session' } - & { ' $fragmentRefs'?: { 'OAuth2Session_SessionFragment': OAuth2Session_SessionFragment } } - ) }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } } }; +export type AppSessionsListQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous' } + | { __typename: 'User', id: string, appSessions: { __typename?: 'AppSessionConnection', totalCount: number, edges: Array<{ __typename?: 'AppSessionEdge', cursor: string, node: + | ( + { __typename: 'CompatSession' } + & { ' $fragmentRefs'?: { 'CompatSession_SessionFragment': CompatSession_SessionFragment } } + ) + | ( + { __typename: 'Oauth2Session' } + & { ' $fragmentRefs'?: { 'OAuth2Session_SessionFragment': OAuth2Session_SessionFragment } } + ) + }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } } + }; export type CurrentUserGreetingQueryVariables = Exact<{ [key: string]: never; }>; -export type CurrentUserGreetingQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous' } | ( - { __typename: 'User' } - & { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } } - ), siteConfig: ( +export type CurrentUserGreetingQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous' } + | ( + { __typename: 'User' } + & { ' $fragmentRefs'?: { 'UserGreeting_UserFragment': UserGreeting_UserFragment } } + ) + , siteConfig: ( { __typename?: 'SiteConfig', planManagementIframeUri?: string | null } & { ' $fragmentRefs'?: { 'UserGreeting_SiteConfigFragment': UserGreeting_SiteConfigFragment } } ) }; @@ -1928,7 +1951,10 @@ export type OAuth2ClientQuery = { __typename?: 'Query', oauth2Client?: ( export type CurrentViewerQueryVariables = Exact<{ [key: string]: never; }>; -export type CurrentViewerQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous', id: string } | { __typename: 'User', id: string } }; +export type CurrentViewerQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous', id: string } + | { __typename: 'User', id: string } + }; export type DeviceRedirectQueryVariables = Exact<{ deviceId: Scalars['String']['input']; @@ -1936,7 +1962,10 @@ export type DeviceRedirectQueryVariables = Exact<{ }>; -export type DeviceRedirectQuery = { __typename?: 'Query', session?: { __typename: 'CompatSession', id: string } | { __typename: 'Oauth2Session', id: string } | null }; +export type DeviceRedirectQuery = { __typename?: 'Query', session?: + | { __typename: 'CompatSession', id: string } + | { __typename: 'Oauth2Session', id: string } + | null }; export type VerifyEmailQueryVariables = Exact<{ id: Scalars['ID']['input']; @@ -1973,7 +2002,10 @@ export type ChangePasswordMutation = { __typename?: 'Mutation', setPassword: { _ export type PasswordChangeQueryVariables = Exact<{ [key: string]: never; }>; -export type PasswordChangeQuery = { __typename?: 'Query', viewer: { __typename: 'Anonymous', id: string } | { __typename: 'User', id: string }, siteConfig: ( +export type PasswordChangeQuery = { __typename?: 'Query', viewer: + | { __typename: 'Anonymous', id: string } + | { __typename: 'User', id: string } + , siteConfig: ( { __typename?: 'SiteConfig' } & { ' $fragmentRefs'?: { 'PasswordCreationDoubleInput_SiteConfigFragment': PasswordCreationDoubleInput_SiteConfigFragment } } ) }; @@ -2025,16 +2057,35 @@ export type SessionDetailQueryVariables = Exact<{ }>; -export type SessionDetailQuery = { __typename?: 'Query', viewerSession: { __typename?: 'Anonymous', id: string } | { __typename?: 'BrowserSession', id: string } | { __typename?: 'Oauth2Session', id: string }, node?: { __typename: 'Anonymous', id: string } | { __typename: 'Authentication', id: string } | ( - { __typename: 'BrowserSession', id: string } - & { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } } - ) | ( - { __typename: 'CompatSession', id: string } - & { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } } - ) | { __typename: 'CompatSsoLogin', id: string } | { __typename: 'Oauth2Client', id: string } | ( - { __typename: 'Oauth2Session', id: string } - & { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } } - ) | { __typename: 'SiteConfig', id: string } | { __typename: 'UpstreamOAuth2Link', id: string } | { __typename: 'UpstreamOAuth2Provider', id: string } | { __typename: 'User', id: string } | { __typename: 'UserEmail', id: string } | { __typename: 'UserEmailAuthentication', id: string } | { __typename: 'UserRecoveryTicket', id: string } | null }; +export type SessionDetailQuery = { __typename?: 'Query', viewerSession: + | { __typename?: 'Anonymous', id: string } + | { __typename?: 'BrowserSession', id: string } + | { __typename?: 'Oauth2Session', id: string } + , node?: + | { __typename: 'Anonymous', id: string } + | { __typename: 'Authentication', id: string } + | ( + { __typename: 'BrowserSession', id: string } + & { ' $fragmentRefs'?: { 'BrowserSession_DetailFragment': BrowserSession_DetailFragment } } + ) + | ( + { __typename: 'CompatSession', id: string } + & { ' $fragmentRefs'?: { 'CompatSession_DetailFragment': CompatSession_DetailFragment } } + ) + | { __typename: 'CompatSsoLogin', id: string } + | { __typename: 'Oauth2Client', id: string } + | ( + { __typename: 'Oauth2Session', id: string } + & { ' $fragmentRefs'?: { 'OAuth2Session_DetailFragment': OAuth2Session_DetailFragment } } + ) + | { __typename: 'SiteConfig', id: string } + | { __typename: 'UpstreamOAuth2Link', id: string } + | { __typename: 'UpstreamOAuth2Provider', id: string } + | { __typename: 'User', id: string } + | { __typename: 'UserEmail', id: string } + | { __typename: 'UserEmailAuthentication', id: string } + | { __typename: 'UserRecoveryTicket', id: string } + | null }; export class TypedDocumentString extends String From c1c76177bd51a297bf1db3e3cae662b5692ffbd2 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 19 Sep 2025 11:12:48 +0200 Subject: [PATCH 074/296] Admin API to list upstream OAuth 2.0 providers --- crates/handlers/src/admin/mod.rs | 5 + crates/handlers/src/admin/model.rs | 76 +++ crates/handlers/src/admin/v1/mod.rs | 8 + .../admin/v1/upstream_oauth_providers/list.rs | 554 ++++++++++++++++++ .../admin/v1/upstream_oauth_providers/mod.rs | 8 + docs/api/spec.json | 240 ++++++++ 6 files changed, 891 insertions(+) create mode 100644 crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs create mode 100644 crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs diff --git a/crates/handlers/src/admin/mod.rs b/crates/handlers/src/admin/mod.rs index 2670d35ab..e5e158be3 100644 --- a/crates/handlers/src/admin/mod.rs +++ b/crates/handlers/src/admin/mod.rs @@ -91,6 +91,11 @@ fn finish(t: TransformOpenApi) -> TransformOpenApi { ), ..Default::default() }) + .tag(Tag { + name: "upstream-oauth-provider".to_owned(), + description: Some("Manage upstream OAuth 2.0 providers".to_owned()), + ..Tag::default() + }) .security_scheme("oauth2", oauth_security_scheme(None)) .security_scheme( "token", diff --git a/crates/handlers/src/admin/model.rs b/crates/handlers/src/admin/model.rs index 2f6648402..c21e22fd7 100644 --- a/crates/handlers/src/admin/model.rs +++ b/crates/handlers/src/admin/model.rs @@ -695,3 +695,79 @@ impl UserRegistrationToken { ] } } + +/// An upstream OAuth 2.0 provider +#[derive(Serialize, JsonSchema)] +pub struct UpstreamOAuthProvider { + #[serde(skip)] + id: Ulid, + + /// The OIDC issuer of the provider + issuer: Option, + + /// A human-readable name for the provider + human_name: Option, + + /// A brand identifier, e.g. "apple" or "google" + brand_name: Option, + + /// When the provider was created + created_at: DateTime, + + /// When the provider was disabled. If null, the provider is enabled. + disabled_at: Option>, +} + +impl From for UpstreamOAuthProvider { + fn from(provider: mas_data_model::UpstreamOAuthProvider) -> Self { + Self { + id: provider.id, + issuer: provider.issuer, + human_name: provider.human_name, + brand_name: provider.brand_name, + created_at: provider.created_at, + disabled_at: provider.disabled_at, + } + } +} + +impl Resource for UpstreamOAuthProvider { + const KIND: &'static str = "upstream-oauth-provider"; + const PATH: &'static str = "/api/admin/v1/upstream-oauth-providers"; + + fn id(&self) -> Ulid { + self.id + } +} + +impl UpstreamOAuthProvider { + /// Samples of upstream OAuth 2.0 providers + pub fn samples() -> [Self; 3] { + [ + Self { + id: Ulid::from_bytes([0x01; 16]), + issuer: Some("https://accounts.google.com".to_owned()), + human_name: Some("Google".to_owned()), + brand_name: Some("google".to_owned()), + created_at: DateTime::default(), + disabled_at: None, + }, + Self { + id: Ulid::from_bytes([0x02; 16]), + issuer: Some("https://appleid.apple.com".to_owned()), + human_name: Some("Apple ID".to_owned()), + brand_name: Some("apple".to_owned()), + created_at: DateTime::default(), + disabled_at: Some(DateTime::default()), + }, + Self { + id: Ulid::from_bytes([0x03; 16]), + issuer: None, + human_name: Some("Custom OAuth Provider".to_owned()), + brand_name: None, + created_at: DateTime::default(), + disabled_at: None, + }, + ] + } +} diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index afe71a05f..8a182bf2f 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -23,6 +23,7 @@ mod oauth2_sessions; mod policy_data; mod site_config; mod upstream_oauth_links; +mod upstream_oauth_providers; mod user_emails; mod user_registration_tokens; mod user_sessions; @@ -187,4 +188,11 @@ where self::upstream_oauth_links::delete_doc, ), ) + .api_route( + "/upstream-oauth-providers", + get_with( + self::upstream_oauth_providers::list, + self::upstream_oauth_providers::list_doc, + ), + ) } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs new file mode 100644 index 000000000..dc5f2cc9c --- /dev/null +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -0,0 +1,554 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::{OperationIo, transform::TransformOperation}; +use axum::{ + Json, + extract::{Query, rejection::QueryRejection}, + response::IntoResponse, +}; +use axum_macros::FromRequestParts; +use hyper::StatusCode; +use mas_axum_utils::record_error; +use mas_storage::{Page, upstream_oauth2::UpstreamOAuthProviderFilter}; +use schemars::JsonSchema; +use serde::Deserialize; + +use crate::{ + admin::{ + call_context::CallContext, + model::{Resource, UpstreamOAuthProvider}, + params::Pagination, + response::{ErrorResponse, PaginatedResponse}, + }, + impl_from_error_for_route, +}; + +#[derive(FromRequestParts, Deserialize, JsonSchema, OperationIo)] +#[serde(rename = "UpstreamOAuthProviderFilter")] +#[aide(input_with = "Query")] +#[from_request(via(Query), rejection(RouteError))] +pub struct FilterParams { + /// Retrieve providers that are (or are not) enabled + #[serde(rename = "filter[enabled]")] + enabled: Option, +} + +impl std::fmt::Display for FilterParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut sep = '?'; + + if let Some(enabled) = self.enabled { + write!(f, "{sep}filter[enabled]={enabled}")?; + sep = '&'; + } + + let _ = sep; + Ok(()) + } +} + +#[derive(Debug, thiserror::Error, OperationIo)] +#[aide(output_with = "Json")] +pub enum RouteError { + #[error(transparent)] + Internal(Box), + + #[error("Invalid filter parameters")] + InvalidFilter(#[from] QueryRejection), +} + +impl_from_error_for_route!(mas_storage::RepositoryError); + +impl IntoResponse for RouteError { + fn into_response(self) -> axum::response::Response { + let error = ErrorResponse::from_error(&self); + let sentry_event_id = record_error!(self, Self::Internal(_)); + let status = match self { + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::InvalidFilter(_) => StatusCode::BAD_REQUEST, + }; + + (status, sentry_event_id, Json(error)).into_response() + } +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("listUpstreamOAuthProviders") + .summary("List upstream OAuth 2.0 providers") + .tag("upstream-oauth-provider") + .response_with::<200, Json>, _>(|t| { + let providers = UpstreamOAuthProvider::samples(); + let pagination = mas_storage::Pagination::first(providers.len()); + let page = Page { + edges: providers.into(), + has_next_page: true, + has_previous_page: false, + }; + + t.description("Paginated response of upstream OAuth 2.0 providers") + .example(PaginatedResponse::new( + page, + pagination, + 42, + UpstreamOAuthProvider::PATH, + )) + }) +} + +#[tracing::instrument(name = "handler.admin.v1.upstream_oauth_providers.list", skip_all)] +pub async fn handler( + CallContext { mut repo, .. }: CallContext, + Pagination(pagination): Pagination, + params: FilterParams, +) -> Result>, RouteError> { + let base = format!("{path}{params}", path = UpstreamOAuthProvider::PATH); + let filter = UpstreamOAuthProviderFilter::new(); + + let filter = match params.enabled { + Some(true) => filter.enabled_only(), + Some(false) => filter.disabled_only(), + None => filter, + }; + + let page = repo + .upstream_oauth_provider() + .list(filter, pagination) + .await?; + let count = repo.upstream_oauth_provider().count(filter).await?; + + Ok(Json(PaginatedResponse::new( + page.map(UpstreamOAuthProvider::from), + pagination, + count, + &base, + ))) +} + +#[cfg(test)] +mod tests { + use hyper::{Request, StatusCode}; + use mas_data_model::{ + UpstreamOAuthProviderClaimsImports, UpstreamOAuthProviderDiscoveryMode, + UpstreamOAuthProviderOnBackchannelLogout, UpstreamOAuthProviderPkceMode, + UpstreamOAuthProviderTokenAuthMethod, + }; + use mas_iana::jose::JsonWebSignatureAlg; + use mas_storage::{ + RepositoryAccess, + upstream_oauth2::{UpstreamOAuthProviderParams, UpstreamOAuthProviderRepository}, + }; + use oauth2_types::scope::{OPENID, Scope}; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + async fn create_test_providers(state: &mut TestState) { + let mut repo = state.repository().await.unwrap(); + + // Create an enabled provider + let enabled_params = UpstreamOAuthProviderParams { + issuer: Some("https://accounts.google.com".to_owned()), + human_name: Some("Google".to_owned()), + brand_name: Some("google".to_owned()), + discovery_mode: UpstreamOAuthProviderDiscoveryMode::Oidc, + pkce_mode: UpstreamOAuthProviderPkceMode::Auto, + jwks_uri_override: None, + authorization_endpoint_override: None, + token_endpoint_override: None, + userinfo_endpoint_override: None, + fetch_userinfo: true, + userinfo_signed_response_alg: None, + client_id: "google-client-id".to_owned(), + encrypted_client_secret: Some("encrypted-secret".to_owned()), + token_endpoint_signing_alg: None, + token_endpoint_auth_method: UpstreamOAuthProviderTokenAuthMethod::ClientSecretPost, + id_token_signed_response_alg: JsonWebSignatureAlg::Rs256, + response_mode: None, + scope: Scope::from_iter([OPENID]), + claims_imports: UpstreamOAuthProviderClaimsImports::default(), + additional_authorization_parameters: vec![], + forward_login_hint: false, + on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + ui_order: 0, + }; + + repo.upstream_oauth_provider() + .add(&mut state.rng(), &state.clock, enabled_params) + .await + .unwrap(); + + // Create a disabled provider + let disabled_params = UpstreamOAuthProviderParams { + issuer: Some("https://appleid.apple.com".to_owned()), + human_name: Some("Apple ID".to_owned()), + brand_name: Some("apple".to_owned()), + discovery_mode: UpstreamOAuthProviderDiscoveryMode::Oidc, + pkce_mode: UpstreamOAuthProviderPkceMode::S256, + jwks_uri_override: None, + authorization_endpoint_override: None, + token_endpoint_override: None, + userinfo_endpoint_override: None, + fetch_userinfo: true, + userinfo_signed_response_alg: None, + client_id: "apple-client-id".to_owned(), + encrypted_client_secret: Some("encrypted-secret".to_owned()), + token_endpoint_signing_alg: None, + token_endpoint_auth_method: UpstreamOAuthProviderTokenAuthMethod::ClientSecretPost, + id_token_signed_response_alg: JsonWebSignatureAlg::Rs256, + response_mode: None, + scope: Scope::from_iter([OPENID]), + claims_imports: UpstreamOAuthProviderClaimsImports::default(), + additional_authorization_parameters: vec![], + forward_login_hint: false, + on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + ui_order: 1, + }; + + let disabled_provider = repo + .upstream_oauth_provider() + .add(&mut state.rng(), &state.clock, disabled_params) + .await + .unwrap(); + + // Disable the provider + repo.upstream_oauth_provider() + .disable(&state.clock, disabled_provider) + .await + .unwrap(); + + // Create another enabled provider + let another_enabled_params = UpstreamOAuthProviderParams { + issuer: Some("https://login.microsoftonline.com/common/v2.0".to_owned()), + human_name: Some("Microsoft".to_owned()), + brand_name: Some("microsoft".to_owned()), + discovery_mode: UpstreamOAuthProviderDiscoveryMode::Oidc, + pkce_mode: UpstreamOAuthProviderPkceMode::Auto, + jwks_uri_override: None, + authorization_endpoint_override: None, + token_endpoint_override: None, + userinfo_endpoint_override: None, + fetch_userinfo: true, + userinfo_signed_response_alg: None, + client_id: "microsoft-client-id".to_owned(), + encrypted_client_secret: Some("encrypted-secret".to_owned()), + token_endpoint_signing_alg: None, + token_endpoint_auth_method: UpstreamOAuthProviderTokenAuthMethod::ClientSecretPost, + id_token_signed_response_alg: JsonWebSignatureAlg::Rs256, + response_mode: None, + scope: Scope::from_iter([OPENID]), + claims_imports: UpstreamOAuthProviderClaimsImports::default(), + additional_authorization_parameters: vec![], + forward_login_hint: false, + on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + ui_order: 2, + }; + + repo.upstream_oauth_provider() + .add(&mut state.rng(), &state.clock, another_enabled_params) + .await + .unwrap(); + + Box::new(repo).save().await.unwrap(); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_list_all_providers(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_providers(&mut state).await; + + let request = Request::get("/api/admin/v1/upstream-oauth-providers") + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + // Should return all providers + assert_eq!(body["data"].as_array().unwrap().len(), 3); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 3 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "issuer": "https://appleid.apple.com", + "human_name": "Apple ID", + "brand_name": "apple", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "issuer": "https://login.microsoftonline.com/common/v2.0", + "human_name": "Microsoft", + "brand_name": "microsoft", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?page[first]=10", + "first": "/api/admin/v1/upstream-oauth-providers?page[first]=10", + "last": "/api/admin/v1/upstream-oauth-providers?page[last]=10" + } + } + "#); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_filter_by_enabled_true(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_providers(&mut state).await; + + let request = Request::get("/api/admin/v1/upstream-oauth-providers?filter[enabled]=true") + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 2 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "issuer": "https://login.microsoftonline.com/common/v2.0", + "human_name": "Microsoft", + "brand_name": "microsoft", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&page[last]=10" + } + } + "#); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_filter_by_enabled_false(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_providers(&mut state).await; + + let request = Request::get("/api/admin/v1/upstream-oauth-providers?filter[enabled]=false") + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "issuer": "https://appleid.apple.com", + "human_name": "Apple ID", + "brand_name": "apple", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=false&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=false&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=false&page[last]=10" + } + } + "#); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_pagination(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_providers(&mut state).await; + + // Test first page with limit of 2 + let request = Request::get("/api/admin/v1/upstream-oauth-providers?page[first]=2") + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 3 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "issuer": "https://appleid.apple.com", + "human_name": "Apple ID", + "brand_name": "apple", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "issuer": "https://login.microsoftonline.com/common/v2.0", + "human_name": "Microsoft", + "brand_name": "microsoft", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?page[first]=2", + "first": "/api/admin/v1/upstream-oauth-providers?page[first]=2", + "last": "/api/admin/v1/upstream-oauth-providers?page[last]=2", + "next": "/api/admin/v1/upstream-oauth-providers?page[after]=01FSHN9AG09AVTNSQFMSR34AJC&page[first]=2" + } + } + "#); + + // Extract the ID of the last item for pagination + let last_item_id = body["data"][1]["id"].as_str().unwrap(); + let request = Request::get(format!( + "/api/admin/v1/upstream-oauth-providers?page[first]=2&page[after]={last_item_id}", + )) + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 3 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?page[after]=01FSHN9AG09AVTNSQFMSR34AJC&page[first]=2", + "first": "/api/admin/v1/upstream-oauth-providers?page[first]=2", + "last": "/api/admin/v1/upstream-oauth-providers?page[last]=2" + } + } + "#); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_invalid_filter(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + + let request = + Request::get("/api/admin/v1/upstream-oauth-providers?filter[enabled]=invalid") + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::BAD_REQUEST); + } +} diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs new file mode 100644 index 000000000..a04301246 --- /dev/null +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs @@ -0,0 +1,8 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +mod list; + +pub use self::list::{doc as list_doc, handler as list}; diff --git a/docs/api/spec.json b/docs/api/spec.json index 3348cf722..166436454 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -3222,6 +3222,143 @@ } } } + }, + "/api/admin/v1/upstream-oauth-providers": { + "get": { + "tags": [ + "upstream-oauth-provider" + ], + "summary": "List upstream OAuth 2.0 providers", + "operationId": "listUpstreamOAuthProviders", + "parameters": [ + { + "in": "query", + "name": "page[before]", + "description": "Retrieve the items before the given ID", + "schema": { + "description": "Retrieve the items before the given ID", + "$ref": "#/components/schemas/ULID", + "nullable": true + }, + "style": "form" + }, + { + "in": "query", + "name": "page[after]", + "description": "Retrieve the items after the given ID", + "schema": { + "description": "Retrieve the items after the given ID", + "$ref": "#/components/schemas/ULID", + "nullable": true + }, + "style": "form" + }, + { + "in": "query", + "name": "page[first]", + "description": "Retrieve the first N items", + "schema": { + "description": "Retrieve the first N items", + "type": "integer", + "format": "uint", + "minimum": 1.0, + "nullable": true + }, + "style": "form" + }, + { + "in": "query", + "name": "page[last]", + "description": "Retrieve the last N items", + "schema": { + "description": "Retrieve the last N items", + "type": "integer", + "format": "uint", + "minimum": 1.0, + "nullable": true + }, + "style": "form" + }, + { + "in": "query", + "name": "filter[enabled]", + "description": "Retrieve providers that are (or are not) enabled", + "schema": { + "description": "Retrieve providers that are (or are not) enabled", + "type": "boolean", + "nullable": true + }, + "style": "form" + } + ], + "responses": { + "200": { + "description": "Paginated response of upstream OAuth 2.0 providers", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaginatedResponse_for_UpstreamOAuthProvider" + }, + "example": { + "meta": { + "count": 42 + }, + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01040G2081040G2081040G2081", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "1970-01-01T00:00:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" + } + }, + { + "type": "upstream-oauth-provider", + "id": "02081040G2081040G2081040G2", + "attributes": { + "issuer": "https://appleid.apple.com", + "human_name": "Apple ID", + "brand_name": "apple", + "created_at": "1970-01-01T00:00:00Z", + "disabled_at": "1970-01-01T00:00:00Z" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/02081040G2081040G2081040G2" + } + }, + { + "type": "upstream-oauth-provider", + "id": "030C1G60R30C1G60R30C1G60R3", + "attributes": { + "issuer": null, + "human_name": "Custom OAuth Provider", + "brand_name": null, + "created_at": "1970-01-01T00:00:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/030C1G60R30C1G60R30C1G60R3" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?page[first]=3", + "first": "/api/admin/v1/upstream-oauth-providers?page[first]=3", + "last": "/api/admin/v1/upstream-oauth-providers?page[last]=3", + "next": "/api/admin/v1/upstream-oauth-providers?page[after]=030C1G60R30C1G60R30C1G60R3&page[first]=3" + } + } + } + } + } + } + } } }, "components": { @@ -4717,6 +4854,105 @@ "$ref": "#/components/schemas/SelfLinks" } } + }, + "UpstreamOAuthProviderFilter": { + "type": "object", + "properties": { + "filter[enabled]": { + "description": "Retrieve providers that are (or are not) enabled", + "type": "boolean", + "nullable": true + } + } + }, + "PaginatedResponse_for_UpstreamOAuthProvider": { + "description": "A top-level response with a page of resources", + "type": "object", + "required": [ + "data", + "links", + "meta" + ], + "properties": { + "meta": { + "description": "Response metadata", + "$ref": "#/components/schemas/PaginationMeta" + }, + "data": { + "description": "The list of resources", + "type": "array", + "items": { + "$ref": "#/components/schemas/SingleResource_for_UpstreamOAuthProvider" + } + }, + "links": { + "description": "Related links", + "$ref": "#/components/schemas/PaginationLinks" + } + } + }, + "SingleResource_for_UpstreamOAuthProvider": { + "description": "A single resource, with its type, ID, attributes and related links", + "type": "object", + "required": [ + "attributes", + "id", + "links", + "type" + ], + "properties": { + "type": { + "description": "The type of the resource", + "type": "string" + }, + "id": { + "description": "The ID of the resource", + "$ref": "#/components/schemas/ULID" + }, + "attributes": { + "description": "The attributes of the resource", + "$ref": "#/components/schemas/UpstreamOAuthProvider" + }, + "links": { + "description": "Related links", + "$ref": "#/components/schemas/SelfLinks" + } + } + }, + "UpstreamOAuthProvider": { + "description": "An upstream OAuth 2.0 provider", + "type": "object", + "required": [ + "created_at" + ], + "properties": { + "issuer": { + "description": "The OIDC issuer of the provider", + "type": "string", + "nullable": true + }, + "human_name": { + "description": "A human-readable name for the provider", + "type": "string", + "nullable": true + }, + "brand_name": { + "description": "A brand identifier, e.g. \"apple\" or \"google\"", + "type": "string", + "nullable": true + }, + "created_at": { + "description": "When the provider was created", + "type": "string", + "format": "date-time" + }, + "disabled_at": { + "description": "When the provider was disabled. If null, the provider is enabled.", + "type": "string", + "format": "date-time", + "nullable": true + } + } } } }, @@ -4768,6 +5004,10 @@ { "name": "upstream-oauth-link", "description": "Manage links between local users and identities from upstream OAuth 2.0 providers" + }, + { + "name": "upstream-oauth-provider", + "description": "Manage upstream OAuth 2.0 providers" } ] } From 28bb634e6ce0d7b472c95283b109ae28d3450e9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 13:17:34 +0000 Subject: [PATCH 075/296] build(deps): bump rustls from 0.23.31 to 0.23.32 Bumps [rustls](https://github.com/rustls/rustls) from 0.23.31 to 0.23.32. - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustls/rustls/compare/v/0.23.31...v/0.23.32) --- updated-dependencies: - dependency-name: rustls dependency-version: 0.23.32 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 854355da1..bbd833664 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5113,9 +5113,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", diff --git a/Cargo.toml b/Cargo.toml index 67c8e730f..9387e3e10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -521,7 +521,7 @@ version = "0.15.4" # TLS stack [workspace.dependencies.rustls] -version = "0.23.31" +version = "0.23.32" # PEM parsing for rustls [workspace.dependencies.rustls-pemfile] From 8ca2ade47bdf31e6963234f38341e667df66779b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 13:18:00 +0000 Subject: [PATCH 076/296] build(deps): bump indexmap from 2.11.3 to 2.11.4 Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.11.3 to 2.11.4. - [Changelog](https://github.com/indexmap-rs/indexmap/blob/main/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.11.3...2.11.4) --- updated-dependencies: - dependency-name: indexmap dependency-version: 2.11.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ Cargo.toml | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 854355da1..8f5046d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ dependencies = [ "bytes", "cfg-if", "http", - "indexmap 2.11.3", + "indexmap 2.11.4", "schemars 0.8.22", "serde", "serde_json", @@ -310,7 +310,7 @@ dependencies = [ "futures-timer", "futures-util", "http", - "indexmap 2.11.3", + "indexmap 2.11.4", "mime", "multer", "num-traits", @@ -362,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ecdaff7c9cffa3614a9f9999bf9ee4c3078fe3ce4d6a6e161736b56febf2de" dependencies = [ "bytes", - "indexmap 2.11.3", + "indexmap 2.11.4", "serde", "serde_json", ] @@ -2057,7 +2057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator", - "indexmap 2.11.3", + "indexmap 2.11.4", "stable_deref_trait", ] @@ -2123,7 +2123,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.3", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -2731,9 +2731,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.3" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92119844f513ffa41556430369ab02c295a3578af21cf945caa3e9e0c2481ac3" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.15.5", @@ -3317,7 +3317,7 @@ dependencies = [ "hex", "hyper", "icu_normalizer", - "indexmap 2.11.3", + "indexmap 2.11.4", "insta", "lettre", "mas-axum-utils", @@ -4025,7 +4025,7 @@ dependencies = [ "assert_matches", "base64ct", "chrono", - "indexmap 2.11.3", + "indexmap 2.11.4", "insta", "language-tags", "mas-iana", @@ -4046,7 +4046,7 @@ checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "crc32fast", "hashbrown 0.15.5", - "indexmap 2.11.3", + "indexmap 2.11.4", "memchr", ] @@ -4528,7 +4528,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64", - "indexmap 2.11.3", + "indexmap 2.11.4", "quick-xml", "serde", "time", @@ -5024,7 +5024,7 @@ dependencies = [ "base64", "bytes", "form_urlencoded", - "indexmap 2.11.3", + "indexmap 2.11.4", "js_int", "percent-encoding", "regex", @@ -5243,7 +5243,7 @@ dependencies = [ "chrono", "dyn-clone", "indexmap 1.9.3", - "indexmap 2.11.3", + "indexmap 2.11.4", "schemars_derive", "serde", "serde_json", @@ -5557,7 +5557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" dependencies = [ "form_urlencoded", - "indexmap 2.11.3", + "indexmap 2.11.4", "itoa", "ryu", "serde_core", @@ -5569,7 +5569,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.3", + "indexmap 2.11.4", "itoa", "memchr", "ryu", @@ -5632,7 +5632,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.3", + "indexmap 2.11.4", "schemars 0.9.0", "schemars 1.0.4", "serde", @@ -5660,7 +5660,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.3", + "indexmap 2.11.4", "itoa", "ryu", "serde", @@ -5846,7 +5846,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.11.3", + "indexmap 2.11.4", "ipnetwork", "log", "memchr", @@ -6420,7 +6420,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.3", + "indexmap 2.11.4", "serde", "serde_spanned", "toml_datetime", @@ -6998,7 +6998,7 @@ checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917" dependencies = [ "bitflags", "hashbrown 0.15.5", - "indexmap 2.11.3", + "indexmap 2.11.4", "semver", "serde", ] @@ -7028,7 +7028,7 @@ dependencies = [ "cc", "cfg-if", "hashbrown 0.15.5", - "indexmap 2.11.3", + "indexmap 2.11.4", "libc", "log", "mach2", @@ -7068,7 +7068,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap 2.11.3", + "indexmap 2.11.4", "log", "object", "postcard", @@ -7213,7 +7213,7 @@ checksum = "1ae057d44a5b60e6ec529b0c21809a9d1fc92e91ef6e0f6771ed11dd02a94a08" dependencies = [ "anyhow", "heck 0.5.0", - "indexmap 2.11.3", + "indexmap 2.11.4", "wit-parser", ] @@ -7728,7 +7728,7 @@ checksum = "0a1f95a87d03a33e259af286b857a95911eb46236a0f726cbaec1227b3dfc67a" dependencies = [ "anyhow", "id-arena", - "indexmap 2.11.3", + "indexmap 2.11.4", "log", "semver", "serde", diff --git a/Cargo.toml b/Cargo.toml index 67c8e730f..5c44c7e57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -321,7 +321,7 @@ features = ["std"] # HashMap which preserves insertion order [workspace.dependencies.indexmap] -version = "2.11.3" +version = "2.11.4" features = ["serde"] # Indented string literals From d309051a35e39bf63605f71e0a23466d06b650e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:21:28 +0000 Subject: [PATCH 077/296] build(deps): bump clap from 4.5.47 to 4.5.48 Bumps [clap](https://github.com/clap-rs/clap) from 4.5.47 to 4.5.48. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.47...clap_complete-v4.5.48) --- updated-dependencies: - dependency-name: clap dependency-version: 4.5.48 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 946317288..8f3a13659 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -971,9 +971,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", "clap_derive", @@ -981,9 +981,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index 03c645a3d..bc66484b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -167,7 +167,7 @@ features = ["serde", "clock"] # CLI argument parsing [workspace.dependencies.clap] -version = "4.5.47" +version = "4.5.48" features = ["derive"] # Object Identifiers (OIDs) as constants From 9c09cbcaa72d57f161f9c3b6851f0d6153a8c324 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:23:23 +0000 Subject: [PATCH 078/296] build(deps): bump anyhow from 1.0.99 to 1.0.100 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.99 to 1.0.100. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.99...1.0.100) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.100 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 946317288..0f6e744bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" diff --git a/Cargo.toml b/Cargo.toml index 03c645a3d..92c967ec8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ version = "0.1.89" # High-level error handling [workspace.dependencies.anyhow] -version = "1.0.99" +version = "1.0.100" # Assert that a value matches a pattern [workspace.dependencies.assert_matches] From 362fd023511f2b373da35bf817de2f64fedbb36c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 14:43:45 +0000 Subject: [PATCH 079/296] Translations updates --- frontend/.storybook/locales.ts | 62 +++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts index 090812bf0..c2acf82ed 100644 --- a/frontend/.storybook/locales.ts +++ b/frontend/.storybook/locales.ts @@ -27,7 +27,7 @@ export type LocalazyMetadata = { }; const localazyMetadata: LocalazyMetadata = { - projectUrl: "https://localazy.com/p/matrix-authentication-service", + projectUrl: "https://localazy.com/p/matrix-authentication-service!v1.3", baseLocale: "en", languages: [ { @@ -172,21 +172,21 @@ const localazyMetadata: LocalazyMetadata = { file: "frontend.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", - "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", - "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", - "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", - "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", - "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", - "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", - "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", - "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", - "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", - "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", - "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", - "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", - "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", - "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" + "cs": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", + "da": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", + "de": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", + "en": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", + "et": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", + "fi": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", + "fr": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", + "hu": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", + "nb_NO": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", + "nl": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", + "pt": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", + "ru": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", + "sv": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", + "uk": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", + "zh#Hans": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" } }, { @@ -194,21 +194,21 @@ const localazyMetadata: LocalazyMetadata = { file: "file.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", - "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", - "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", - "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", - "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", - "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", - "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", - "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", - "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", - "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", - "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", - "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", - "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", - "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", - "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" + "cs": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", + "da": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", + "de": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", + "en": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", + "et": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", + "fi": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", + "fr": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", + "hu": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", + "nb_NO": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", + "nl": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", + "pt": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", + "ru": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", + "sv": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", + "uk": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", + "zh#Hans": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" } } ] From d2477b145e6c7d126f5ddcfc72efadb11628d86e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Sep 2025 15:21:57 +0000 Subject: [PATCH 080/296] 1.3.0 --- Cargo.lock | 56 +++++++++++++++++++++++++------------------------- Cargo.toml | 60 +++++++++++++++++++++++++++--------------------------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c00b8a00..191e76f2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3106,7 +3106,7 @@ dependencies = [ [[package]] name = "mas-axum-utils" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "axum", @@ -3140,7 +3140,7 @@ dependencies = [ [[package]] name = "mas-cli" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "axum", @@ -3213,7 +3213,7 @@ dependencies = [ [[package]] name = "mas-config" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "camino", @@ -3245,7 +3245,7 @@ dependencies = [ [[package]] name = "mas-context" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "console", "opentelemetry", @@ -3261,7 +3261,7 @@ dependencies = [ [[package]] name = "mas-data-model" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "base64ct", "chrono", @@ -3284,7 +3284,7 @@ dependencies = [ [[package]] name = "mas-email" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "async-trait", "lettre", @@ -3295,7 +3295,7 @@ dependencies = [ [[package]] name = "mas-handlers" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "aide", "anyhow", @@ -3375,7 +3375,7 @@ dependencies = [ [[package]] name = "mas-http" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "futures-util", "headers", @@ -3396,7 +3396,7 @@ dependencies = [ [[package]] name = "mas-i18n" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "camino", "icu_calendar", @@ -3418,7 +3418,7 @@ dependencies = [ [[package]] name = "mas-i18n-scan" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "camino", "clap", @@ -3432,7 +3432,7 @@ dependencies = [ [[package]] name = "mas-iana" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "schemars 0.8.22", "serde", @@ -3440,7 +3440,7 @@ dependencies = [ [[package]] name = "mas-iana-codegen" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "async-trait", @@ -3456,7 +3456,7 @@ dependencies = [ [[package]] name = "mas-jose" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "base64ct", "chrono", @@ -3486,7 +3486,7 @@ dependencies = [ [[package]] name = "mas-keystore" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "aead", "base64ct", @@ -3514,7 +3514,7 @@ dependencies = [ [[package]] name = "mas-listener" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "bytes", @@ -3539,7 +3539,7 @@ dependencies = [ [[package]] name = "mas-matrix" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "async-trait", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "mas-matrix-synapse" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "async-trait", @@ -3566,7 +3566,7 @@ dependencies = [ [[package]] name = "mas-oidc-client" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "assert_matches", "async-trait", @@ -3602,7 +3602,7 @@ dependencies = [ [[package]] name = "mas-policy" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "arc-swap", @@ -3619,7 +3619,7 @@ dependencies = [ [[package]] name = "mas-router" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "axum", "serde", @@ -3630,7 +3630,7 @@ dependencies = [ [[package]] name = "mas-spa" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "camino", "serde", @@ -3639,7 +3639,7 @@ dependencies = [ [[package]] name = "mas-storage" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "async-trait", "chrono", @@ -3661,7 +3661,7 @@ dependencies = [ [[package]] name = "mas-storage-pg" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "async-trait", "chrono", @@ -3688,7 +3688,7 @@ dependencies = [ [[package]] name = "mas-tasks" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "async-trait", @@ -3720,7 +3720,7 @@ dependencies = [ [[package]] name = "mas-templates" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "arc-swap", @@ -3750,7 +3750,7 @@ dependencies = [ [[package]] name = "mas-tower" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "http", "opentelemetry", @@ -4020,7 +4020,7 @@ dependencies = [ [[package]] name = "oauth2-types" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "assert_matches", "base64ct", @@ -6103,7 +6103,7 @@ dependencies = [ [[package]] name = "syn2mas" -version = "1.3.0-rc.0" +version = "1.3.0" dependencies = [ "anyhow", "arc-swap", diff --git a/Cargo.toml b/Cargo.toml index b99c6aa31..dda7224d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = ["crates/*"] resolver = "2" # Updated in the CI with a `sed` command -package.version = "1.3.0-rc.0" +package.version = "1.3.0" package.license = "AGPL-3.0-only OR LicenseRef-Element-Commercial" package.authors = ["Element Backend Team"] package.edition = "2024" @@ -34,35 +34,35 @@ broken_intra_doc_links = "deny" [workspace.dependencies] # Workspace crates -mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.3.0-rc.0" } -mas-cli = { path = "./crates/cli/", version = "=1.3.0-rc.0" } -mas-config = { path = "./crates/config/", version = "=1.3.0-rc.0" } -mas-context = { path = "./crates/context/", version = "=1.3.0-rc.0" } -mas-data-model = { path = "./crates/data-model/", version = "=1.3.0-rc.0" } -mas-email = { path = "./crates/email/", version = "=1.3.0-rc.0" } -mas-graphql = { path = "./crates/graphql/", version = "=1.3.0-rc.0" } -mas-handlers = { path = "./crates/handlers/", version = "=1.3.0-rc.0" } -mas-http = { path = "./crates/http/", version = "=1.3.0-rc.0" } -mas-i18n = { path = "./crates/i18n/", version = "=1.3.0-rc.0" } -mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.3.0-rc.0" } -mas-iana = { path = "./crates/iana/", version = "=1.3.0-rc.0" } -mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.3.0-rc.0" } -mas-jose = { path = "./crates/jose/", version = "=1.3.0-rc.0" } -mas-keystore = { path = "./crates/keystore/", version = "=1.3.0-rc.0" } -mas-listener = { path = "./crates/listener/", version = "=1.3.0-rc.0" } -mas-matrix = { path = "./crates/matrix/", version = "=1.3.0-rc.0" } -mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.3.0-rc.0" } -mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.3.0-rc.0" } -mas-policy = { path = "./crates/policy/", version = "=1.3.0-rc.0" } -mas-router = { path = "./crates/router/", version = "=1.3.0-rc.0" } -mas-spa = { path = "./crates/spa/", version = "=1.3.0-rc.0" } -mas-storage = { path = "./crates/storage/", version = "=1.3.0-rc.0" } -mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.3.0-rc.0" } -mas-tasks = { path = "./crates/tasks/", version = "=1.3.0-rc.0" } -mas-templates = { path = "./crates/templates/", version = "=1.3.0-rc.0" } -mas-tower = { path = "./crates/tower/", version = "=1.3.0-rc.0" } -oauth2-types = { path = "./crates/oauth2-types/", version = "=1.3.0-rc.0" } -syn2mas = { path = "./crates/syn2mas", version = "=1.3.0-rc.0" } +mas-axum-utils = { path = "./crates/axum-utils/", version = "=1.3.0" } +mas-cli = { path = "./crates/cli/", version = "=1.3.0" } +mas-config = { path = "./crates/config/", version = "=1.3.0" } +mas-context = { path = "./crates/context/", version = "=1.3.0" } +mas-data-model = { path = "./crates/data-model/", version = "=1.3.0" } +mas-email = { path = "./crates/email/", version = "=1.3.0" } +mas-graphql = { path = "./crates/graphql/", version = "=1.3.0" } +mas-handlers = { path = "./crates/handlers/", version = "=1.3.0" } +mas-http = { path = "./crates/http/", version = "=1.3.0" } +mas-i18n = { path = "./crates/i18n/", version = "=1.3.0" } +mas-i18n-scan = { path = "./crates/i18n-scan/", version = "=1.3.0" } +mas-iana = { path = "./crates/iana/", version = "=1.3.0" } +mas-iana-codegen = { path = "./crates/iana-codegen/", version = "=1.3.0" } +mas-jose = { path = "./crates/jose/", version = "=1.3.0" } +mas-keystore = { path = "./crates/keystore/", version = "=1.3.0" } +mas-listener = { path = "./crates/listener/", version = "=1.3.0" } +mas-matrix = { path = "./crates/matrix/", version = "=1.3.0" } +mas-matrix-synapse = { path = "./crates/matrix-synapse/", version = "=1.3.0" } +mas-oidc-client = { path = "./crates/oidc-client/", version = "=1.3.0" } +mas-policy = { path = "./crates/policy/", version = "=1.3.0" } +mas-router = { path = "./crates/router/", version = "=1.3.0" } +mas-spa = { path = "./crates/spa/", version = "=1.3.0" } +mas-storage = { path = "./crates/storage/", version = "=1.3.0" } +mas-storage-pg = { path = "./crates/storage-pg/", version = "=1.3.0" } +mas-tasks = { path = "./crates/tasks/", version = "=1.3.0" } +mas-templates = { path = "./crates/templates/", version = "=1.3.0" } +mas-tower = { path = "./crates/tower/", version = "=1.3.0" } +oauth2-types = { path = "./crates/oauth2-types/", version = "=1.3.0" } +syn2mas = { path = "./crates/syn2mas", version = "=1.3.0" } # OpenAPI schema generation and validation [workspace.dependencies.aide] From 43ec44fd7b0a13cd310339e6583b16687bbe6cd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 13:15:29 +0000 Subject: [PATCH 081/296] build(deps-dev): bump the storybook group in /frontend with 3 updates Bumps the storybook group in /frontend with 3 updates: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite) and [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core). Updates `@storybook/addon-docs` from 9.1.6 to 9.1.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.7/code/addons/docs) Updates `@storybook/react-vite` from 9.1.6 to 9.1.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.7/code/frameworks/react-vite) Updates `storybook` from 9.1.6 to 9.1.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.7/code/core) --- updated-dependencies: - dependency-name: "@storybook/addon-docs" dependency-version: 9.1.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/react-vite" dependency-version: 9.1.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-version: 9.1.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 70 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dc60ee1c3..4f7d1ae88 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,8 +36,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.6", - "@storybook/react-vite": "^9.1.6", + "@storybook/addon-docs": "^9.1.8", + "@storybook/react-vite": "^9.1.8", "@tanstack/react-query-devtools": "^5.89.0", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", @@ -4884,16 +4884,16 @@ "license": "Apache-2.0" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.6.tgz", - "integrity": "sha512-4ZE/T2Ayw77/v2ersAk/VM7vlvqV2zCNFwt0uvOzUR1VZ9VqZCHhsfy/IyBPeKt6Otax3EpfE1LkH4slfceB0g==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.8.tgz", + "integrity": "sha512-GVrNVEdNRRo6r1hawfgyy6x+HJqPx1oOHm0U0wz0SGAxgS/Xh6SQVZL+RDoh7NpXkNi1GbezVlT931UsHQTyvQ==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.6", + "@storybook/csf-plugin": "9.1.8", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.6", + "@storybook/react-dom-shim": "9.1.8", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -4903,17 +4903,17 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.6" + "storybook": "^9.1.8" } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.6.tgz", - "integrity": "sha512-AUoSjXr4MvtkFQkfFfZSXrqVM0z80DX0sebm80nODu/qFhsJIU5trNP+XDYY8ClODERXd5QSZJyOyH9nOz60SA==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.8.tgz", + "integrity": "sha512-JjvBag0nM1N51O3VF5++op9Ly5OC8Q+y4PrWLgi2dKhMxJFs8fD9D4PeI/v41PUiQcI0suQxN9BoYoKn2QxUZw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.6", + "@storybook/csf-plugin": "9.1.8", "ts-dedent": "^2.0.0" }, "funding": { @@ -4921,14 +4921,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.6", + "storybook": "^9.1.8", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.6.tgz", - "integrity": "sha512-cz4Y+OYCtuovFNwoLkIKk0T62clrRTYf26Bbo1gdIGuX/W3JPP/LnN97sP2/0nfF6heZqCdEwb47k7RubkxXZg==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.8.tgz", + "integrity": "sha512-KnrXPz87bn+8ZGkzFEBc7TT5HkWpR1Xz7ojxPclSvkKxTfzazuaw0JlOQMzJoI1+wHXDAIw/4MIsO8HEiaWyfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4939,7 +4939,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.6" + "storybook": "^9.1.8" } }, "node_modules/@storybook/global": { @@ -4964,14 +4964,14 @@ } }, "node_modules/@storybook/react": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.6.tgz", - "integrity": "sha512-BGf3MQaXj6LmYnYpSwHUoWH0RP6kaqBoPc2u5opSU2ajw34enIL5w2sFaXzL+k2ap0aHnCYYlyBINBBvtD6NIA==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.8.tgz", + "integrity": "sha512-EULkwHroJ4IDYcjIBj9VpGhaZ9E5b8LI84hlfBkJ9rnK44a/GrK1yFRIusukO58qTJSh2Y7zfAFKNuiaWh3Sfw==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "9.1.6" + "@storybook/react-dom-shim": "9.1.8" }, "engines": { "node": ">=20.0.0" @@ -4983,7 +4983,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.6", + "storybook": "^9.1.8", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -4993,9 +4993,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.6.tgz", - "integrity": "sha512-Px4duzPMTPqI3kes6eUyYjWpEeJ0AOCCeSDCBDm9rzlf4a+eXlxfhkcVWft3viCDiIkc0vtYagb2Yu7bcSIypg==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.8.tgz", + "integrity": "sha512-OepccjVZh/KQugTH8/RL2CIyf1g5Lwc5ESC8x8BH3iuYc82WMQBwMJzRI5EofQdirau63NGrqkWCgQASoVreEA==", "dev": true, "license": "MIT", "funding": { @@ -5005,20 +5005,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.6" + "storybook": "^9.1.8" } }, "node_modules/@storybook/react-vite": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.6.tgz", - "integrity": "sha512-YNKQZcz5Vtv8OdHUJ65Wx4PbfZMrPPbtL+OYAR0We+EEoTDofi3VogXyOUw99Jppp1HIq5IiDF5qyZPEpC5k0A==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.8.tgz", + "integrity": "sha512-DIxp76vcelyFOUJupeQEIHXDrSPP6KDXj6Z+Z9thS1HH7JY+OdGtcMLy4fbiD77Zyc8TV9RRZ1D33z2Ot/v9Vw==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "9.1.6", - "@storybook/react": "9.1.6", + "@storybook/builder-vite": "9.1.8", + "@storybook/react": "9.1.8", "find-up": "^7.0.0", "magic-string": "^0.30.0", "react-docgen": "^8.0.0", @@ -5035,7 +5035,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.6", + "storybook": "^9.1.8", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -11908,9 +11908,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.6.tgz", - "integrity": "sha512-iIcMaDKkjR5nN+JYBy9hhoxZhjX4TXhyJgUBed+toJOlfrl+QvxpBjImAi7qKyLR3hng3uoigEP0P8+vYtXpOg==", + "version": "9.1.8", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.8.tgz", + "integrity": "sha512-/iP+DvieJ6Mnixy4PFY/KXnhsg/IHIDlTbZqly3EDbveuhsCuIUELfGnj+QSRGf9C6v/f4sZf9sZ3r80ZnKuEA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 8cf53912b..6e3eb2013 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,8 +46,8 @@ "@graphql-codegen/cli": "^5.0.7", "@graphql-codegen/client-preset": "^4.8.3", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.6", - "@storybook/react-vite": "^9.1.6", + "@storybook/addon-docs": "^9.1.8", + "@storybook/react-vite": "^9.1.8", "@tanstack/react-query-devtools": "^5.89.0", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", From 82465761348d048052705e2a3a40ebad90a2b690 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:13:31 +0000 Subject: [PATCH 082/296] build(deps): bump the fontsource group in /frontend with 2 updates Bumps the fontsource group in /frontend with 2 updates: [@fontsource/inconsolata](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/inconsolata) and [@fontsource/inter](https://github.com/fontsource/font-files/tree/HEAD/fonts/google/inter). Updates `@fontsource/inconsolata` from 5.2.7 to 5.2.8 - [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md) - [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/inconsolata) Updates `@fontsource/inter` from 5.2.7 to 5.2.8 - [Changelog](https://github.com/fontsource/font-files/blob/main/CHANGELOG.md) - [Commits](https://github.com/fontsource/font-files/commits/HEAD/fonts/google/inter) --- updated-dependencies: - dependency-name: "@fontsource/inconsolata" dependency-version: 5.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fontsource - dependency-name: "@fontsource/inter" dependency-version: 5.2.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fontsource ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dc60ee1c3..21d37c9de 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,8 +8,8 @@ "name": "mas-frontend", "version": "0.0.0", "dependencies": { - "@fontsource/inconsolata": "^5.2.7", - "@fontsource/inter": "^5.2.7", + "@fontsource/inconsolata": "^5.2.8", + "@fontsource/inter": "^5.2.8", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.89.0", @@ -1862,18 +1862,18 @@ "license": "MIT" }, "node_modules/@fontsource/inconsolata": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.7.tgz", - "integrity": "sha512-qmARxA7lS16PCoB404sehiXzh8mzcZzFio6n05/zpxIC97W+AxdJqgWQ0kfMzdj78ILy2PaaXZ1Js4kfxL1JMw==", + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/inconsolata/-/inconsolata-5.2.8.tgz", + "integrity": "sha512-lIZW+WOZYpUH91g9r6rYYhfTmptF3YPPM54ZOs8IYVeeL4SeiAu4tfj7mdr8llYEq31DLYgi6JtGIJa192gB0Q==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" } }, "node_modules/@fontsource/inter": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.7.tgz", - "integrity": "sha512-sfE4VQglV9B05DuJ+RD2RHY42FiVTdCf/dJtVkugRVkygoDigLM4SuNcBrCeo+zoGiC/IudmVcE6QKqW7S1Gkg==", + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", "license": "OFL-1.1", "funding": { "url": "https://github.com/sponsors/ayuhito" diff --git a/frontend/package.json b/frontend/package.json index 8cf53912b..70cc60d60 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,8 +18,8 @@ "knip": "knip" }, "dependencies": { - "@fontsource/inconsolata": "^5.2.7", - "@fontsource/inter": "^5.2.7", + "@fontsource/inconsolata": "^5.2.8", + "@fontsource/inter": "^5.2.8", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", "@tanstack/react-query": "^5.89.0", From 8962f355ff1178c3dcb335d541058e58a4ee7be5 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 29 Sep 2025 14:46:28 +0200 Subject: [PATCH 083/296] storage: make the edges in pages include cursors --- crates/storage-pg/src/app_session.rs | 36 +++++--- crates/storage-pg/src/compat/mod.rs | 23 ++--- crates/storage-pg/src/compat/session.rs | 13 +++ crates/storage-pg/src/compat/sso_login.rs | 7 ++ crates/storage-pg/src/oauth2/mod.rs | 48 +++++----- crates/storage-pg/src/oauth2/session.rs | 7 ++ crates/storage-pg/src/upstream_oauth2/link.rs | 7 ++ crates/storage-pg/src/upstream_oauth2/mod.rs | 40 +++++---- .../src/upstream_oauth2/provider.rs | 7 ++ .../storage-pg/src/upstream_oauth2/session.rs | 7 ++ crates/storage-pg/src/user/email.rs | 7 ++ crates/storage-pg/src/user/mod.rs | 8 ++ .../storage-pg/src/user/registration_token.rs | 30 ++++--- crates/storage-pg/src/user/session.rs | 7 ++ crates/storage-pg/src/user/tests.rs | 14 +-- crates/storage/src/pagination.rs | 88 ++++++++++++++----- crates/storage/src/queue/tasks.rs | 6 +- 17 files changed, 246 insertions(+), 109 deletions(-) diff --git a/crates/storage-pg/src/app_session.rs b/crates/storage-pg/src/app_session.rs index 62f3979a9..4e12810cc 100644 --- a/crates/storage-pg/src/app_session.rs +++ b/crates/storage-pg/src/app_session.rs @@ -55,7 +55,9 @@ mod priv_ { use std::net::IpAddr; use chrono::{DateTime, Utc}; + use mas_storage::pagination::Node; use sea_query::enum_def; + use ulid::Ulid; use uuid::Uuid; #[derive(sqlx::FromRow)] @@ -77,6 +79,12 @@ mod priv_ { pub(super) last_active_at: Option>, pub(super) last_active_ip: Option, } + + impl Node for AppSessionLookup { + fn cursor(&self) -> Ulid { + self.cursor.into() + } + } } use priv_::{AppSessionLookup, AppSessionLookupIden}; @@ -592,13 +600,13 @@ mod tests { let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 1); assert_eq!( - full_list.edges[0], + full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); let active_list = repo.app_session().list(active, pagination).await.unwrap(); assert_eq!(active_list.edges.len(), 1); assert_eq!( - active_list.edges[0], + active_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); @@ -618,7 +626,7 @@ mod tests { let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 1); assert_eq!( - full_list.edges[0], + full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); let active_list = repo.app_session().list(active, pagination).await.unwrap(); @@ -626,7 +634,7 @@ mod tests { let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 1); assert_eq!( - finished_list.edges[0], + finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); @@ -680,25 +688,25 @@ mod tests { let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 2); assert_eq!( - full_list.edges[0], + full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( - full_list.edges[1], + full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); let active_list = repo.app_session().list(active, pagination).await.unwrap(); assert_eq!(active_list.edges.len(), 1); assert_eq!( - active_list.edges[0], + active_list.edges[0].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 1); assert_eq!( - finished_list.edges[0], + finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); @@ -716,11 +724,11 @@ mod tests { let full_list = repo.app_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 2); assert_eq!( - full_list.edges[0], + full_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( - full_list.edges[1], + full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); @@ -730,11 +738,11 @@ mod tests { let finished_list = repo.app_session().list(finished, pagination).await.unwrap(); assert_eq!(finished_list.edges.len(), 2); assert_eq!( - finished_list.edges[0], + finished_list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); assert_eq!( - full_list.edges[1], + full_list.edges[1].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); @@ -744,7 +752,7 @@ mod tests { let list = repo.app_session().list(filter, pagination).await.unwrap(); assert_eq!(list.edges.len(), 1); assert_eq!( - list.edges[0], + list.edges[0].node, AppSession::Compat(Box::new(compat_session.clone())) ); @@ -753,7 +761,7 @@ mod tests { let list = repo.app_session().list(filter, pagination).await.unwrap(); assert_eq!(list.edges.len(), 1); assert_eq!( - list.edges[0], + list.edges[0].node, AppSession::OAuth2(Box::new(oauth_session.clone())) ); diff --git a/crates/storage-pg/src/compat/mod.rs b/crates/storage-pg/src/compat/mod.rs index db190db71..d42c9b1af 100644 --- a/crates/storage-pg/src/compat/mod.rs +++ b/crates/storage-pg/src/compat/mod.rs @@ -92,14 +92,14 @@ mod tests { let full_list = repo.compat_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 1); - assert_eq!(full_list.edges[0].0.id, session.id); + assert_eq!(full_list.edges[0].node.0.id, session.id); let active_list = repo .compat_session() .list(active, pagination) .await .unwrap(); assert_eq!(active_list.edges.len(), 1); - assert_eq!(active_list.edges[0].0.id, session.id); + assert_eq!(active_list.edges[0].node.0.id, session.id); let finished_list = repo .compat_session() .list(finished, pagination) @@ -150,7 +150,7 @@ mod tests { .await .unwrap(); assert_eq!(list.edges.len(), 1); - let session_lookup = &list.edges[0].0; + let session_lookup = &list.edges[0].node.0; assert_eq!(session_lookup.id, session.id); assert_eq!(session_lookup.user_id, user.id); assert_eq!(session.device.as_ref().unwrap().as_str(), device_str); @@ -168,7 +168,7 @@ mod tests { let full_list = repo.compat_session().list(all, pagination).await.unwrap(); assert_eq!(full_list.edges.len(), 1); - assert_eq!(full_list.edges[0].0.id, session.id); + assert_eq!(full_list.edges[0].node.0.id, session.id); let active_list = repo .compat_session() .list(active, pagination) @@ -181,7 +181,7 @@ mod tests { .await .unwrap(); assert_eq!(finished_list.edges.len(), 1); - assert_eq!(finished_list.edges[0].0.id, session.id); + assert_eq!(finished_list.edges[0].node.0.id, session.id); // Reload the session and check again let session_lookup = repo @@ -260,14 +260,14 @@ mod tests { .await .unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0].0.id, sso_login_session.id); + assert_eq!(list.edges[0].node.0.id, sso_login_session.id); let list = repo .compat_session() .list(unknown, pagination) .await .unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0].0.id, unknown_session.id); + assert_eq!(list.edges[0].node.0.id, unknown_session.id); // Check that combining the two filters works // At this point, there is one active SSO login session and one finished unknown @@ -696,7 +696,8 @@ mod tests { // List all logins let logins = repo.compat_sso_login().list(all, pagination).await.unwrap(); assert!(!logins.has_next_page); - assert_eq!(logins.edges, vec![login.clone()]); + assert_eq!(logins.edges.len(), 1); + assert_eq!(logins.edges[0].node, login); // List the logins for the user let logins = repo @@ -705,7 +706,8 @@ mod tests { .await .unwrap(); assert!(!logins.has_next_page); - assert_eq!(logins.edges, vec![login.clone()]); + assert_eq!(logins.edges.len(), 1); + assert_eq!(logins.edges[0].node, login); // List only the pending logins for the user let logins = repo @@ -732,6 +734,7 @@ mod tests { .await .unwrap(); assert!(!logins.has_next_page); - assert_eq!(logins.edges, &[login]); + assert_eq!(logins.edges.len(), 1); + assert_eq!(logins.edges[0].node, login); } } diff --git a/crates/storage-pg/src/compat/session.rs b/crates/storage-pg/src/compat/session.rs index 4ba5ee726..0fb21c487 100644 --- a/crates/storage-pg/src/compat/session.rs +++ b/crates/storage-pg/src/compat/session.rs @@ -15,6 +15,7 @@ use mas_data_model::{ use mas_storage::{ Page, Pagination, compat::{CompatSessionFilter, CompatSessionRepository}, + pagination::Node, }; use rand::RngCore; use sea_query::{Expr, PostgresQueryBuilder, Query, enum_def}; @@ -59,6 +60,12 @@ struct CompatSessionLookup { last_active_ip: Option, } +impl Node for CompatSessionLookup { + fn cursor(&self) -> Ulid { + self.compat_session_id.into() + } +} + impl From for CompatSession { fn from(value: CompatSessionLookup) -> Self { let id = value.compat_session_id.into(); @@ -106,6 +113,12 @@ struct CompatSessionAndSsoLoginLookup { compat_sso_login_exchanged_at: Option>, } +impl Node for CompatSessionAndSsoLoginLookup { + fn cursor(&self) -> Ulid { + self.compat_session_id.into() + } +} + impl TryFrom for (CompatSession, Option) { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/compat/sso_login.rs b/crates/storage-pg/src/compat/sso_login.rs index eeadff164..43ad4bead 100644 --- a/crates/storage-pg/src/compat/sso_login.rs +++ b/crates/storage-pg/src/compat/sso_login.rs @@ -10,6 +10,7 @@ use mas_data_model::{BrowserSession, Clock, CompatSession, CompatSsoLogin, Compa use mas_storage::{ Page, Pagination, compat::{CompatSsoLoginFilter, CompatSsoLoginRepository}, + pagination::Node, }; use rand::RngCore; use sea_query::{Expr, PostgresQueryBuilder, Query, enum_def}; @@ -54,6 +55,12 @@ struct CompatSsoLoginLookup { compat_session_id: Option, } +impl Node for CompatSsoLoginLookup { + fn cursor(&self) -> Ulid { + self.compat_sso_login_id.into() + } +} + impl TryFrom for CompatSsoLogin { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/oauth2/mod.rs b/crates/storage-pg/src/oauth2/mod.rs index 6b1c81d46..bf741b5f2 100644 --- a/crates/storage-pg/src/oauth2/mod.rs +++ b/crates/storage-pg/src/oauth2/mod.rs @@ -511,10 +511,10 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 4); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session12); - assert_eq!(list.edges[2], session21); - assert_eq!(list.edges[3], session22); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session12); + assert_eq!(list.edges[2].node, session21); + assert_eq!(list.edges[3].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 4); @@ -527,8 +527,8 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 2); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session21); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session21); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2); @@ -541,8 +541,8 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 2); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session12); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session12); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2); @@ -557,7 +557,7 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session22); + assert_eq!(list.edges[0].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); @@ -570,8 +570,8 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 2); - assert_eq!(list.edges[0], session12); - assert_eq!(list.edges[1], session21); + assert_eq!(list.edges[0].node, session12); + assert_eq!(list.edges[1].node, session21); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2); @@ -584,8 +584,8 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 2); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session22); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2); @@ -598,7 +598,7 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session22); + assert_eq!(list.edges[0].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); @@ -613,7 +613,7 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session22); + assert_eq!(list.edges[0].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); @@ -626,7 +626,7 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session12); + assert_eq!(list.edges[0].node, session12); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); @@ -641,7 +641,7 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session21); + assert_eq!(list.edges[0].node, session21); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); @@ -655,10 +655,10 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 4); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session12); - assert_eq!(list.edges[2], session21); - assert_eq!(list.edges[3], session22); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session12); + assert_eq!(list.edges[2].node, session21); + assert_eq!(list.edges[3].node, session22); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 4); // We should get all sessions with the "openid" and "email" scope @@ -671,8 +671,8 @@ mod tests { .unwrap(); assert!(!list.has_next_page); assert_eq!(list.edges.len(), 2); - assert_eq!(list.edges[0], session11); - assert_eq!(list.edges[1], session12); + assert_eq!(list.edges[0].node, session11); + assert_eq!(list.edges[1].node, session12); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 2); // Try combining the scope filter with the user filter @@ -685,7 +685,7 @@ mod tests { .await .unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0], session11); + assert_eq!(list.edges[0].node, session11); assert_eq!(repo.oauth2_session().count(filter).await.unwrap(), 1); // Finish all sessions of a client in batch diff --git a/crates/storage-pg/src/oauth2/session.rs b/crates/storage-pg/src/oauth2/session.rs index c04e03df0..072691a06 100644 --- a/crates/storage-pg/src/oauth2/session.rs +++ b/crates/storage-pg/src/oauth2/session.rs @@ -12,6 +12,7 @@ use mas_data_model::{BrowserSession, Client, Clock, Session, SessionState, User} use mas_storage::{ Page, Pagination, oauth2::{OAuth2SessionFilter, OAuth2SessionRepository}, + pagination::Node, }; use oauth2_types::scope::{Scope, ScopeToken}; use rand::RngCore; @@ -61,6 +62,12 @@ struct OAuthSessionLookup { human_name: Option, } +impl Node for OAuthSessionLookup { + fn cursor(&self) -> Ulid { + self.oauth2_session_id.into() + } +} + impl TryFrom for Session { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/upstream_oauth2/link.rs b/crates/storage-pg/src/upstream_oauth2/link.rs index 6f671655d..c43dd8a18 100644 --- a/crates/storage-pg/src/upstream_oauth2/link.rs +++ b/crates/storage-pg/src/upstream_oauth2/link.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use mas_data_model::{Clock, UpstreamOAuthLink, UpstreamOAuthProvider, User}; use mas_storage::{ Page, Pagination, + pagination::Node, upstream_oauth2::{UpstreamOAuthLinkFilter, UpstreamOAuthLinkRepository}, }; use opentelemetry_semantic_conventions::trace::DB_QUERY_TEXT; @@ -53,6 +54,12 @@ struct LinkLookup { created_at: DateTime, } +impl Node for LinkLookup { + fn cursor(&self) -> Ulid { + self.upstream_oauth_link_id.into() + } +} + impl From for UpstreamOAuthLink { fn from(value: LinkLookup) -> Self { UpstreamOAuthLink { diff --git a/crates/storage-pg/src/upstream_oauth2/mod.rs b/crates/storage-pg/src/upstream_oauth2/mod.rs index 6381c9b7f..d98e840b6 100644 --- a/crates/storage-pg/src/upstream_oauth2/mod.rs +++ b/crates/storage-pg/src/upstream_oauth2/mod.rs @@ -206,8 +206,8 @@ mod tests { assert!(!links.has_previous_page); assert!(!links.has_next_page); assert_eq!(links.edges.len(), 1); - assert_eq!(links.edges[0].id, link.id); - assert_eq!(links.edges[0].user_id, Some(user.id)); + assert_eq!(links.edges[0].node.id, link.id); + assert_eq!(links.edges[0].node.user_id, Some(user.id)); assert_eq!(repo.upstream_oauth_link().count(filter).await.unwrap(), 1); @@ -282,7 +282,7 @@ mod tests { .unwrap(); assert_eq!(session_page.edges.len(), 1); - assert_eq!(session_page.edges[0].id, session.id); + assert_eq!(session_page.edges[0].node.id, session.id); assert!(!session_page.has_next_page); assert!(!session_page.has_previous_page); @@ -374,7 +374,7 @@ mod tests { // It returned the first 10 items assert!(page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect(); assert_eq!(&edge_ids, &ids[..10]); // Getting the same page with the "enabled only" filter should return the same @@ -396,7 +396,7 @@ mod tests { // It returned the next 10 items assert!(!page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect(); assert_eq!(&edge_ids, &ids[10..]); // Lookup the last 10 items @@ -408,7 +408,7 @@ mod tests { // It returned the last 10 items assert!(page.has_previous_page); - let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect(); assert_eq!(&edge_ids, &ids[10..]); // Lookup the previous 10 items @@ -420,7 +420,7 @@ mod tests { // It returned the previous 10 items assert!(!page.has_previous_page); - let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect(); assert_eq!(&edge_ids, &ids[..10]); // Lookup 10 items between two IDs @@ -432,7 +432,7 @@ mod tests { // It returned the items in between assert!(!page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|p| p.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|p| p.node.id).collect(); assert_eq!(&edge_ids, &ids[6..8]); // There should not be any disabled providers @@ -560,7 +560,7 @@ mod tests { // It returned the first 10 items assert!(page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect(); assert_eq!(&edge_ids, &ids[..10]); // Lookup the next 10 items @@ -572,7 +572,7 @@ mod tests { // It returned the next 10 items assert!(!page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect(); assert_eq!(&edge_ids, &ids[10..]); // Lookup the last 10 items @@ -584,7 +584,7 @@ mod tests { // It returned the last 10 items assert!(page.has_previous_page); - let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect(); assert_eq!(&edge_ids, &ids[10..]); // Lookup the previous 10 items @@ -596,7 +596,7 @@ mod tests { // It returned the previous 10 items assert!(!page.has_previous_page); - let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect(); assert_eq!(&edge_ids, &ids[..10]); // Lookup 5 items between two IDs @@ -608,7 +608,7 @@ mod tests { // It returned the items in between assert!(!page.has_next_page); - let edge_ids: Vec<_> = page.edges.iter().map(|s| s.id).collect(); + let edge_ids: Vec<_> = page.edges.iter().map(|s| s.node.id).collect(); assert_eq!(&edge_ids, &ids[6..11]); // Check the sub/sid filters @@ -638,11 +638,21 @@ mod tests { assert_eq!(page.edges.len(), 4); for edge in page.edges { assert_eq!( - edge.id_token_claims().unwrap().get("sub").unwrap().as_str(), + edge.node + .id_token_claims() + .unwrap() + .get("sub") + .unwrap() + .as_str(), Some("alice") ); assert_eq!( - edge.id_token_claims().unwrap().get("sid").unwrap().as_str(), + edge.node + .id_token_claims() + .unwrap() + .get("sid") + .unwrap() + .as_str(), Some("one") ); } diff --git a/crates/storage-pg/src/upstream_oauth2/provider.rs b/crates/storage-pg/src/upstream_oauth2/provider.rs index 583f8ec0c..caade738d 100644 --- a/crates/storage-pg/src/upstream_oauth2/provider.rs +++ b/crates/storage-pg/src/upstream_oauth2/provider.rs @@ -9,6 +9,7 @@ use chrono::{DateTime, Utc}; use mas_data_model::{Clock, UpstreamOAuthProvider, UpstreamOAuthProviderClaimsImports}; use mas_storage::{ Page, Pagination, + pagination::Node, upstream_oauth2::{ UpstreamOAuthProviderFilter, UpstreamOAuthProviderParams, UpstreamOAuthProviderRepository, }, @@ -74,6 +75,12 @@ struct ProviderLookup { on_backchannel_logout: String, } +impl Node for ProviderLookup { + fn cursor(&self) -> Ulid { + self.upstream_oauth_provider_id.into() + } +} + impl TryFrom for UpstreamOAuthProvider { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/upstream_oauth2/session.rs b/crates/storage-pg/src/upstream_oauth2/session.rs index 8b37aae2e..b961c4f8c 100644 --- a/crates/storage-pg/src/upstream_oauth2/session.rs +++ b/crates/storage-pg/src/upstream_oauth2/session.rs @@ -12,6 +12,7 @@ use mas_data_model::{ }; use mas_storage::{ Page, Pagination, + pagination::Node, upstream_oauth2::{UpstreamOAuthSessionFilter, UpstreamOAuthSessionRepository}, }; use rand::RngCore; @@ -91,6 +92,12 @@ struct SessionLookup { unlinked_at: Option>, } +impl Node for SessionLookup { + fn cursor(&self) -> Ulid { + self.upstream_oauth_authorization_session_id.into() + } +} + impl TryFrom for UpstreamOAuthAuthorizationSession { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/user/email.rs b/crates/storage-pg/src/user/email.rs index 916874ae8..0f998e55f 100644 --- a/crates/storage-pg/src/user/email.rs +++ b/crates/storage-pg/src/user/email.rs @@ -12,6 +12,7 @@ use mas_data_model::{ }; use mas_storage::{ Page, Pagination, + pagination::Node, user::{UserEmailFilter, UserEmailRepository}, }; use rand::RngCore; @@ -51,6 +52,12 @@ struct UserEmailLookup { created_at: DateTime, } +impl Node for UserEmailLookup { + fn cursor(&self) -> Ulid { + self.user_email_id.into() + } +} + impl From for UserEmail { fn from(e: UserEmailLookup) -> UserEmail { UserEmail { diff --git a/crates/storage-pg/src/user/mod.rs b/crates/storage-pg/src/user/mod.rs index 0be594556..bbf02567e 100644 --- a/crates/storage-pg/src/user/mod.rs +++ b/crates/storage-pg/src/user/mod.rs @@ -61,7 +61,9 @@ mod priv_ { #![allow(missing_docs)] use chrono::{DateTime, Utc}; + use mas_storage::pagination::Node; use sea_query::enum_def; + use ulid::Ulid; use uuid::Uuid; #[derive(Debug, Clone, sqlx::FromRow)] @@ -75,6 +77,12 @@ mod priv_ { pub(super) can_request_admin: bool, pub(super) is_guest: bool, } + + impl Node for UserLookup { + fn cursor(&self) -> Ulid { + self.user_id.into() + } + } } use priv_::{UserLookup, UserLookupIden}; diff --git a/crates/storage-pg/src/user/registration_token.rs b/crates/storage-pg/src/user/registration_token.rs index f64c8136d..5c9231aa1 100644 --- a/crates/storage-pg/src/user/registration_token.rs +++ b/crates/storage-pg/src/user/registration_token.rs @@ -8,6 +8,7 @@ use chrono::{DateTime, Utc}; use mas_data_model::{Clock, UserRegistrationToken}; use mas_storage::{ Page, Pagination, + pagination::Node, user::{UserRegistrationTokenFilter, UserRegistrationTokenRepository}, }; use rand::RngCore; @@ -53,6 +54,12 @@ struct UserRegistrationTokenLookup { revoked_at: Option>, } +impl Node for UserRegistrationTokenLookup { + fn cursor(&self) -> Ulid { + self.user_registration_token_id.into() + } +} + impl Filter for UserRegistrationTokenFilter { fn generate_condition(&self, _has_joins: bool) -> impl sea_query::IntoCondition { sea_query::Condition::all() @@ -230,7 +237,7 @@ impl UserRegistrationTokenRepository for PgUserRegistrationTokenRepository<'_> { filter: UserRegistrationTokenFilter, pagination: Pagination, ) -> Result, Self::Error> { - let (sql, values) = Query::select() + let (sql, arguments) = Query::select() .expr_as( Expr::col(( UserRegistrationTokens::Table, @@ -295,15 +302,14 @@ impl UserRegistrationTokenRepository for PgUserRegistrationTokenRepository<'_> { ) .build_sqlx(PostgresQueryBuilder); - let tokens = sqlx::query_as_with::<_, UserRegistrationTokenLookup, _>(&sql, values) + let edges: Vec = sqlx::query_as_with(&sql, arguments) .traced() .fetch_all(&mut *self.conn) - .await? - .into_iter() - .map(TryInto::try_into) - .collect::, _>>()?; + .await?; - let page = pagination.process(tokens); + let page = pagination + .process(edges) + .try_map(UserRegistrationToken::try_from)?; Ok(page) } @@ -705,7 +711,7 @@ mod tests { .await .unwrap(); - assert!(page.edges.iter().any(|t| t.id == unrevoked_token.id)); + assert!(page.edges.iter().any(|t| t.node.id == unrevoked_token.id)); } #[sqlx::test(migrator = "crate::MIGRATOR")] @@ -867,7 +873,7 @@ mod tests { .await .unwrap(); assert_eq!(page.edges.len(), 1); - assert_eq!(page.edges[0].id, token2.id); + assert_eq!(page.edges[0].node.id, token2.id); // Test unused filter let unused_filter = UserRegistrationTokenFilter::new(clock.now()).with_been_used(false); @@ -886,7 +892,7 @@ mod tests { .await .unwrap(); assert_eq!(page.edges.len(), 1); - assert_eq!(page.edges[0].id, token3.id); + assert_eq!(page.edges[0].node.id, token3.id); let not_expired_filter = UserRegistrationTokenFilter::new(clock.now()).with_expired(false); let page = repo @@ -904,7 +910,7 @@ mod tests { .await .unwrap(); assert_eq!(page.edges.len(), 1); - assert_eq!(page.edges[0].id, token4.id); + assert_eq!(page.edges[0].node.id, token4.id); let not_revoked_filter = UserRegistrationTokenFilter::new(clock.now()).with_revoked(false); let page = repo @@ -941,7 +947,7 @@ mod tests { .await .unwrap(); assert_eq!(page.edges.len(), 1); - assert_eq!(page.edges[0].id, token4.id); + assert_eq!(page.edges[0].node.id, token4.id); // Test pagination let page = repo diff --git a/crates/storage-pg/src/user/session.rs b/crates/storage-pg/src/user/session.rs index 54645b3cb..8644d7666 100644 --- a/crates/storage-pg/src/user/session.rs +++ b/crates/storage-pg/src/user/session.rs @@ -14,6 +14,7 @@ use mas_data_model::{ }; use mas_storage::{ Page, Pagination, + pagination::Node, user::{BrowserSessionFilter, BrowserSessionRepository}, }; use rand::RngCore; @@ -64,6 +65,12 @@ struct SessionLookup { user_is_guest: bool, } +impl Node for SessionLookup { + fn cursor(&self) -> Ulid { + self.user_id.into() + } +} + impl TryFrom for BrowserSession { type Error = DatabaseInconsistencyError; diff --git a/crates/storage-pg/src/user/tests.rs b/crates/storage-pg/src/user/tests.rs index 0ee978914..98489d68d 100644 --- a/crates/storage-pg/src/user/tests.rs +++ b/crates/storage-pg/src/user/tests.rs @@ -190,7 +190,7 @@ async fn test_user_repo(pool: PgPool) { // Check the list method let list = repo.user().list(all, Pagination::first(10)).await.unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0].id, user.id); + assert_eq!(list.edges[0].node.id, user.id); let list = repo .user() @@ -205,7 +205,7 @@ async fn test_user_repo(pool: PgPool) { .await .unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0].id, user.id); + assert_eq!(list.edges[0].node.id, user.id); let list = repo .user() @@ -227,7 +227,7 @@ async fn test_user_repo(pool: PgPool) { .await .unwrap(); assert_eq!(list.edges.len(), 1); - assert_eq!(list.edges[0].id, user.id); + assert_eq!(list.edges[0].node.id, user.id); repo.save().await.unwrap(); } @@ -348,7 +348,7 @@ async fn test_user_email_repo(pool: PgPool) { .unwrap(); assert!(!emails.has_next_page); assert_eq!(emails.edges.len(), 1); - assert_eq!(emails.edges[0], user_email); + assert_eq!(emails.edges[0].node, user_email); // Listing emails from the email address should work let emails = repo @@ -358,7 +358,7 @@ async fn test_user_email_repo(pool: PgPool) { .unwrap(); assert!(!emails.has_next_page); assert_eq!(emails.edges.len(), 1); - assert_eq!(emails.edges[0], user_email); + assert_eq!(emails.edges[0].node, user_email); // Filtering on another email should not return anything let emails = repo @@ -648,7 +648,7 @@ async fn test_user_session(pool: PgPool) { .unwrap(); assert!(!session_list.has_next_page); assert_eq!(session_list.edges.len(), 1); - assert_eq!(session_list.edges[0], session); + assert_eq!(session_list.edges[0].node, session); let session_lookup = repo .browser_session() @@ -809,7 +809,7 @@ async fn test_user_session(pool: PgPool) { .await .unwrap(); assert_eq!(page.edges.len(), 1); - assert_eq!(page.edges[0].id, session.id); + assert_eq!(page.edges[0].node.id, session.id); // Try counting assert_eq!(repo.browser_session().count(filter).await.unwrap(), 1); diff --git a/crates/storage/src/pagination.rs b/crates/storage/src/pagination.rs index 01b8ed197..ad632cb10 100644 --- a/crates/storage/src/pagination.rs +++ b/crates/storage/src/pagination.rs @@ -16,12 +16,12 @@ pub struct InvalidPagination; /// Pagination parameters #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Pagination { +pub struct Pagination { /// The cursor to start from - pub before: Option, + pub before: Option, /// The cursor to end at - pub after: Option, + pub after: Option, /// The maximum number of items to return pub count: usize, @@ -40,16 +40,22 @@ pub enum PaginationDirection { Backward, } -impl Pagination { +/// A node in a page, with a cursor +pub trait Node { + /// The cursor of that particular node + fn cursor(&self) -> C; +} + +impl Pagination { /// Creates a new [`Pagination`] from user-provided parameters. /// /// # Errors /// /// Either `first` or `last` must be provided, else this function will /// return an [`InvalidPagination`] error. - pub const fn try_new( - before: Option, - after: Option, + pub fn try_new( + before: Option, + after: Option, first: Option, last: Option, ) -> Result { @@ -91,49 +97,57 @@ impl Pagination { /// Get items before the given cursor #[must_use] - pub const fn before(mut self, id: Ulid) -> Self { - self.before = Some(id); + pub fn before(mut self, cursor: C) -> Self { + self.before = Some(cursor); self } /// Clear the before cursor #[must_use] - pub const fn clear_before(mut self) -> Self { + pub fn clear_before(mut self) -> Self { self.before = None; self } /// Get items after the given cursor #[must_use] - pub const fn after(mut self, id: Ulid) -> Self { - self.after = Some(id); + pub fn after(mut self, cursor: C) -> Self { + self.after = Some(cursor); self } /// Clear the after cursor #[must_use] - pub const fn clear_after(mut self) -> Self { + pub fn clear_after(mut self) -> Self { self.after = None; self } /// Process a page returned by a paginated query #[must_use] - pub fn process(&self, mut edges: Vec) -> Page { - let is_full = edges.len() == (self.count + 1); + pub fn process>(&self, mut nodes: Vec) -> Page { + let is_full = nodes.len() == (self.count + 1); if is_full { - edges.pop(); + nodes.pop(); } let (has_previous_page, has_next_page) = match self.direction { PaginationDirection::Forward => (false, is_full), PaginationDirection::Backward => { // 6. If the last argument is provided, I reverse the order of the results - edges.reverse(); + nodes.reverse(); (is_full, false) } }; + let edges = nodes + .into_iter() + .map(|node| Edge { + cursor: node.cursor(), + node, + }) + .collect(); + Page { has_next_page, has_previous_page, @@ -142,9 +156,18 @@ impl Pagination { } } +/// An edge in a paginated result +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Edge { + /// The cursor of the edge + pub cursor: C, + /// The node of the edge + pub node: T, +} + /// A page of results returned by a paginated query #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Page { +pub struct Page { /// When paginating forwards, this is true if there are more items after pub has_next_page: bool, @@ -152,21 +175,28 @@ pub struct Page { pub has_previous_page: bool, /// The items in the page - pub edges: Vec, + pub edges: Vec>, } -impl Page { +impl Page { /// Map the items in this page with the given function /// /// # Parameters /// /// * `f`: The function to map the items with #[must_use] - pub fn map(self, f: F) -> Page + pub fn map(self, mut f: F) -> Page where F: FnMut(T) -> T2, { - let edges = self.edges.into_iter().map(f).collect(); + let edges = self + .edges + .into_iter() + .map(|edge| Edge { + cursor: edge.cursor, + node: f(edge.node), + }) + .collect(); Page { has_next_page: self.has_next_page, has_previous_page: self.has_previous_page, @@ -183,11 +213,21 @@ impl Page { /// # Errors /// /// Returns the first error encountered while mapping the items - pub fn try_map(self, f: F) -> Result, E> + pub fn try_map(self, mut f: F) -> Result, E> where F: FnMut(T) -> Result, { - let edges: Result, E> = self.edges.into_iter().map(f).collect(); + let edges: Result>, E> = self + .edges + .into_iter() + .map(|edge| { + Ok(Edge { + cursor: edge.cursor, + node: f(edge.node)?, + }) + }) + .collect(); + Ok(Page { has_next_page: self.has_next_page, has_previous_page: self.has_previous_page, diff --git a/crates/storage/src/queue/tasks.rs b/crates/storage/src/queue/tasks.rs index eb16f6e29..3558314cf 100644 --- a/crates/storage/src/queue/tasks.rs +++ b/crates/storage/src/queue/tasks.rs @@ -384,7 +384,7 @@ impl ExpireInactiveOAuthSessionsJob { let last_edge = page.edges.last()?; Some(Self { threshold: self.threshold, - after: Some(last_edge.id), + after: Some(last_edge.cursor), }) } } @@ -441,7 +441,7 @@ impl ExpireInactiveCompatSessionsJob { let last_edge = page.edges.last()?; Some(Self { threshold: self.threshold, - after: Some(last_edge.id), + after: Some(last_edge.cursor), }) } } @@ -498,7 +498,7 @@ impl ExpireInactiveUserSessionsJob { let last_edge = page.edges.last()?; Some(Self { threshold: self.threshold, - after: Some(last_edge.id), + after: Some(last_edge.cursor), }) } } From 55120c909b173d88ba1efd45c5b24151af9bcc0f Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 29 Sep 2025 15:08:46 +0200 Subject: [PATCH 084/296] Adapt most code to use the new edges and cursors --- crates/cli/src/commands/manage.rs | 5 +- crates/cli/src/sync.rs | 3 +- .../src/graphql/model/browser_sessions.rs | 2 +- crates/handlers/src/graphql/model/users.rs | 51 +++++++++---------- crates/handlers/src/graphql/query/session.rs | 7 +-- .../src/graphql/query/upstream_oauth.rs | 6 +-- crates/handlers/src/graphql/query/user.rs | 11 ++-- crates/tasks/src/matrix.rs | 11 ++-- crates/tasks/src/recovery.rs | 18 ++----- crates/tasks/src/sessions.rs | 14 ++--- 10 files changed, 62 insertions(+), 66 deletions(-) diff --git a/crates/cli/src/commands/manage.rs b/crates/cli/src/commands/manage.rs index 0b0121078..5bbd870ea 100644 --- a/crates/cli/src/commands/manage.rs +++ b/crates/cli/src/commands/manage.rs @@ -390,9 +390,10 @@ impl Options { info!("The following users can request admin privileges ({total} total):"); loop { let page = repo.user().list(filter, cursor).await?; - for user in page.edges { + for edge in page.edges { + let user = edge.node; info!(%user.id, username = %user.username); - cursor = cursor.after(user.id); + cursor = cursor.after(edge.cursor); } if !page.has_next_page { diff --git a/crates/cli/src/sync.rs b/crates/cli/src/sync.rs index 4b8c388c3..e66b3aa50 100644 --- a/crates/cli/src/sync.rs +++ b/crates/cli/src/sync.rs @@ -132,7 +132,8 @@ pub async fn config_sync( let mut existing_enabled_ids = BTreeSet::new(); let mut existing_disabled = BTreeMap::new(); // Process the existing providers - for provider in page.edges { + for edge in page.edges { + let provider = edge.node; if provider.enabled() { if config_ids.contains(&provider.id) { existing_enabled_ids.insert(provider.id); diff --git a/crates/handlers/src/graphql/model/browser_sessions.rs b/crates/handlers/src/graphql/model/browser_sessions.rs index 925288067..08ba25830 100644 --- a/crates/handlers/src/graphql/model/browser_sessions.rs +++ b/crates/handlers/src/graphql/model/browser_sessions.rs @@ -172,7 +172,7 @@ impl BrowserSession { connection .edges - .extend(page.edges.into_iter().map(|s| match s { + .extend(page.edges.into_iter().map(|edge| match edge.node { mas_storage::app_session::AppSession::Compat(session) => Edge::new( OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)), AppSession::CompatSession(Box::new(CompatSession::new(*session))), diff --git a/crates/handlers/src/graphql/model/users.rs b/crates/handlers/src/graphql/model/users.rs index 11522c6b4..7e615df7d 100644 --- a/crates/handlers/src/graphql/model/users.rs +++ b/crates/handlers/src/graphql/model/users.rs @@ -125,10 +125,10 @@ impl User { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|u| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::CompatSsoLogin, u.id)), - CompatSsoLogin(u), + OpaqueCursor(NodeCursor(NodeType::CompatSsoLogin, edge.cursor)), + CompatSsoLogin(edge.node), ) })); @@ -219,14 +219,13 @@ impl User { page.has_next_page, PreloadedTotalCount(count), ); - connection - .edges - .extend(page.edges.into_iter().map(|(session, sso_login)| { - Edge::new( - OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)), - CompatSession::new(session).with_loaded_sso_login(sso_login), - ) - })); + connection.edges.extend(page.edges.into_iter().map(|edge| { + let (session, sso_login) = edge.node; + Edge::new( + OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)), + CompatSession::new(session).with_loaded_sso_login(sso_login), + ) + })); Ok::<_, async_graphql::Error>(connection) }, @@ -305,10 +304,10 @@ impl User { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|u| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::BrowserSession, u.id)), - BrowserSession(u), + OpaqueCursor(NodeCursor(NodeType::BrowserSession, edge.cursor)), + BrowserSession(edge.node), ) })); @@ -373,10 +372,10 @@ impl User { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|u| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::UserEmail, u.id)), - UserEmail(u), + OpaqueCursor(NodeCursor(NodeType::UserEmail, edge.cursor)), + UserEmail(edge.node), ) })); @@ -480,10 +479,10 @@ impl User { PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|s| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::OAuth2Session, s.id)), - OAuth2Session(s), + OpaqueCursor(NodeCursor(NodeType::OAuth2Session, edge.cursor)), + OAuth2Session(edge.node), ) })); @@ -547,10 +546,10 @@ impl User { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|s| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Link, s.id)), - UpstreamOAuth2Link::new(s), + OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Link, edge.cursor)), + UpstreamOAuth2Link::new(edge.node), ) })); @@ -689,13 +688,13 @@ impl User { connection .edges - .extend(page.edges.into_iter().map(|s| match s { + .extend(page.edges.into_iter().map(|edge| match edge.node { mas_storage::app_session::AppSession::Compat(session) => Edge::new( - OpaqueCursor(NodeCursor(NodeType::CompatSession, session.id)), + OpaqueCursor(NodeCursor(NodeType::CompatSession, edge.cursor)), AppSession::CompatSession(Box::new(CompatSession::new(*session))), ), mas_storage::app_session::AppSession::OAuth2(session) => Edge::new( - OpaqueCursor(NodeCursor(NodeType::OAuth2Session, session.id)), + OpaqueCursor(NodeCursor(NodeType::OAuth2Session, edge.cursor)), AppSession::OAuth2Session(Box::new(OAuth2Session(*session))), ), })); diff --git a/crates/handlers/src/graphql/query/session.rs b/crates/handlers/src/graphql/query/session.rs index 921009ee9..82ca55fd9 100644 --- a/crates/handlers/src/graphql/query/session.rs +++ b/crates/handlers/src/graphql/query/session.rs @@ -68,7 +68,8 @@ impl SessionQuery { ); } - if let Some((compat_session, sso_login)) = compat_sessions.edges.into_iter().next() { + if let Some(edge) = compat_sessions.edges.into_iter().next() { + let (compat_session, sso_login) = edge.node; repo.cancel().await?; return Ok(Some(Session::CompatSession(Box::new( @@ -92,10 +93,10 @@ impl SessionQuery { ); } - if let Some(session) = sessions.edges.into_iter().next() { + if let Some(edge) = sessions.edges.into_iter().next() { repo.cancel().await?; return Ok(Some(Session::OAuth2Session(Box::new(OAuth2Session( - session, + edge.node, ))))); } repo.cancel().await?; diff --git a/crates/handlers/src/graphql/query/upstream_oauth.rs b/crates/handlers/src/graphql/query/upstream_oauth.rs index f52c21f82..f0b4ceee6 100644 --- a/crates/handlers/src/graphql/query/upstream_oauth.rs +++ b/crates/handlers/src/graphql/query/upstream_oauth.rs @@ -130,10 +130,10 @@ impl UpstreamOAuthQuery { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend(page.edges.into_iter().map(|p| { + connection.edges.extend(page.edges.into_iter().map(|edge| { Edge::new( - OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Provider, p.id)), - UpstreamOAuth2Provider::new(p), + OpaqueCursor(NodeCursor(NodeType::UpstreamOAuth2Provider, edge.cursor)), + UpstreamOAuth2Provider::new(edge.node), ) })); diff --git a/crates/handlers/src/graphql/query/user.rs b/crates/handlers/src/graphql/query/user.rs index 364319e57..bb55ef67b 100644 --- a/crates/handlers/src/graphql/query/user.rs +++ b/crates/handlers/src/graphql/query/user.rs @@ -143,11 +143,12 @@ impl UserQuery { page.has_next_page, PreloadedTotalCount(count), ); - connection.edges.extend( - page.edges.into_iter().map(|p| { - Edge::new(OpaqueCursor(NodeCursor(NodeType::User, p.id)), User(p)) - }), - ); + connection.edges.extend(page.edges.into_iter().map(|edge| { + Edge::new( + OpaqueCursor(NodeCursor(NodeType::User, edge.cursor)), + User(edge.node), + ) + })); Ok::<_, async_graphql::Error>(connection) }, diff --git a/crates/tasks/src/matrix.rs b/crates/tasks/src/matrix.rs index 87e052d20..2acd9372e 100644 --- a/crates/tasks/src/matrix.rs +++ b/crates/tasks/src/matrix.rs @@ -203,11 +203,12 @@ impl RunnableJob for SyncDevicesJob { .await .map_err(JobError::retry)?; - for (compat_session, _) in page.edges { + for edge in page.edges { + let (compat_session, _) = edge.node; if let Some(ref device) = compat_session.device { devices.insert(device.as_str().to_owned()); } - cursor = cursor.after(compat_session.id); + cursor = cursor.after(edge.cursor); } if !page.has_next_page { @@ -227,14 +228,14 @@ impl RunnableJob for SyncDevicesJob { .await .map_err(JobError::retry)?; - for oauth2_session in page.edges { - for scope in &*oauth2_session.scope { + for edge in page.edges { + for scope in &*edge.node.scope { if let Some(device) = Device::from_scope_token(scope) { devices.insert(device.as_str().to_owned()); } } - cursor = cursor.after(oauth2_session.id); + cursor = cursor.after(edge.cursor); } if !page.has_next_page { diff --git a/crates/tasks/src/recovery.rs b/crates/tasks/src/recovery.rs index 03e02d57b..51afcc295 100644 --- a/crates/tasks/src/recovery.rs +++ b/crates/tasks/src/recovery.rs @@ -70,26 +70,18 @@ impl RunnableJob for SendAccountRecoveryEmailsJob { .await .map_err(JobError::retry)?; - for email in page.edges { + for edge in page.edges { let ticket = Alphanumeric.sample_string(&mut rng, 32); let ticket = repo .user_recovery() - .add_ticket(&mut rng, clock, &session, &email, ticket) + .add_ticket(&mut rng, clock, &session, &edge.node, ticket) .await .map_err(JobError::retry)?; - let user_email = repo - .user_email() - .lookup(email.id) - .await - .map_err(JobError::retry)? - .context("User email not found") - .map_err(JobError::fail)?; - let user = repo .user() - .lookup(user_email.user_id) + .lookup(edge.node.user_id) .await .map_err(JobError::retry)? .context("User not found") @@ -97,7 +89,7 @@ impl RunnableJob for SendAccountRecoveryEmailsJob { let url = url_builder.account_recovery_link(ticket.ticket); - let address: Address = user_email.email.parse().map_err(JobError::fail)?; + let address: Address = edge.node.email.parse().map_err(JobError::fail)?; let mailbox = Mailbox::new(Some(user.username.clone()), address); info!("Sending recovery email to {}", mailbox); @@ -112,7 +104,7 @@ impl RunnableJob for SendAccountRecoveryEmailsJob { ); } - cursor = cursor.after(email.id); + cursor = cursor.after(edge.cursor); } if !page.has_next_page { diff --git a/crates/tasks/src/sessions.rs b/crates/tasks/src/sessions.rs index d10d908da..eede69d51 100644 --- a/crates/tasks/src/sessions.rs +++ b/crates/tasks/src/sessions.rs @@ -110,7 +110,7 @@ impl RunnableJob for ExpireInactiveOAuthSessionsJob { } for edge in page.edges { - if let Some(user_id) = edge.user_id { + if let Some(user_id) = edge.node.user_id { let inserted = users_synced.insert(user_id); if inserted { tracing::info!(user.id = %user_id, "Scheduling devices sync for user"); @@ -128,7 +128,7 @@ impl RunnableJob for ExpireInactiveOAuthSessionsJob { } repo.oauth2_session() - .finish(clock, edge) + .finish(clock, edge.node) .await .map_err(JobError::retry)?; } @@ -174,14 +174,14 @@ impl RunnableJob for ExpireInactiveCompatSessionsJob { } for edge in page.edges { - let inserted = users_synced.insert(edge.user_id); + let inserted = users_synced.insert(edge.node.user_id); if inserted { - tracing::info!(user.id = %edge.user_id, "Scheduling devices sync for user"); + tracing::info!(user.id = %edge.node.user_id, "Scheduling devices sync for user"); repo.queue_job() .schedule_job_later( &mut rng, clock, - SyncDevicesJob::new_for_id(edge.user_id), + SyncDevicesJob::new_for_id(edge.node.user_id), clock.now() + delay, ) .await @@ -190,7 +190,7 @@ impl RunnableJob for ExpireInactiveCompatSessionsJob { } repo.compat_session() - .finish(clock, edge) + .finish(clock, edge.node) .await .map_err(JobError::retry)?; } @@ -230,7 +230,7 @@ impl RunnableJob for ExpireInactiveUserSessionsJob { for edge in page.edges { repo.browser_session() - .finish(clock, edge) + .finish(clock, edge.node) .await .map_err(JobError::retry)?; } From 209bc05ae701aa5e5eca1d862c9c16341ed0ab64 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 29 Sep 2025 15:09:15 +0200 Subject: [PATCH 085/296] Admin API: add pagination cursors to list endpoints --- crates/handlers/src/admin/response.rs | 45 ++++- .../src/admin/v1/compat_sessions/list.rs | 33 +++- .../src/admin/v1/oauth2_sessions/list.rs | 13 +- .../src/admin/v1/upstream_oauth_links/list.rs | 64 ++++++- .../admin/v1/upstream_oauth_providers/list.rs | 53 +++++- .../handlers/src/admin/v1/user_emails/list.rs | 40 +++- .../admin/v1/user_registration_tokens/list.rs | 163 +++++++++++++++- .../src/admin/v1/user_sessions/list.rs | 49 ++++- crates/handlers/src/admin/v1/users/list.rs | 8 +- .../src/upstream_oauth2/backchannel_logout.rs | 6 +- crates/handlers/src/upstream_oauth2/link.rs | 4 +- docs/api/spec.json | 174 ++++++++++++++++++ 12 files changed, 613 insertions(+), 39 deletions(-) diff --git a/crates/handlers/src/admin/response.rs b/crates/handlers/src/admin/response.rs index 19f0e8040..986ec2479 100644 --- a/crates/handlers/src/admin/response.rs +++ b/crates/handlers/src/admin/response.rs @@ -6,7 +6,7 @@ #![allow(clippy::module_name_repetitions)] -use mas_storage::Pagination; +use mas_storage::{Pagination, pagination::Edge}; use schemars::JsonSchema; use serde::Serialize; use ulid::Ulid; @@ -102,7 +102,7 @@ impl PaginatedResponse { base, current_pagination .clear_before() - .after(page.edges.last().unwrap().id()), + .after(page.edges.last().unwrap().cursor), ) }), prev: if page.has_previous_page { @@ -110,14 +110,18 @@ impl PaginatedResponse { base, current_pagination .clear_after() - .before(page.edges.first().unwrap().id()), + .before(page.edges.first().unwrap().cursor), )) } else { None }, }; - let data = page.edges.into_iter().map(SingleResource::new).collect(); + let data = page + .edges + .into_iter() + .map(SingleResource::from_edge) + .collect(); Self { meta: PaginationMeta { count }, @@ -143,6 +147,31 @@ struct SingleResource { /// Related links links: SelfLinks, + + /// Metadata about the resource + #[serde(skip_serializing_if = "SingleResourceMeta::is_empty")] + meta: SingleResourceMeta, +} + +/// Metadata associated with a resource +#[derive(Serialize, JsonSchema)] +struct SingleResourceMeta { + /// Information about the pagination of the resource + #[serde(skip_serializing_if = "Option::is_none")] + page: Option, +} + +impl SingleResourceMeta { + fn is_empty(&self) -> bool { + self.page.is_none() + } +} + +/// Pagination metadata for a resource +#[derive(Serialize, JsonSchema)] +struct SingleResourceMetaPage { + /// The cursor of this resource in the paginated result + cursor: String, } impl SingleResource { @@ -153,8 +182,16 @@ impl SingleResource { id: resource.id(), attributes: resource, links: SelfLinks { self_ }, + meta: SingleResourceMeta { page: None }, } } + + fn from_edge(edge: Edge) -> Self { + let cursor = edge.cursor.to_string(); + let mut resource = Self::new(edge.node); + resource.meta.page = Some(SingleResourceMetaPage { cursor }); + resource + } } /// Related links diff --git a/crates/handlers/src/admin/v1/compat_sessions/list.rs b/crates/handlers/src/admin/v1/compat_sessions/list.rs index debb2a304..2ab788a2b 100644 --- a/crates/handlers/src/admin/v1/compat_sessions/list.rs +++ b/crates/handlers/src/admin/v1/compat_sessions/list.rs @@ -137,7 +137,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p let sessions = CompatSession::samples(); let pagination = mas_storage::Pagination::first(sessions.len()); let page = Page { - edges: sessions.into(), + edges: sessions + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -299,6 +305,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y" + }, + "meta": { + "page": { + "cursor": "01FSHNB530AAPR7PEV8KNBZD5Y" + } } }, { @@ -318,6 +329,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW" + }, + "meta": { + "page": { + "cursor": "01FSHNCZP0PPF7X0EVMJNECPZW" + } } } ], @@ -362,6 +378,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y" + }, + "meta": { + "page": { + "cursor": "01FSHNB530AAPR7PEV8KNBZD5Y" + } } } ], @@ -403,6 +424,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y" + }, + "meta": { + "page": { + "cursor": "01FSHNB530AAPR7PEV8KNBZD5Y" + } } } ], @@ -444,6 +470,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW" + }, + "meta": { + "page": { + "cursor": "01FSHNCZP0PPF7X0EVMJNECPZW" + } } } ], diff --git a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs index 52b597edc..b24877c45 100644 --- a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs +++ b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs @@ -192,7 +192,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p let sessions = OAuth2Session::samples(); let pagination = mas_storage::Pagination::first(sessions.len()); let page = Page { - edges: sessions.into(), + edges: sessions + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -354,6 +360,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MKGTBNZ16RDR3PVY" + } } } ], diff --git a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs index 59efe6541..4c2eeb7d5 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs @@ -112,7 +112,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { let links = UpstreamOAuthLink::samples(); let pagination = mas_storage::Pagination::first(links.len()); let page = Page { - edges: links.into(), + edges: links + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -296,7 +302,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 3 @@ -314,6 +320,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0AQZQP8DX40GD59PW" + } } }, { @@ -328,6 +339,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4" + } } }, { @@ -342,6 +358,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07" + } } } ], @@ -351,7 +372,7 @@ mod tests { "last": "/api/admin/v1/upstream-oauth-links?page[last]=10" } } - "###); + "#); // Filter by user ID let request = Request::get(format!( @@ -364,7 +385,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 2 @@ -382,6 +403,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0AQZQP8DX40GD59PW" + } } }, { @@ -396,6 +422,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0QHEHKX2JNQ2A2D07" + } } } ], @@ -405,7 +436,7 @@ mod tests { "last": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10" } } - "###); + "#); // Filter by provider let request = Request::get(format!( @@ -418,7 +449,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 2 @@ -436,6 +467,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0AQZQP8DX40GD59PW" + } } }, { @@ -450,6 +486,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0PJZ6DZNTAA1XKPT4" + } } } ], @@ -459,7 +500,7 @@ mod tests { "last": "/api/admin/v1/upstream-oauth-links?filter[provider]=01FSHN9AG09NMZYX8MFYH578R9&page[last]=10" } } - "###); + "#); // Filter by subject let request = Request::get(format!( @@ -472,7 +513,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -490,6 +531,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0AQZQP8DX40GD59PW" + } } } ], @@ -499,6 +545,6 @@ mod tests { "last": "/api/admin/v1/upstream-oauth-links?filter[subject]=subject1&page[last]=10" } } - "###); + "#); } } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs index dc5f2cc9c..6439e2fdd 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -84,7 +84,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { let providers = UpstreamOAuthProvider::samples(); let pagination = mas_storage::Pagination::first(providers.len()); let page = Page { - edges: providers.into(), + edges: providers + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -291,6 +297,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -305,6 +316,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -319,6 +335,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -364,6 +385,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -378,6 +404,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -423,6 +454,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } } ], @@ -469,6 +505,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -483,6 +524,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } } ], @@ -525,6 +571,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], diff --git a/crates/handlers/src/admin/v1/user_emails/list.rs b/crates/handlers/src/admin/v1/user_emails/list.rs index 92dfe12c2..edf64e989 100644 --- a/crates/handlers/src/admin/v1/user_emails/list.rs +++ b/crates/handlers/src/admin/v1/user_emails/list.rs @@ -99,7 +99,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { let emails = UserEmail::samples(); let pagination = mas_storage::Pagination::first(emails.len()); let page = Page { - edges: emails.into(), + edges: emails + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -209,7 +215,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - insta::assert_json_snapshot!(body, @r###" + insta::assert_json_snapshot!(body, @r#" { "meta": { "count": 2 @@ -225,6 +231,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09NMZYX8MFYH578R9" + } } }, { @@ -237,6 +248,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-emails/01FSHN9AG0KEPHYQQXW9XPTX6Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0KEPHYQQXW9XPTX6Z" + } } } ], @@ -246,7 +262,7 @@ mod tests { "last": "/api/admin/v1/user-emails?page[last]=10" } } - "###); + "#); // Filter by user let request = Request::get(format!( @@ -258,7 +274,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - insta::assert_json_snapshot!(body, @r###" + insta::assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -274,6 +290,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09NMZYX8MFYH578R9" + } } } ], @@ -283,7 +304,7 @@ mod tests { "last": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10" } } - "###); + "#); // Filter by email let request = Request::get("/api/admin/v1/user-emails?filter[email]=alice@example.com") @@ -292,7 +313,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - insta::assert_json_snapshot!(body, @r###" + insta::assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -308,6 +329,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09NMZYX8MFYH578R9" + } } } ], @@ -317,6 +343,6 @@ mod tests { "last": "/api/admin/v1/user-emails?filter[email]=alice@example.com&page[last]=10" } } - "###); + "#); } } diff --git a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs index 546491536..08acad4df 100644 --- a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs +++ b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs @@ -112,7 +112,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { let tokens = UserRegistrationToken::samples(); let pagination = mas_storage::Pagination::first(tokens.len()); let page = Page { - edges: tokens.into(), + edges: tokens + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -300,6 +306,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } }, { @@ -317,6 +328,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -334,6 +350,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -351,6 +372,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } }, { @@ -368,6 +394,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -416,6 +447,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -433,6 +469,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -473,6 +514,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } }, { @@ -490,6 +536,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -507,6 +558,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -555,6 +611,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -572,6 +633,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -612,6 +678,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } }, { @@ -629,6 +700,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -646,6 +722,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -694,6 +775,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } } ], @@ -734,6 +820,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -751,6 +842,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -768,6 +864,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } }, { @@ -785,6 +886,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -833,6 +939,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } }, { @@ -850,6 +961,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -890,6 +1006,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } }, { @@ -907,6 +1028,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -924,6 +1050,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -974,6 +1105,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], @@ -1022,6 +1158,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG064K8BYZXSY5G511Z" + } } }, { @@ -1039,6 +1180,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG07HNEZXNQM2KNBNF6" + } } } ], @@ -1080,6 +1226,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG09AVTNSQFMSR34AJC" + } } }, { @@ -1097,6 +1248,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -1138,6 +1294,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0S3ZJD8CXQ7F11KXN" + } } } ], diff --git a/crates/handlers/src/admin/v1/user_sessions/list.rs b/crates/handlers/src/admin/v1/user_sessions/list.rs index 28a52edf2..555d15d23 100644 --- a/crates/handlers/src/admin/v1/user_sessions/list.rs +++ b/crates/handlers/src/admin/v1/user_sessions/list.rs @@ -123,7 +123,13 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p let sessions = UserSession::samples(); let pagination = mas_storage::Pagination::first(sessions.len()); let page = Page { - edges: sessions.into(), + edges: sessions + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; @@ -241,7 +247,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 2 @@ -260,6 +266,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } }, { @@ -275,6 +286,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z" + }, + "meta": { + "page": { + "cursor": "01FSHNB530AJ6AC5HQ9X6H4RP4" + } } } ], @@ -284,7 +300,7 @@ mod tests { "last": "/api/admin/v1/user-sessions?page[last]=10" } } - "###); + "#); // Filter by user let request = Request::get(format!( @@ -296,7 +312,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -315,6 +331,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -324,7 +345,7 @@ mod tests { "last": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&page[last]=10" } } - "###); + "#); // Filter by status (active) let request = Request::get("/api/admin/v1/user-sessions?filter[status]=active") @@ -333,7 +354,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -352,6 +373,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9" + }, + "meta": { + "page": { + "cursor": "01FSHN9AG0MZAA6S4AF7CTV32E" + } } } ], @@ -361,7 +387,7 @@ mod tests { "last": "/api/admin/v1/user-sessions?filter[status]=active&page[last]=10" } } - "###); + "#); // Filter by status (finished) let request = Request::get("/api/admin/v1/user-sessions?filter[status]=finished") @@ -370,7 +396,7 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::OK); let body: serde_json::Value = response.json(); - assert_json_snapshot!(body, @r###" + assert_json_snapshot!(body, @r#" { "meta": { "count": 1 @@ -389,6 +415,11 @@ mod tests { }, "links": { "self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z" + }, + "meta": { + "page": { + "cursor": "01FSHNB530AJ6AC5HQ9X6H4RP4" + } } } ], @@ -398,6 +429,6 @@ mod tests { "last": "/api/admin/v1/user-sessions?filter[status]=finished&page[last]=10" } } - "###); + "#); } } diff --git a/crates/handlers/src/admin/v1/users/list.rs b/crates/handlers/src/admin/v1/users/list.rs index da70e5807..cdfe59d4a 100644 --- a/crates/handlers/src/admin/v1/users/list.rs +++ b/crates/handlers/src/admin/v1/users/list.rs @@ -137,7 +137,13 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { let users = User::samples(); let pagination = mas_storage::Pagination::first(users.len()); let page = Page { - edges: users.into(), + edges: users + .into_iter() + .map(|node| mas_storage::pagination::Edge { + cursor: node.id(), + node, + }) + .collect(), has_next_page: true, has_previous_page: false, }; diff --git a/crates/handlers/src/upstream_oauth2/backchannel_logout.rs b/crates/handlers/src/upstream_oauth2/backchannel_logout.rs index 76a7b574c..63454741c 100644 --- a/crates/handlers/src/upstream_oauth2/backchannel_logout.rs +++ b/crates/handlers/src/upstream_oauth2/backchannel_logout.rs @@ -267,9 +267,9 @@ pub(crate) async fn post( .browser_session() .list(browser_session_filter, cursor) .await?; - for browser_session in browser_sessions.edges { - user_ids.insert(browser_session.user.id); - cursor = cursor.after(browser_session.id); + for edge in browser_sessions.edges { + user_ids.insert(edge.node.user.id); + cursor = cursor.after(edge.cursor); } if !browser_sessions.has_next_page { diff --git a/crates/handlers/src/upstream_oauth2/link.rs b/crates/handlers/src/upstream_oauth2/link.rs index a3d4c1bb9..d9577bafd 100644 --- a/crates/handlers/src/upstream_oauth2/link.rs +++ b/crates/handlers/src/upstream_oauth2/link.rs @@ -1212,9 +1212,9 @@ mod tests { .list(UserEmailFilter::new().for_user(&user), Pagination::first(1)) .await .unwrap(); - let email = page.edges.first().expect("email exists"); + let edge = page.edges.first().expect("email exists"); - assert_eq!(email.email, "john@example.com"); + assert_eq!(edge.node.email, "john@example.com"); } #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] diff --git a/docs/api/spec.json b/docs/api/spec.json index 166436454..b730e30ce 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -171,6 +171,11 @@ }, "links": { "self": "/api/admin/v1/compat-sessions/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -190,6 +195,11 @@ }, "links": { "self": "/api/admin/v1/compat-sessions/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -209,6 +219,11 @@ }, "links": { "self": "/api/admin/v1/compat-sessions/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -473,6 +488,11 @@ }, "links": { "self": "/api/admin/v1/oauth2-sessions/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -492,6 +512,11 @@ }, "links": { "self": "/api/admin/v1/oauth2-sessions/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -511,6 +536,11 @@ }, "links": { "self": "/api/admin/v1/oauth2-sessions/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -964,6 +994,11 @@ }, "links": { "self": "/api/admin/v1/users/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -979,6 +1014,11 @@ }, "links": { "self": "/api/admin/v1/users/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -994,6 +1034,11 @@ }, "links": { "self": "/api/admin/v1/users/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -1798,6 +1843,11 @@ }, "links": { "self": "/api/admin/v1/user-emails/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } } ], @@ -2146,6 +2196,11 @@ }, "links": { "self": "/api/admin/v1/user-sessions/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -2161,6 +2216,11 @@ }, "links": { "self": "/api/admin/v1/user-sessions/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -2176,6 +2236,11 @@ }, "links": { "self": "/api/admin/v1/user-sessions/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -2408,6 +2473,11 @@ }, "links": { "self": "/api/admin/v1/user-registration-tokens/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -2425,6 +2495,11 @@ }, "links": { "self": "/api/admin/v1/user-registration-tokens/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } } ], @@ -2941,6 +3016,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-links/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -2955,6 +3035,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-links/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -2969,6 +3054,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-links/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -3316,6 +3406,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" + }, + "meta": { + "page": { + "cursor": "01040G2081040G2081040G2081" + } } }, { @@ -3330,6 +3425,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/02081040G2081040G2081040G2" + }, + "meta": { + "page": { + "cursor": "02081040G2081040G2081040G2" + } } }, { @@ -3344,6 +3444,11 @@ }, "links": { "self": "/api/admin/v1/upstream-oauth-providers/030C1G60R30C1G60R30C1G60R3" + }, + "meta": { + "page": { + "cursor": "030C1G60R30C1G60R30C1G60R3" + } } } ], @@ -3568,6 +3673,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -3586,6 +3692,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -3674,6 +3784,30 @@ } } }, + "SingleResourceMeta": { + "description": "Metadata associated with a resource", + "type": "object", + "properties": { + "page": { + "description": "Information about the pagination of the resource", + "$ref": "#/components/schemas/SingleResourceMetaPage", + "nullable": true + } + } + }, + "SingleResourceMetaPage": { + "description": "Pagination metadata for a resource", + "type": "object", + "required": [ + "cursor" + ], + "properties": { + "cursor": { + "description": "The cursor of this resource in the paginated result", + "type": "string" + } + } + }, "PaginationLinks": { "description": "Related links", "type": "object", @@ -3849,6 +3983,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -3867,6 +4002,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -3989,6 +4128,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4007,6 +4147,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4094,6 +4238,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4112,6 +4257,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4295,6 +4444,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4313,6 +4463,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4430,6 +4584,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4448,6 +4603,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4567,6 +4726,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4585,6 +4745,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4756,6 +4920,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4774,6 +4939,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, @@ -4898,6 +5067,7 @@ "attributes", "id", "links", + "meta", "type" ], "properties": { @@ -4916,6 +5086,10 @@ "links": { "description": "Related links", "$ref": "#/components/schemas/SelfLinks" + }, + "meta": { + "description": "Metadata about the resource", + "$ref": "#/components/schemas/SingleResourceMeta" } } }, From 14322661221c9dbc144b9162ea6b85865cdf8415 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:54:21 +0000 Subject: [PATCH 086/296] build(deps): bump psl from 2.1.141 to 2.1.145 Bumps [psl](https://github.com/addr-rs/psl) from 2.1.141 to 2.1.145. - [Release notes](https://github.com/addr-rs/psl/releases) - [Commits](https://github.com/addr-rs/psl/compare/v2.1.141...v2.1.145) --- updated-dependencies: - dependency-name: psl dependency-version: 2.1.145 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c75fc78d0..8e6f94691 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4679,9 +4679,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.141" +version = "2.1.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c10a4dce9ad24c1fad826cffc79a624cf626bfaddb466e969368a53d877b30" +checksum = "f9bc7bed4cdf5168c58514ad64f37615f6683882209e2b6ba345cda0c6b8d949" dependencies = [ "psl-types", ] diff --git a/Cargo.toml b/Cargo.toml index be3ca88b4..831aadcaa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -476,7 +476,7 @@ features = ["std", "pkcs5", "encryption"] # Public Suffix List [workspace.dependencies.psl] -version = "2.1.141" +version = "2.1.145" # High-precision clock [workspace.dependencies.quanta] From 39fc59deb2fbc52a7745012508a24bd560927f88 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 29 Sep 2025 18:27:22 +0200 Subject: [PATCH 087/296] Admin API: parameter to include total number of items This allows removing the count calculation when not needed, or to skip the list of items entirely. --- crates/handlers/src/admin/params.rs | 51 +++++- crates/handlers/src/admin/response.rs | 51 +++++- .../src/admin/v1/compat_sessions/list.rs | 41 +++-- .../src/admin/v1/oauth2_sessions/list.rs | 41 +++-- .../src/admin/v1/upstream_oauth_links/list.rs | 41 +++-- .../admin/v1/upstream_oauth_providers/list.rs | 44 +++-- .../handlers/src/admin/v1/user_emails/list.rs | 41 +++-- .../admin/v1/user_registration_tokens/list.rs | 44 +++-- .../src/admin/v1/user_sessions/list.rs | 41 +++-- crates/handlers/src/admin/v1/users/list.rs | 36 ++-- docs/api/spec.json | 164 +++++++++++++++--- 11 files changed, 453 insertions(+), 142 deletions(-) diff --git a/crates/handlers/src/admin/params.rs b/crates/handlers/src/admin/params.rs index 633917d9a..67ec3316f 100644 --- a/crates/handlers/src/admin/params.rs +++ b/crates/handlers/src/admin/params.rs @@ -7,7 +7,7 @@ // Generated code from schemars violates this rule #![allow(clippy::str_to_string)] -use std::num::NonZeroUsize; +use std::{borrow::Cow, num::NonZeroUsize}; use aide::OperationIo; use axum::{ @@ -64,6 +64,34 @@ impl std::ops::Deref for UlidPathParam { /// The default page size if not specified const DEFAULT_PAGE_SIZE: usize = 10; +#[derive(Deserialize, JsonSchema, Clone, Copy, Default, Debug)] +pub enum IncludeCount { + /// Include the total number of items (default) + #[default] + #[serde(rename = "true")] + True, + + /// Do not include the total number of items + #[serde(rename = "false")] + False, + + /// Only include the total number of items, skip the items themselves + #[serde(rename = "only")] + Only, +} + +impl IncludeCount { + pub(crate) fn add_to_base(self, base: &str) -> Cow<'_, str> { + let separator = if base.contains('?') { '&' } else { '?' }; + match self { + // This is the default, don't add anything + Self::True => Cow::Borrowed(base), + Self::False => format!("{base}{separator}count=false").into(), + Self::Only => format!("{base}{separator}count=only").into(), + } + } +} + #[derive(Deserialize, JsonSchema, Clone, Copy)] struct PaginationParams { /// Retrieve the items before the given ID @@ -83,6 +111,10 @@ struct PaginationParams { /// Retrieve the last N items #[serde(rename = "page[last]")] last: Option, + + /// Include the total number of items. Defaults to `true`. + #[serde(rename = "count")] + include_count: Option, } #[derive(Debug, thiserror::Error)] @@ -107,7 +139,7 @@ impl IntoResponse for PaginationRejection { /// An extractor for pagination parameters in the query string #[derive(OperationIo, Debug, Clone, Copy)] #[aide(input_with = "Query")] -pub struct Pagination(pub mas_storage::Pagination); +pub struct Pagination(pub mas_storage::Pagination, pub IncludeCount); impl FromRequestParts for Pagination { type Rejection = PaginationRejection; @@ -130,11 +162,14 @@ impl FromRequestParts for Pagination { (None, Some(last)) => (PaginationDirection::Backward, last.into()), }; - Ok(Self(mas_storage::Pagination { - before: params.before, - after: params.after, - direction, - count, - })) + Ok(Self( + mas_storage::Pagination { + before: params.before, + after: params.after, + direction, + count, + }, + params.include_count.unwrap_or_default(), + )) } } diff --git a/crates/handlers/src/admin/response.rs b/crates/handlers/src/admin/response.rs index 19f0e8040..c5065c7da 100644 --- a/crates/handlers/src/admin/response.rs +++ b/crates/handlers/src/admin/response.rs @@ -21,10 +21,12 @@ struct PaginationLinks { self_: String, /// The link to the first page of results - first: String, + #[serde(skip_serializing_if = "Option::is_none")] + first: Option, /// The link to the last page of results - last: String, + #[serde(skip_serializing_if = "Option::is_none")] + last: Option, /// The link to the next page of results /// @@ -42,17 +44,26 @@ struct PaginationLinks { #[derive(Serialize, JsonSchema)] struct PaginationMeta { /// The total number of results - count: usize, + #[serde(skip_serializing_if = "Option::is_none")] + count: Option, +} + +impl PaginationMeta { + fn is_empty(&self) -> bool { + self.count.is_none() + } } /// A top-level response with a page of resources #[derive(Serialize, JsonSchema)] pub struct PaginatedResponse { /// Response metadata + #[serde(skip_serializing_if = "PaginationMeta::is_empty")] meta: PaginationMeta, /// The list of resources - data: Vec>, + #[serde(skip_serializing_if = "Option::is_none")] + data: Option>>, /// Related links links: PaginationLinks, @@ -87,16 +98,22 @@ fn url_with_pagination(base: &str, pagination: Pagination) -> String { } impl PaginatedResponse { - pub fn new( + pub fn for_page( page: mas_storage::Page, current_pagination: Pagination, - count: usize, + count: Option, base: &str, ) -> Self { let links = PaginationLinks { self_: url_with_pagination(base, current_pagination), - first: url_with_pagination(base, Pagination::first(current_pagination.count)), - last: url_with_pagination(base, Pagination::last(current_pagination.count)), + first: Some(url_with_pagination( + base, + Pagination::first(current_pagination.count), + )), + last: Some(url_with_pagination( + base, + Pagination::last(current_pagination.count), + )), next: page.has_next_page.then(|| { url_with_pagination( base, @@ -121,7 +138,23 @@ impl PaginatedResponse { Self { meta: PaginationMeta { count }, - data, + data: Some(data), + links, + } + } + + pub fn for_count_only(count: usize, base: &str) -> Self { + let links = PaginationLinks { + self_: base.to_owned(), + first: None, + last: None, + next: None, + prev: None, + }; + + Self { + meta: PaginationMeta { count: Some(count) }, + data: None, links, } } diff --git a/crates/handlers/src/admin/v1/compat_sessions/list.rs b/crates/handlers/src/admin/v1/compat_sessions/list.rs index debb2a304..96a2708af 100644 --- a/crates/handlers/src/admin/v1/compat_sessions/list.rs +++ b/crates/handlers/src/admin/v1/compat_sessions/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{CompatSession, Resource}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -143,10 +143,10 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p }; t.description("Paginated response of compatibility sessions") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), CompatSession::PATH, )) }) @@ -159,10 +159,11 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p #[tracing::instrument(name = "handler.admin.v1.compat_sessions.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = CompatSession::PATH); + let base = include_count.add_to_base(&base); let filter = CompatSessionFilter::default(); // Load the user from the filter @@ -206,15 +207,31 @@ pub async fn handler( None => filter, }; - let page = repo.compat_session().list(filter, pagination).await?; - let count = repo.compat_session().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .compat_session() + .list(filter, pagination) + .await? + .map(CompatSession::from); + let count = repo.compat_session().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .compat_session() + .list(filter, pagination) + .await? + .map(CompatSession::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.compat_session().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(CompatSession::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs index 52b597edc..8b6ff6b2b 100644 --- a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs +++ b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs @@ -25,7 +25,7 @@ use crate::{ admin::{ call_context::CallContext, model::{OAuth2Session, Resource}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -198,10 +198,10 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p }; t.description("Paginated response of OAuth 2.0 sessions") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), OAuth2Session::PATH, )) }) @@ -218,10 +218,11 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p #[tracing::instrument(name = "handler.admin.v1.oauth2_sessions.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = OAuth2Session::PATH); + let base = include_count.add_to_base(&base); let filter = OAuth2SessionFilter::default(); // Load the user from the filter @@ -300,15 +301,31 @@ pub async fn handler( None => filter, }; - let page = repo.oauth2_session().list(filter, pagination).await?; - let count = repo.oauth2_session().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .oauth2_session() + .list(filter, pagination) + .await? + .map(OAuth2Session::from); + let count = repo.oauth2_session().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .oauth2_session() + .list(filter, pagination) + .await? + .map(OAuth2Session::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.oauth2_session().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(OAuth2Session::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs index 59efe6541..068011ab7 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, UpstreamOAuthLink}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -118,10 +118,10 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { }; t.description("Paginated response of upstream OAuth 2.0 links") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), UpstreamOAuthLink::PATH, )) }) @@ -135,10 +135,11 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { #[tracing::instrument(name = "handler.admin.v1.upstream_oauth_links.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = UpstreamOAuthLink::PATH); + let base = include_count.add_to_base(&base); let filter = UpstreamOAuthLinkFilter::default(); // Load the user from the filter @@ -183,15 +184,31 @@ pub async fn handler( filter }; - let page = repo.upstream_oauth_link().list(filter, pagination).await?; - let count = repo.upstream_oauth_link().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .upstream_oauth_link() + .list(filter, pagination) + .await? + .map(UpstreamOAuthLink::from); + let count = repo.upstream_oauth_link().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .upstream_oauth_link() + .list(filter, pagination) + .await? + .map(UpstreamOAuthLink::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.upstream_oauth_link().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(UpstreamOAuthLink::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs index dc5f2cc9c..419c3552f 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -20,7 +20,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, UpstreamOAuthProvider}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -90,10 +90,10 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { }; t.description("Paginated response of upstream OAuth 2.0 providers") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), UpstreamOAuthProvider::PATH, )) }) @@ -102,10 +102,11 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { #[tracing::instrument(name = "handler.admin.v1.upstream_oauth_providers.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = UpstreamOAuthProvider::PATH); + let base = include_count.add_to_base(&base); let filter = UpstreamOAuthProviderFilter::new(); let filter = match params.enabled { @@ -114,18 +115,31 @@ pub async fn handler( None => filter, }; - let page = repo - .upstream_oauth_provider() - .list(filter, pagination) - .await?; - let count = repo.upstream_oauth_provider().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .upstream_oauth_provider() + .list(filter, pagination) + .await? + .map(UpstreamOAuthProvider::from); + let count = repo.upstream_oauth_provider().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .upstream_oauth_provider() + .list(filter, pagination) + .await? + .map(UpstreamOAuthProvider::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.upstream_oauth_provider().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(UpstreamOAuthProvider::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/user_emails/list.rs b/crates/handlers/src/admin/v1/user_emails/list.rs index 92dfe12c2..2363aba28 100644 --- a/crates/handlers/src/admin/v1/user_emails/list.rs +++ b/crates/handlers/src/admin/v1/user_emails/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, UserEmail}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -105,10 +105,10 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { }; t.description("Paginated response of user emails") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), UserEmail::PATH, )) }) @@ -121,10 +121,11 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { #[tracing::instrument(name = "handler.admin.v1.user_emails.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = UserEmail::PATH); + let base = include_count.add_to_base(&base); let filter = UserEmailFilter::default(); // Load the user from the filter @@ -150,15 +151,31 @@ pub async fn handler( None => filter, }; - let page = repo.user_email().list(filter, pagination).await?; - let count = repo.user_email().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .user_email() + .list(filter, pagination) + .await? + .map(UserEmail::from); + let count = repo.user_email().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .user_email() + .list(filter, pagination) + .await? + .map(UserEmail::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.user_email().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(UserEmail::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs index 546491536..f1700aaa7 100644 --- a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs +++ b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, UserRegistrationToken}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -118,10 +118,10 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { }; t.description("Paginated response of registration tokens") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), UserRegistrationToken::PATH, )) }) @@ -132,10 +132,11 @@ pub async fn handler( CallContext { mut repo, clock, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = UserRegistrationToken::PATH); + let base = include_count.add_to_base(&base); let now = clock.now(); let mut filter = UserRegistrationTokenFilter::new(now); @@ -155,18 +156,31 @@ pub async fn handler( filter = filter.with_valid(valid); } - let page = repo - .user_registration_token() - .list(filter, pagination) - .await?; - let count = repo.user_registration_token().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .user_registration_token() + .list(filter, pagination) + .await? + .map(|token| UserRegistrationToken::new(token, now)); + let count = repo.user_registration_token().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .user_registration_token() + .list(filter, pagination) + .await? + .map(|token| UserRegistrationToken::new(token, now)); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.user_registration_token().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(|token| UserRegistrationToken::new(token, now)), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/user_sessions/list.rs b/crates/handlers/src/admin/v1/user_sessions/list.rs index 28a52edf2..6ba1dc5f0 100644 --- a/crates/handlers/src/admin/v1/user_sessions/list.rs +++ b/crates/handlers/src/admin/v1/user_sessions/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, UserSession}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -129,10 +129,10 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p }; t.description("Paginated response of user sessions") - .example(PaginatedResponse::new( + .example(PaginatedResponse::for_page( page, pagination, - 42, + Some(42), UserSession::PATH, )) }) @@ -145,10 +145,11 @@ Use the `filter[status]` parameter to filter the sessions by their status and `p #[tracing::instrument(name = "handler.admin.v1.user_sessions.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = UserSession::PATH); + let base = include_count.add_to_base(&base); let filter = BrowserSessionFilter::default(); // Load the user from the filter @@ -175,15 +176,31 @@ pub async fn handler( None => filter, }; - let page = repo.browser_session().list(filter, pagination).await?; - let count = repo.browser_session().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo + .browser_session() + .list(filter, pagination) + .await? + .map(UserSession::from); + let count = repo.browser_session().count(filter).await?; + PaginatedResponse::for_page(page, pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo + .browser_session() + .list(filter, pagination) + .await? + .map(UserSession::from); + PaginatedResponse::for_page(page, pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.browser_session().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(UserSession::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } #[cfg(test)] diff --git a/crates/handlers/src/admin/v1/users/list.rs b/crates/handlers/src/admin/v1/users/list.rs index da70e5807..ddafa9984 100644 --- a/crates/handlers/src/admin/v1/users/list.rs +++ b/crates/handlers/src/admin/v1/users/list.rs @@ -21,7 +21,7 @@ use crate::{ admin::{ call_context::CallContext, model::{Resource, User}, - params::Pagination, + params::{IncludeCount, Pagination}, response::{ErrorResponse, PaginatedResponse}, }, impl_from_error_for_route, @@ -143,17 +143,23 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { }; t.description("Paginated response of users") - .example(PaginatedResponse::new(page, pagination, 42, User::PATH)) + .example(PaginatedResponse::for_page( + page, + pagination, + Some(42), + User::PATH, + )) }) } #[tracing::instrument(name = "handler.admin.v1.users.list", skip_all)] pub async fn handler( CallContext { mut repo, .. }: CallContext, - Pagination(pagination): Pagination, + Pagination(pagination, include_count): Pagination, params: FilterParams, ) -> Result>, RouteError> { let base = format!("{path}{params}", path = User::PATH); + let base = include_count.add_to_base(&base); let filter = UserFilter::default(); let filter = match params.admin { @@ -180,13 +186,21 @@ pub async fn handler( None => filter, }; - let page = repo.user().list(filter, pagination).await?; - let count = repo.user().count(filter).await?; + let response = match include_count { + IncludeCount::True => { + let page = repo.user().list(filter, pagination).await?; + let count = repo.user().count(filter).await?; + PaginatedResponse::for_page(page.map(User::from), pagination, Some(count), &base) + } + IncludeCount::False => { + let page = repo.user().list(filter, pagination).await?; + PaginatedResponse::for_page(page.map(User::from), pagination, None, &base) + } + IncludeCount::Only => { + let count = repo.user().count(filter).await?; + PaginatedResponse::for_count_only(count, &base) + } + }; - Ok(Json(PaginatedResponse::new( - page.map(User::from), - pagination, - count, - &base, - ))) + Ok(Json(response)) } diff --git a/docs/api/spec.json b/docs/api/spec.json index 166436454..d874f7700 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -107,6 +107,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[user]", @@ -373,6 +384,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[user]", @@ -893,6 +915,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[admin]", @@ -1752,6 +1785,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[user]", @@ -2097,6 +2141,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[user]", @@ -2335,6 +2390,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[used]", @@ -2882,6 +2948,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[user]", @@ -3279,6 +3356,17 @@ }, "style": "form" }, + { + "in": "query", + "name": "count", + "description": "Include the total number of items. Defaults to `true`.", + "schema": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true + }, + "style": "form" + }, { "in": "query", "name": "filter[enabled]", @@ -3481,6 +3569,11 @@ "format": "uint", "minimum": 1.0, "nullable": true + }, + "count": { + "description": "Include the total number of items. Defaults to `true`.", + "$ref": "#/components/schemas/IncludeCount", + "nullable": true } } }, @@ -3494,6 +3587,31 @@ "type": "string", "pattern": "^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$" }, + "IncludeCount": { + "oneOf": [ + { + "description": "Include the total number of items (default)", + "type": "string", + "enum": [ + "true" + ] + }, + { + "description": "Do not include the total number of items", + "type": "string", + "enum": [ + "false" + ] + }, + { + "description": "Only include the total number of items, skip the items themselves", + "type": "string", + "enum": [ + "only" + ] + } + ] + }, "CompatSessionFilter": { "type": "object", "properties": { @@ -3525,7 +3643,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -3539,7 +3656,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_CompatSession" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -3549,15 +3667,13 @@ }, "PaginationMeta": { "type": "object", - "required": [ - "count" - ], "properties": { "count": { "description": "The total number of results", "type": "integer", "format": "uint", - "minimum": 0.0 + "minimum": 0.0, + "nullable": true } } }, @@ -3678,8 +3794,6 @@ "description": "Related links", "type": "object", "required": [ - "first", - "last", "self" ], "properties": { @@ -3689,11 +3803,13 @@ }, "first": { "description": "The link to the first page of results", - "type": "string" + "type": "string", + "nullable": true }, "last": { "description": "The link to the last page of results", - "type": "string" + "type": "string", + "nullable": true }, "next": { "description": "The link to the next page of results\n\nOnly present if there is a next page", @@ -3820,7 +3936,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -3834,7 +3949,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_OAuth2Session" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4065,7 +4181,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4079,7 +4194,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_User" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4266,7 +4382,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4280,7 +4395,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_UserEmail" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4401,7 +4517,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4415,7 +4530,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_UserSession" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4538,7 +4654,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4552,7 +4667,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_UserRegistrationToken" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4727,7 +4843,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4741,7 +4856,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_UpstreamOAuthLink" - } + }, + "nullable": true }, "links": { "description": "Related links", @@ -4869,7 +4985,6 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "data", "links", "meta" ], @@ -4883,7 +4998,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SingleResource_for_UpstreamOAuthProvider" - } + }, + "nullable": true }, "links": { "description": "Related links", From eca3ec4171775e74328d175d96ff7d6f56ea644c Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Mon, 29 Sep 2025 18:47:57 +0200 Subject: [PATCH 088/296] Add tests for count=false and count=only --- .../src/admin/v1/compat_sessions/list.rs | 135 ++++++++++++ .../src/admin/v1/oauth2_sessions/list.rs | 56 +++++ .../src/admin/v1/upstream_oauth_links/list.rs | 150 +++++++++++++ .../admin/v1/upstream_oauth_providers/list.rs | 158 ++++++++++++++ .../handlers/src/admin/v1/user_emails/list.rs | 116 ++++++++++ .../admin/v1/user_registration_tokens/list.rs | 203 ++++++++++++++++++ .../src/admin/v1/user_sessions/list.rs | 122 +++++++++++ crates/handlers/src/admin/v1/users/list.rs | 197 +++++++++++++++++ 8 files changed, 1137 insertions(+) diff --git a/crates/handlers/src/admin/v1/compat_sessions/list.rs b/crates/handlers/src/admin/v1/compat_sessions/list.rs index 96a2708af..ff37ca912 100644 --- a/crates/handlers/src/admin/v1/compat_sessions/list.rs +++ b/crates/handlers/src/admin/v1/compat_sessions/list.rs @@ -471,5 +471,140 @@ mod tests { } } "#); + + // Test count=false + let request = Request::get("/api/admin/v1/compat-sessions?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "compat-session", + "id": "01FSHNB530AAPR7PEV8KNBZD5Y", + "attributes": { + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "device_id": "LoieH5Iecx", + "user_session_id": null, + "redirect_uri": null, + "created_at": "2022-01-16T14:41:00Z", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null, + "finished_at": null, + "human_name": null + }, + "links": { + "self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y" + } + }, + { + "type": "compat-session", + "id": "01FSHNCZP0PPF7X0EVMJNECPZW", + "attributes": { + "user_id": "01FSHNB530AJ6AC5HQ9X6H4RP4", + "device_id": "ZXyvelQWW9", + "user_session_id": null, + "redirect_uri": null, + "created_at": "2022-01-16T14:42:00Z", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null, + "finished_at": "2022-01-16T14:43:00Z", + "human_name": null + }, + "links": { + "self": "/api/admin/v1/compat-sessions/01FSHNCZP0PPF7X0EVMJNECPZW" + } + } + ], + "links": { + "self": "/api/admin/v1/compat-sessions?count=false&page[first]=10", + "first": "/api/admin/v1/compat-sessions?count=false&page[first]=10", + "last": "/api/admin/v1/compat-sessions?count=false&page[last]=10" + } + } + "#); + + // Test count=only + let request = Request::get("/api/admin/v1/compat-sessions?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/compat-sessions?count=only" + } + } + "#); + + // Test count=false with filtering + let request = Request::get(format!( + "/api/admin/v1/compat-sessions?count=false&filter[user]={}", + alice.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "compat-session", + "id": "01FSHNB530AAPR7PEV8KNBZD5Y", + "attributes": { + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "device_id": "LoieH5Iecx", + "user_session_id": null, + "redirect_uri": null, + "created_at": "2022-01-16T14:41:00Z", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null, + "finished_at": null, + "human_name": null + }, + "links": { + "self": "/api/admin/v1/compat-sessions/01FSHNB530AAPR7PEV8KNBZD5Y" + } + } + ], + "links": { + "self": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "first": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "last": "/api/admin/v1/compat-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = + Request::get("/api/admin/v1/compat-sessions?count=only&filter[status]=active") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/compat-sessions?filter[status]=active&count=only" + } + } + "#); } } diff --git a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs index 8b6ff6b2b..748c7bc60 100644 --- a/crates/handlers/src/admin/v1/oauth2_sessions/list.rs +++ b/crates/handlers/src/admin/v1/oauth2_sessions/list.rs @@ -381,5 +381,61 @@ mod tests { } } "#); + + // Test count=false + let request = Request::get("/api/admin/v1/oauth2-sessions?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "oauth2-session", + "id": "01FSHN9AG0MKGTBNZ16RDR3PVY", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "finished_at": null, + "user_id": null, + "user_session_id": null, + "client_id": "01FSHN9AG0FAQ50MT1E9FFRPZR", + "scope": "urn:mas:admin", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null, + "human_name": null + }, + "links": { + "self": "/api/admin/v1/oauth2-sessions/01FSHN9AG0MKGTBNZ16RDR3PVY" + } + } + ], + "links": { + "self": "/api/admin/v1/oauth2-sessions?count=false&page[first]=10", + "first": "/api/admin/v1/oauth2-sessions?count=false&page[first]=10", + "last": "/api/admin/v1/oauth2-sessions?count=false&page[last]=10" + } + } + "#); + + // Test count=only + let request = Request::get("/api/admin/v1/oauth2-sessions?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/oauth2-sessions?count=only" + } + } + "#); } } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs index 068011ab7..d5c7ee026 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_links/list.rs @@ -517,5 +517,155 @@ mod tests { } } "###); + + // Test count=false + let request = Request::get("/api/admin/v1/upstream-oauth-links?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r###" + { + "data": [ + { + "type": "upstream-oauth-link", + "id": "01FSHN9AG0AQZQP8DX40GD59PW", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "provider_id": "01FSHN9AG09NMZYX8MFYH578R9", + "subject": "subject1", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "human_account_name": "alice@acme" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + } + }, + { + "type": "upstream-oauth-link", + "id": "01FSHN9AG0PJZ6DZNTAA1XKPT4", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "provider_id": "01FSHN9AG09NMZYX8MFYH578R9", + "subject": "subject3", + "user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", + "human_account_name": "bob@acme" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0PJZ6DZNTAA1XKPT4" + } + }, + { + "type": "upstream-oauth-link", + "id": "01FSHN9AG0QHEHKX2JNQ2A2D07", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "provider_id": "01FSHN9AG0KEPHYQQXW9XPTX6Z", + "subject": "subject2", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "human_account_name": "alice@example" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-links?count=false&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-links?count=false&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-links?count=false&page[last]=10" + } + } + "###); + + // Test count=only + let request = Request::get("/api/admin/v1/upstream-oauth-links?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r###" + { + "meta": { + "count": 3 + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links?count=only" + } + } + "###); + + // Test count=false with filtering + let request = Request::get(format!( + "/api/admin/v1/upstream-oauth-links?count=false&filter[user]={}", + alice.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "upstream-oauth-link", + "id": "01FSHN9AG0AQZQP8DX40GD59PW", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "provider_id": "01FSHN9AG09NMZYX8MFYH578R9", + "subject": "subject1", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "human_account_name": "alice@acme" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0AQZQP8DX40GD59PW" + } + }, + { + "type": "upstream-oauth-link", + "id": "01FSHN9AG0QHEHKX2JNQ2A2D07", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "provider_id": "01FSHN9AG0KEPHYQQXW9XPTX6Z", + "subject": "subject2", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "human_account_name": "alice@example" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links/01FSHN9AG0QHEHKX2JNQ2A2D07" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-links?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = Request::get(format!( + "/api/admin/v1/upstream-oauth-links?count=only&filter[provider]={}", + provider1.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-links?filter[provider]=01FSHN9AG09NMZYX8MFYH578R9&count=only" + } + } + "#); } } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs index 419c3552f..76e8c4464 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -565,4 +565,162 @@ mod tests { let response = state.request(request).await; response.assert_status(StatusCode::BAD_REQUEST); } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_count_parameter(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_providers(&mut state).await; + + // Test count=false + let request = Request::get("/api/admin/v1/upstream-oauth-providers?count=false") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "issuer": "https://appleid.apple.com", + "human_name": "Apple ID", + "brand_name": "apple", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG07HNEZXNQM2KNBNF6" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "issuer": "https://login.microsoftonline.com/common/v2.0", + "human_name": "Microsoft", + "brand_name": "microsoft", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?count=false&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-providers?count=false&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-providers?count=false&page[last]=10" + } + } + "#); + + // Test count=only + let request = Request::get("/api/admin/v1/upstream-oauth-providers?count=only") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 3 + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?count=only" + } + } + "#); + + // Test count=false with filtering + let request = + Request::get("/api/admin/v1/upstream-oauth-providers?count=false&filter[enabled]=true") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "issuer": "https://login.microsoftonline.com/common/v2.0", + "human_name": "Microsoft", + "brand_name": "microsoft", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG09AVTNSQFMSR34AJC" + } + }, + { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[first]=10", + "first": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[first]=10", + "last": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=true&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = + Request::get("/api/admin/v1/upstream-oauth-providers?count=only&filter[enabled]=false") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers?count=only&filter[enabled]=false" + } + } + "#); + } } diff --git a/crates/handlers/src/admin/v1/user_emails/list.rs b/crates/handlers/src/admin/v1/user_emails/list.rs index 2363aba28..034e5214c 100644 --- a/crates/handlers/src/admin/v1/user_emails/list.rs +++ b/crates/handlers/src/admin/v1/user_emails/list.rs @@ -335,5 +335,121 @@ mod tests { } } "###); + + // Test count=false + let request = Request::get("/api/admin/v1/user-emails?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r###" + { + "data": [ + { + "type": "user-email", + "id": "01FSHN9AG09NMZYX8MFYH578R9", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "email": "alice@example.com" + }, + "links": { + "self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9" + } + }, + { + "type": "user-email", + "id": "01FSHN9AG0KEPHYQQXW9XPTX6Z", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "user_id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", + "email": "bob@example.com" + }, + "links": { + "self": "/api/admin/v1/user-emails/01FSHN9AG0KEPHYQQXW9XPTX6Z" + } + } + ], + "links": { + "self": "/api/admin/v1/user-emails?count=false&page[first]=10", + "first": "/api/admin/v1/user-emails?count=false&page[first]=10", + "last": "/api/admin/v1/user-emails?count=false&page[last]=10" + } + } + "###); + + // Test count=only + let request = Request::get("/api/admin/v1/user-emails?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r###" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/user-emails?count=only" + } + } + "###); + + // Test count=false with filtering + let request = Request::get(format!( + "/api/admin/v1/user-emails?count=false&filter[user]={}", + alice.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "user-email", + "id": "01FSHN9AG09NMZYX8MFYH578R9", + "attributes": { + "created_at": "2022-01-16T14:40:00Z", + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "email": "alice@example.com" + }, + "links": { + "self": "/api/admin/v1/user-emails/01FSHN9AG09NMZYX8MFYH578R9" + } + } + ], + "links": { + "self": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "first": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "last": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = Request::get(format!( + "/api/admin/v1/user-emails?count=only&filter[user]={}", + alice.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/user-emails?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=only" + } + } + "#); } } diff --git a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs index f1700aaa7..c99195e5c 100644 --- a/crates/handlers/src/admin/v1/user_registration_tokens/list.rs +++ b/crates/handlers/src/admin/v1/user_registration_tokens/list.rs @@ -1186,4 +1186,207 @@ mod tests { .contains("Invalid filter parameters") ); } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_count_parameter(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + create_test_tokens(&mut state).await; + + // Test count=false + let request = Request::get("/api/admin/v1/user-registration-tokens?count=false") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "user-registration_token", + "id": "01FSHN9AG064K8BYZXSY5G511Z", + "attributes": { + "token": "token_expired", + "valid": false, + "usage_limit": 5, + "times_used": 0, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": null, + "expires_at": "2022-01-15T14:40:00Z", + "revoked_at": null + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG064K8BYZXSY5G511Z" + } + }, + { + "type": "user-registration_token", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "token": "token_used", + "valid": true, + "usage_limit": 10, + "times_used": 1, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": "2022-01-16T14:40:00Z", + "expires_at": null, + "revoked_at": null + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + } + }, + { + "type": "user-registration_token", + "id": "01FSHN9AG09AVTNSQFMSR34AJC", + "attributes": { + "token": "token_revoked", + "valid": false, + "usage_limit": 10, + "times_used": 0, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": null, + "expires_at": null, + "revoked_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG09AVTNSQFMSR34AJC" + } + }, + { + "type": "user-registration_token", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "token": "token_unused", + "valid": true, + "usage_limit": 10, + "times_used": 0, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": null, + "expires_at": null, + "revoked_at": null + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + } + }, + { + "type": "user-registration_token", + "id": "01FSHN9AG0S3ZJD8CXQ7F11KXN", + "attributes": { + "token": "token_used_revoked", + "valid": false, + "usage_limit": 10, + "times_used": 1, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": "2022-01-16T14:40:00Z", + "expires_at": null, + "revoked_at": "2022-01-16T14:40:00Z" + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0S3ZJD8CXQ7F11KXN" + } + } + ], + "links": { + "self": "/api/admin/v1/user-registration-tokens?count=false&page[first]=10", + "first": "/api/admin/v1/user-registration-tokens?count=false&page[first]=10", + "last": "/api/admin/v1/user-registration-tokens?count=false&page[last]=10" + } + } + "#); + + // Test count=only + let request = Request::get("/api/admin/v1/user-registration-tokens?count=only") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 5 + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens?count=only" + } + } + "#); + + // Test count=false with filtering + let request = + Request::get("/api/admin/v1/user-registration-tokens?count=false&filter[valid]=true") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "user-registration_token", + "id": "01FSHN9AG07HNEZXNQM2KNBNF6", + "attributes": { + "token": "token_used", + "valid": true, + "usage_limit": 10, + "times_used": 1, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": "2022-01-16T14:40:00Z", + "expires_at": null, + "revoked_at": null + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG07HNEZXNQM2KNBNF6" + } + }, + { + "type": "user-registration_token", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "token": "token_unused", + "valid": true, + "usage_limit": 10, + "times_used": 0, + "created_at": "2022-01-16T14:40:00Z", + "last_used_at": null, + "expires_at": null, + "revoked_at": null + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[first]=10", + "first": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[first]=10", + "last": "/api/admin/v1/user-registration-tokens?filter[valid]=true&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = + Request::get("/api/admin/v1/user-registration-tokens?count=only&filter[revoked]=true") + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/user-registration-tokens?filter[revoked]=true&count=only" + } + } + "#); + } } diff --git a/crates/handlers/src/admin/v1/user_sessions/list.rs b/crates/handlers/src/admin/v1/user_sessions/list.rs index 6ba1dc5f0..c00925915 100644 --- a/crates/handlers/src/admin/v1/user_sessions/list.rs +++ b/crates/handlers/src/admin/v1/user_sessions/list.rs @@ -416,5 +416,127 @@ mod tests { } } "###); + + // Test count=false + let request = Request::get("/api/admin/v1/user-sessions?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r###" + { + "data": [ + { + "type": "user-session", + "id": "01FSHNB5309NMZYX8MFYH578R9", + "attributes": { + "created_at": "2022-01-16T14:41:00Z", + "finished_at": null, + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null + }, + "links": { + "self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9" + } + }, + { + "type": "user-session", + "id": "01FSHNB530KEPHYQQXW9XPTX6Z", + "attributes": { + "created_at": "2022-01-16T14:41:00Z", + "finished_at": "2022-01-16T14:42:00Z", + "user_id": "01FSHNB530AJ6AC5HQ9X6H4RP4", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null + }, + "links": { + "self": "/api/admin/v1/user-sessions/01FSHNB530KEPHYQQXW9XPTX6Z" + } + } + ], + "links": { + "self": "/api/admin/v1/user-sessions?count=false&page[first]=10", + "first": "/api/admin/v1/user-sessions?count=false&page[first]=10", + "last": "/api/admin/v1/user-sessions?count=false&page[last]=10" + } + } + "###); + + // Test count=only + let request = Request::get("/api/admin/v1/user-sessions?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r###" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/user-sessions?count=only" + } + } + "###); + + // Test count=false with filtering + let request = Request::get(format!( + "/api/admin/v1/user-sessions?count=false&filter[user]={}", + alice.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "user-session", + "id": "01FSHNB5309NMZYX8MFYH578R9", + "attributes": { + "created_at": "2022-01-16T14:41:00Z", + "finished_at": null, + "user_id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "user_agent": null, + "last_active_at": null, + "last_active_ip": null + }, + "links": { + "self": "/api/admin/v1/user-sessions/01FSHNB5309NMZYX8MFYH578R9" + } + } + ], + "links": { + "self": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "first": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[first]=10", + "last": "/api/admin/v1/user-sessions?filter[user]=01FSHN9AG0MZAA6S4AF7CTV32E&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = Request::get("/api/admin/v1/user-sessions?count=only&filter[status]=active") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/user-sessions?filter[status]=active&count=only" + } + } + "#); } } diff --git a/crates/handlers/src/admin/v1/users/list.rs b/crates/handlers/src/admin/v1/users/list.rs index ddafa9984..8fd778bd2 100644 --- a/crates/handlers/src/admin/v1/users/list.rs +++ b/crates/handlers/src/admin/v1/users/list.rs @@ -204,3 +204,200 @@ pub async fn handler( Ok(Json(response)) } + +#[cfg(test)] +mod tests { + use hyper::{Request, StatusCode}; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_list_users(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + let mut rng = state.rng(); + + // Provision two users + let mut repo = state.repository().await.unwrap(); + repo.user() + .add(&mut rng, &state.clock, "alice".to_owned()) + .await + .unwrap(); + repo.user() + .add(&mut rng, &state.clock, "bob".to_owned()) + .await + .unwrap(); + repo.save().await.unwrap(); + + // Test default behavior (count=true) + let request = Request::get("/api/admin/v1/users").bearer(&token).empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 2 + }, + "data": [ + { + "type": "user", + "id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", + "attributes": { + "username": "bob", + "created_at": "2022-01-16T14:40:00Z", + "locked_at": null, + "deactivated_at": null, + "admin": false, + "legacy_guest": false + }, + "links": { + "self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4" + } + }, + { + "type": "user", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "username": "alice", + "created_at": "2022-01-16T14:40:00Z", + "locked_at": null, + "deactivated_at": null, + "admin": false, + "legacy_guest": false + }, + "links": { + "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/users?page[first]=10", + "first": "/api/admin/v1/users?page[first]=10", + "last": "/api/admin/v1/users?page[last]=10" + } + } + "#); + + // Test count=false + let request = Request::get("/api/admin/v1/users?count=false") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r###" + { + "data": [ + { + "type": "user", + "id": "01FSHN9AG0AJ6AC5HQ9X6H4RP4", + "attributes": { + "username": "bob", + "created_at": "2022-01-16T14:40:00Z", + "locked_at": null, + "deactivated_at": null, + "admin": false, + "legacy_guest": false + }, + "links": { + "self": "/api/admin/v1/users/01FSHN9AG0AJ6AC5HQ9X6H4RP4" + } + }, + { + "type": "user", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "username": "alice", + "created_at": "2022-01-16T14:40:00Z", + "locked_at": null, + "deactivated_at": null, + "admin": false, + "legacy_guest": false + }, + "links": { + "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/users?count=false&page[first]=10", + "first": "/api/admin/v1/users?count=false&page[first]=10", + "last": "/api/admin/v1/users?count=false&page[last]=10" + } + } + "###); + + // Test count=only + let request = Request::get("/api/admin/v1/users?count=only") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r###" + { + "meta": { + "count": 2 + }, + "links": { + "self": "/api/admin/v1/users?count=only" + } + } + "###); + + // Test count=false with filtering + let request = Request::get("/api/admin/v1/users?count=false&filter[search]=alice") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "data": [ + { + "type": "user", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "username": "alice", + "created_at": "2022-01-16T14:40:00Z", + "locked_at": null, + "deactivated_at": null, + "admin": false, + "legacy_guest": false + }, + "links": { + "self": "/api/admin/v1/users/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + ], + "links": { + "self": "/api/admin/v1/users?filter[search]=alice&count=false&page[first]=10", + "first": "/api/admin/v1/users?filter[search]=alice&count=false&page[first]=10", + "last": "/api/admin/v1/users?filter[search]=alice&count=false&page[last]=10" + } + } + "#); + + // Test count=only with filtering + let request = Request::get("/api/admin/v1/users?count=only&filter[search]=alice") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + insta::assert_json_snapshot!(body, @r#" + { + "meta": { + "count": 1 + }, + "links": { + "self": "/api/admin/v1/users?filter[search]=alice&count=only" + } + } + "#); + } +} From 3409003f0cb1e045a98bb075bc8b93d4e3f07808 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 17:36:52 +0000 Subject: [PATCH 089/296] build(deps): bump docker/login-action from 3.5.0 to 3.6.0 Bumps [docker/login-action](https://github.com/docker/login-action) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v3.5.0...v3.6.0) --- updated-dependencies: - dependency-name: docker/login-action dependency-version: 3.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e51df6f56..7dad4d1d4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -268,7 +268,7 @@ jobs: mirrors = ["mirror.gcr.io"] - name: Login to GitHub Container Registry - uses: docker/login-action@v3.5.0 + uses: docker/login-action@v3.6.0 with: registry: ghcr.io username: ${{ github.repository_owner }} From 325a79ddc1af8625be2ae23601104dd6cb86e364 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Sep 2025 18:15:43 +0000 Subject: [PATCH 090/296] build(deps): bump serde from 1.0.225 to 1.0.228 Bumps [serde](https://github.com/serde-rs/serde) from 1.0.225 to 1.0.228. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.225...v1.0.228) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.228 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c75fc78d0..4c4466253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5511,9 +5511,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -5521,18 +5521,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index be3ca88b4..162f9b210 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -582,7 +582,7 @@ version = "0.42.0" # Serialization and deserialization [workspace.dependencies.serde] -version = "1.0.225" +version = "1.0.228" features = ["derive"] # Most of the time, if we need serde, we need derive # JSON serialization and deserialization From 6f98f0a65106a073a61bd3518725859436fde42c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 00:12:26 +0000 Subject: [PATCH 091/296] build(deps-dev): bump the types group across 1 directory with 2 updates Bumps the types group with 2 updates in the /frontend directory: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). Updates `@types/node` from 24.5.0 to 24.5.2 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/react` from 19.1.13 to 19.1.15 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.5.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types - dependency-name: "@types/react" dependency-version: 19.1.15 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index dc60ee1c3..3f7605262 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,8 +44,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.5.0", - "@types/react": "19.1.13", + "@types/node": "^24.5.2", + "@types/react": "19.1.15", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.3", @@ -5597,9 +5597,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.0.tgz", - "integrity": "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==", + "version": "24.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", + "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5607,9 +5607,9 @@ } }, "node_modules/@types/react": { - "version": "19.1.13", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", - "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", + "version": "19.1.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.15.tgz", + "integrity": "sha512-+kLxJpaJzXybyDyFXYADyP1cznTO8HSuBpenGlnKOAkH4hyNINiywvXS/tGJhsrGGP/gM185RA3xpjY0Yg4erA==", "devOptional": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 8cf53912b..2a1c8296d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.5.0", - "@types/react": "19.1.13", + "@types/node": "^24.5.2", + "@types/react": "19.1.15", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.3", From 68e462b0808eda5fc97472abf12a0c7baa6a3140 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:22:21 +0000 Subject: [PATCH 092/296] build(deps-dev): bump the vite group in /frontend with 2 updates Bumps the vite group in /frontend with 2 updates: [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `@vitejs/plugin-react` from 5.0.3 to 5.0.4 - [Release notes](https://github.com/vitejs/vite-plugin-react/releases) - [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.0.4/packages/plugin-react) Updates `vite` from 7.1.6 to 7.1.7 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.1.7/packages/vite) --- updated-dependencies: - dependency-name: "@vitejs/plugin-react" dependency-version: 5.0.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite - dependency-name: vite dependency-version: 7.1.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 330c5e6ea..1067bf388 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -48,7 +48,7 @@ "@types/react": "19.1.15", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^5.0.3", + "@vitejs/plugin-react": "^5.0.4", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -66,7 +66,7 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.6", + "vite": "7.1.7", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", @@ -4553,9 +4553,9 @@ "license": "MIT" }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.35", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz", - "integrity": "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==", + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", "dev": true, "license": "MIT" }, @@ -5719,16 +5719,16 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz", - "integrity": "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.35", + "@rolldown/pluginutils": "1.0.0-beta.38", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, @@ -13124,9 +13124,9 @@ } }, "node_modules/vite": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.6.tgz", - "integrity": "sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", + "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 0ce85802d..ebe8649f5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -58,7 +58,7 @@ "@types/react": "19.1.15", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", - "@vitejs/plugin-react": "^5.0.3", + "@vitejs/plugin-react": "^5.0.4", "@vitest/coverage-v8": "^3.2.4", "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", @@ -76,7 +76,7 @@ "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.6", + "vite": "7.1.7", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", From caf67e3432f697d1a41b2db86aeab28e582f778a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 10:33:00 +0200 Subject: [PATCH 093/296] Update test snapshots --- crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs index 76e8c4464..a545f0f2f 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/list.rs @@ -718,7 +718,7 @@ mod tests { "count": 1 }, "links": { - "self": "/api/admin/v1/upstream-oauth-providers?count=only&filter[enabled]=false" + "self": "/api/admin/v1/upstream-oauth-providers?filter[enabled]=false&count=only" } } "#); From 15db2e597ea6522a3749b2f6d5670398ac99bf7d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:35:19 +0000 Subject: [PATCH 094/296] build(deps): bump react-i18next in /frontend in the i18next group Bumps the i18next group in /frontend with 1 update: [react-i18next](https://github.com/i18next/react-i18next). Updates `react-i18next` from 15.7.3 to 16.0.0 - [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/react-i18next/compare/v15.7.3...v16.0.0) --- updated-dependencies: - dependency-name: react-i18next dependency-version: 16.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: i18next ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 10 +++++----- frontend/package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a90aae4eb..3bee4a8fc 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,7 +23,7 @@ "i18next": "^25.5.2", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-i18next": "^15.7.3", + "react-i18next": "^16.0.0", "swagger-ui-dist": "^5.29.0", "valibot": "^1.1.0", "vaul": "^1.1.2" @@ -11245,16 +11245,16 @@ } }, "node_modules/react-i18next": { - "version": "15.7.3", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.7.3.tgz", - "integrity": "sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.0.0.tgz", + "integrity": "sha512-JQ+dFfLnFSKJQt7W01lJHWRC0SX7eDPobI+MSTJ3/gP39xH2g33AuTE7iddAfXYHamJdAeMGM0VFboPaD3G68Q==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { - "i18next": ">= 25.4.1", + "i18next": ">= 25.5.2", "react": ">= 16.8.0", "typescript": "^5" }, diff --git a/frontend/package.json b/frontend/package.json index 34a6d7cd4..8800016b5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,7 +33,7 @@ "i18next": "^25.5.2", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-i18next": "^15.7.3", + "react-i18next": "^16.0.0", "swagger-ui-dist": "^5.29.0", "valibot": "^1.1.0", "vaul": "^1.1.2" From c960ff828497102e32455304e5faad7a652e225f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:35:42 +0000 Subject: [PATCH 095/296] build(deps-dev): bump @graphql-codegen/client-preset Bumps the graphql-codegen group in /frontend with 1 update: [@graphql-codegen/client-preset](https://github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/presets/client). Updates `@graphql-codegen/client-preset` from 5.0.1 to 5.0.2 - [Release notes](https://github.com/dotansimha/graphql-code-generator/releases) - [Changelog](https://github.com/dotansimha/graphql-code-generator/blob/master/packages/presets/client/CHANGELOG.md) - [Commits](https://github.com/dotansimha/graphql-code-generator/commits/@graphql-codegen/client-preset@5.0.2/packages/presets/client) --- updated-dependencies: - dependency-name: "@graphql-codegen/client-preset" dependency-version: 5.0.2 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: graphql-codegen ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 58 +++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a90aae4eb..00a0728ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -34,7 +34,7 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@graphql-codegen/cli": "^6.0.0", - "@graphql-codegen/client-preset": "^5.0.1", + "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.8", "@storybook/react-vite": "^9.1.8", @@ -2009,21 +2009,21 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/client-preset": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.0.1.tgz", - "integrity": "sha512-3dXS7Sh/AkV+Ewq/HB1DSCb0tZBOIdTL8zkGQjRKWaf14x21h2f/xKl2zhRh6KlXjcCrIpX+AxHAhQxs6cXwVw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.0.2.tgz", + "integrity": "sha512-lBkVMz7QA7FHWb71BcNB/tFFOh0LDNCPIBaJ70Lj1SIPjOfCEYmbkK6D5piPZu87m60hyWN3XDwNHEH8eGoXNA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", "@graphql-codegen/add": "^6.0.0", - "@graphql-codegen/gql-tag-operations": "5.0.0", + "@graphql-codegen/gql-tag-operations": "5.0.1", "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/typed-document-node": "^6.0.0", - "@graphql-codegen/typescript": "^5.0.0", - "@graphql-codegen/typescript-operations": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "^6.0.0", + "@graphql-codegen/typed-document-node": "^6.0.1", + "@graphql-codegen/typescript": "^5.0.1", + "@graphql-codegen/typescript-operations": "^5.0.1", + "@graphql-codegen/visitor-plugin-common": "^6.0.1", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -2076,14 +2076,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.0.0.tgz", - "integrity": "sha512-kC2pc/tyzVc1laZtlfuQHqYxF4UqB4YXzAboFfeY1cxrxCh/+H70jHnfA1O4vhPndiRd+XZA8wxPv0hIqDXYaA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.0.1.tgz", + "integrity": "sha512-GVd/B6mtRAXg6UxgeO805P7VDrCmVIb6qIMrE7O69j8e4EqIt/URdmJ7On+Bn8IIKp7TcpcLSo/VI28ptcssNw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.1", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" @@ -2156,14 +2156,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.0.0.tgz", - "integrity": "sha512-OYmbadwvjq19yCZjioy901pLI9YV6i7A0fP3MpcJlo2uQVY27RJPcN2NeLfFzXdHr6f5bm9exqB6X1iKimfA2Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.0.1.tgz", + "integrity": "sha512-z0vvvmwfdozkY1AFqbNLeb/jAWyVwWJOIllZEEwPDKcVtCMPQZ1DRApPMRDRndRL6fOG4aXXnt7C5kgniC+qGw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.1", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -2183,15 +2183,15 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.0.tgz", - "integrity": "sha512-u90SGM6+Rdc3Je1EmVQOrGk5fl7hK1cLR4y5Q1MeUenj0aZFxKno65DCW7RcQpcfebvkPsVGA6y3oS02wPFj6Q==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.1.tgz", + "integrity": "sha512-GqAl4pxFdWTvW1h+Ume7djrucYwt03wiaS88m4ErG+tHsJaR2ZCtoHOo+B4bh7KIuBKap14/xOZG0qY/ThWAhg==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-codegen/schema-ast": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.0", + "@graphql-codegen/visitor-plugin-common": "6.0.1", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2520,15 +2520,15 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.0.tgz", - "integrity": "sha512-mqgp/lp5v7w+RYj5AJ/BVquP+sgje3EAgg++62ciolOB5zzWT8en09cRdNq4UZfszCYTOtlhCG7NQAAcSae37A==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.1.tgz", + "integrity": "sha512-uJwsOIqvXyxlOI1Mnoy8Mn3TiOHTzVTGDwqL9gHnpKqQZdFfvMgfDf/HyT7Mw3XCOfhSS99fe9ATW0bkMExBZg==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/typescript": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.0", + "@graphql-codegen/typescript": "^5.0.1", + "@graphql-codegen/visitor-plugin-common": "6.0.1", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2560,9 +2560,9 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.0.0.tgz", - "integrity": "sha512-K05Jv2elOeFstH3i+Ah0Pi9do6NYUvrbdhEkP+UvP9fmIro1hCKwcIEP7j4VFz8mt3gAC3dB5KVJDoyaPUgi4Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.0.1.tgz", + "integrity": "sha512-3gopoUYXn26PSj2UdCWmYj0QiRVD5qR3eDiXx72OQcN1Vb8qj6VfOWB+NDuD1Q1sgVYbCQVKgj92ERsSW1xH9Q==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 34a6d7cd4..31940d15d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -44,7 +44,7 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@graphql-codegen/cli": "^6.0.0", - "@graphql-codegen/client-preset": "^5.0.1", + "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.8", "@storybook/react-vite": "^9.1.8", From 0966257cb33f183fa064f94f2db9d2bd29a63607 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:35:52 +0000 Subject: [PATCH 096/296] build(deps): bump the axum group with 2 updates Bumps the axum group with 2 updates: [axum](https://github.com/tokio-rs/axum) and [axum-extra](https://github.com/tokio-rs/axum). Updates `axum` from 0.8.4 to 0.8.5 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.8.4...axum-v0.8.5) Updates `axum-extra` from 0.10.1 to 0.10.2 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-extra-v0.10.1...axum-extra-v0.10.2) --- updated-dependencies: - dependency-name: axum dependency-version: 0.8.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: axum - dependency-name: axum-extra dependency-version: 0.10.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: axum ... Signed-off-by: dependabot[bot] --- Cargo.lock | 20 +++++++++----------- Cargo.toml | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 813b9a561..65cadd68c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,9 +553,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "98e529aee37b5c8206bb4bf4c44797127566d72f76952c970bd3d1e85de8f4e2" dependencies = [ "axum-core", "bytes", @@ -572,8 +572,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -587,9 +586,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "0ac7a6beb1182c7e30253ee75c3e918080bfb83f5a3023bcdf7209d85fd147e6" dependencies = [ "bytes", "futures-core", @@ -598,7 +597,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -607,9 +605,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" +checksum = "d86d701cd16f401888ebe9c3214dc838c7ef27a405d5726196765a913603b5dd" dependencies = [ "axum", "axum-core", @@ -623,10 +621,10 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "serde", - "tower", + "serde_core", "tower-layer", "tower-service", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2267d086f..cf8e9f0b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,11 +96,11 @@ version = "1.5.0" # HTTP router [workspace.dependencies.axum] -version = "0.8.4" +version = "0.8.5" # Extra utilities for Axum [workspace.dependencies.axum-extra] -version = "0.10.1" +version = "0.10.2" features = ["cookie-private", "cookie-key-expansion", "typed-header"] # Axum macros From 5a00b388ed91a5036ad6aa6fb162d3c8537c831f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:36:03 +0000 Subject: [PATCH 097/296] build(deps): bump the tanstack-query group in /frontend with 2 updates Bumps the tanstack-query group in /frontend with 2 updates: [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) and [@tanstack/react-query-devtools](https://github.com/TanStack/query/tree/HEAD/packages/react-query-devtools). Updates `@tanstack/react-query` from 5.89.0 to 5.90.2 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.90.2/packages/react-query) Updates `@tanstack/react-query-devtools` from 5.89.0 to 5.90.2 - [Release notes](https://github.com/TanStack/query/releases) - [Commits](https://github.com/TanStack/query/commits/v5.90.2/packages/react-query-devtools) --- updated-dependencies: - dependency-name: "@tanstack/react-query" dependency-version: 5.90.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: tanstack-query - dependency-name: "@tanstack/react-query-devtools" dependency-version: 5.90.2 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: tanstack-query ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 34 +++++++++++++++++----------------- frontend/package.json | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a90aae4eb..466e7df52 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,7 @@ "@fontsource/inter": "^5.2.8", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", - "@tanstack/react-query": "^5.89.0", + "@tanstack/react-query": "^5.90.2", "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", @@ -38,7 +38,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.8", "@storybook/react-vite": "^9.1.8", - "@tanstack/react-query-devtools": "^5.89.0", + "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", @@ -5331,9 +5331,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.89.0.tgz", - "integrity": "sha512-joFV1MuPhSLsKfTzwjmPDrp8ENfZ9N23ymFu07nLfn3JCkSHy0CFgsyhHTJOmWaumC/WiNIKM0EJyduCF/Ih/Q==", + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.2.tgz", + "integrity": "sha512-k/TcR3YalnzibscALLwxeiLUub6jN5EDLwKDiO7q5f4ICEoptJ+n9+7vcEFy5/x/i6Q+Lb/tXrsKCggf5uQJXQ==", "license": "MIT", "funding": { "type": "github", @@ -5341,9 +5341,9 @@ } }, "node_modules/@tanstack/query-devtools": { - "version": "5.87.3", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.87.3.tgz", - "integrity": "sha512-LkzxzSr2HS1ALHTgDmJH5eGAVsSQiuwz//VhFW5OqNk0OQ+Fsqba0Tsf+NzWRtXYvpgUqwQr4b2zdFZwxHcGvg==", + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.90.1.tgz", + "integrity": "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==", "dev": true, "license": "MIT", "funding": { @@ -5352,12 +5352,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.89.0.tgz", - "integrity": "sha512-SXbtWSTSRXyBOe80mszPxpEbaN4XPRUp/i0EfQK1uyj3KCk/c8FuPJNIRwzOVe/OU3rzxrYtiNabsAmk1l714A==", + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.2.tgz", + "integrity": "sha512-CLABiR+h5PYfOWr/z+vWFt5VsOA2ekQeRQBFSKlcoW6Ndx/f8rfyVmq4LbgOM4GG2qtxAxjLYLOpCNTYm4uKzw==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.89.0" + "@tanstack/query-core": "5.90.2" }, "funding": { "type": "github", @@ -5368,20 +5368,20 @@ } }, "node_modules/@tanstack/react-query-devtools": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.89.0.tgz", - "integrity": "sha512-Syc4UjZeIJCkXCRGyQcWwlnv89JNb98MMg/DAkFCV3rwOcknj98+nG3Nm6xLXM6ne9sK6RZeDJMPLKZUh6NUGA==", + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.90.2.tgz", + "integrity": "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==", "dev": true, "license": "MIT", "dependencies": { - "@tanstack/query-devtools": "5.87.3" + "@tanstack/query-devtools": "5.90.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" }, "peerDependencies": { - "@tanstack/react-query": "^5.89.0", + "@tanstack/react-query": "^5.90.2", "react": "^18 || ^19" } }, diff --git a/frontend/package.json b/frontend/package.json index 34a6d7cd4..5c50d7667 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,7 +22,7 @@ "@fontsource/inter": "^5.2.8", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", - "@tanstack/react-query": "^5.89.0", + "@tanstack/react-query": "^5.90.2", "@tanstack/react-router": "^1.131.44", "@vector-im/compound-design-tokens": "6.0.0", "@vector-im/compound-web": "^8.2.4", @@ -48,7 +48,7 @@ "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.8", "@storybook/react-vite": "^9.1.8", - "@tanstack/react-query-devtools": "^5.89.0", + "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", "@testing-library/jest-dom": "^6.8.0", From 230824f0a8584cd3ea76f095fa3d8d9f2a98b88b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:36:23 +0000 Subject: [PATCH 098/296] build(deps-dev): bump the types group in /frontend with 2 updates Bumps the types group in /frontend with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react). Updates `@types/node` from 24.5.2 to 24.6.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@types/react` from 19.1.15 to 19.1.16 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.6.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: types - dependency-name: "@types/react" dependency-version: 19.1.16 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 24 ++++++++++++------------ frontend/package.json | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a90aae4eb..ff8fba8ce 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,8 +44,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.5.2", - "@types/react": "19.1.15", + "@types/node": "^24.6.0", + "@types/react": "19.1.16", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.4", @@ -5868,19 +5868,19 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.5.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", - "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.0.tgz", + "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.12.0" + "undici-types": "~7.13.0" } }, "node_modules/@types/react": { - "version": "19.1.15", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.15.tgz", - "integrity": "sha512-+kLxJpaJzXybyDyFXYADyP1cznTO8HSuBpenGlnKOAkH4hyNINiywvXS/tGJhsrGGP/gM185RA3xpjY0Yg4erA==", + "version": "19.1.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.16.tgz", + "integrity": "sha512-WBM/nDbEZmDUORKnh5i1bTnAz6vTohUf9b8esSMu+b24+srbaxa04UbJgWx78CVfNXA20sNu0odEIluZDFdCog==", "devOptional": true, "license": "MIT", "dependencies": { @@ -12984,9 +12984,9 @@ } }, "node_modules/undici-types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", - "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz", + "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index 34a6d7cd4..f769a142c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,8 +54,8 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.5.2", - "@types/react": "19.1.15", + "@types/node": "^24.6.0", + "@types/react": "19.1.16", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.4", From ec786d73a65148258c30ac251e4291879e422c7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:40:58 +0000 Subject: [PATCH 099/296] build(deps): bump tokio-rustls from 0.26.3 to 0.26.4 Bumps [tokio-rustls](https://github.com/rustls/tokio-rustls) from 0.26.3 to 0.26.4. - [Release notes](https://github.com/rustls/tokio-rustls/releases) - [Commits](https://github.com/rustls/tokio-rustls/compare/v/0.26.3...v/0.26.4) --- updated-dependencies: - dependency-name: tokio-rustls dependency-version: 0.26.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 813b9a561..3e7c78362 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6347,9 +6347,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 2267d086f..2169f3f7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -652,7 +652,7 @@ version = "0.1.17" # Tokio rustls integration [workspace.dependencies.tokio-rustls] -version = "0.26.3" +version = "0.26.4" # Tokio test utilities [workspace.dependencies.tokio-test] From 5304eeaa293853a5dd74286f8a349842a1bc4724 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:41:21 +0000 Subject: [PATCH 100/296] build(deps): bump camino from 1.2.0 to 1.2.1 Bumps [camino](https://github.com/camino-rs/camino) from 1.2.0 to 1.2.1. - [Release notes](https://github.com/camino-rs/camino/releases) - [Changelog](https://github.com/camino-rs/camino/blob/main/CHANGELOG.md) - [Commits](https://github.com/camino-rs/camino/compare/camino-1.2.0...camino-1.2.1) --- updated-dependencies: - dependency-name: camino dependency-version: 1.2.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 813b9a561..a70540d1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -822,9 +822,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" dependencies = [ "serde_core", ] diff --git a/Cargo.toml b/Cargo.toml index 2267d086f..e21826b14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ version = "1.10.1" # UTF-8 paths [workspace.dependencies.camino] -version = "1.2.0" +version = "1.2.1" features = ["serde1"] # ChaCha20Poly1305 AEAD From 30dffaf3c2df5fc272d8e5ccb9df6d0b921bcfcd Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 11:32:26 +0200 Subject: [PATCH 101/296] Replace storybook-react-i18next with our own globals --- frontend/.storybook/main.ts | 2 +- frontend/.storybook/preview.tsx | 134 +++++++++++++++++++------------- frontend/package-lock.json | 65 ---------------- frontend/package.json | 1 - 4 files changed, 79 insertions(+), 123 deletions(-) diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts index d895a0bc9..b4ffa1976 100644 --- a/frontend/.storybook/main.ts +++ b/frontend/.storybook/main.ts @@ -9,7 +9,7 @@ import type { StorybookConfig } from "@storybook/react-vite"; const config: StorybookConfig = { stories: ["../{src,stories}/**/*.stories.@(js|jsx|ts|tsx)"], - addons: ["storybook-react-i18next", "@storybook/addon-docs"], + addons: ["@storybook/addon-docs"], framework: "@storybook/react-vite", diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx index a9abadc7d..7ba9e4218 100644 --- a/frontend/.storybook/preview.tsx +++ b/frontend/.storybook/preview.tsx @@ -4,15 +4,11 @@ // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. -import type { - ArgTypes, - Decorator, - Parameters, - Preview, -} from "@storybook/react-vite"; +import type { Decorator, Preview } from "@storybook/react-vite"; import { TooltipProvider } from "@vector-im/compound-web"; import { initialize, mswLoader } from "msw-storybook-addon"; -import { useLayoutEffect } from "react"; +import { useEffect, useLayoutEffect } from "react"; +import { I18nextProvider } from "react-i18next"; import "../src/shared.css"; import i18n, { setupI18n } from "../src/i18n"; import { DummyRouter } from "../src/test-utils/router"; @@ -31,37 +27,12 @@ initialize( setupI18n(); -export const parameters: Parameters = { - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/, - }, - }, -}; - -export const globalTypes = { - theme: { - name: "Theme", - defaultValue: "system", - description: "Global theme for components", - toolbar: { - icon: "circlehollow", - title: "Theme", - items: [ - { title: "System", value: "system", icon: "browser" }, - { title: "Light", value: "light", icon: "sun" }, - { title: "Light (high contrast)", value: "light-hc", icon: "sun" }, - { title: "Dark", value: "dark", icon: "moon" }, - { title: "Dark (high contrast)", value: "dark-hc", icon: "moon" }, - ], - }, - }, -} satisfies ArgTypes; - -const allThemesClasses = globalTypes.theme.toolbar.items.map( - ({ value }) => `cpd-theme-${value}`, -); +const allThemesClasses = [ + "cpd-theme-light", + "cpd-theme-light-hc", + "cpd-theme-dark", + "cpd-theme-dark-hc", +]; const ThemeSwitcher: React.FC<{ theme: string; @@ -86,6 +57,27 @@ const withThemeProvider: Decorator = (Story, context) => { ); }; +const LocaleSwitcher: React.FC<{ + locale: string; +}> = ({ locale }) => { + useEffect(() => { + i18n.changeLanguage(locale); + }, [locale]); + + return null; +}; + +const withI18nProvider: Decorator = (Story, context) => { + return ( + <> + + + + + + ); +}; + const withDummyRouter: Decorator = (Story, _context) => { return ( @@ -102,28 +94,58 @@ const withTooltipProvider: Decorator = (Story, _context) => { ); }; -export const decorators: Decorator[] = [ - withThemeProvider, - withDummyRouter, - withTooltipProvider, -]; - -const locales = Object.fromEntries( - localazyMetadata.languages.map(({ language, name, localizedName }) => [ - language, - `${localizedName} (${name})`, - ]), -); - const preview: Preview = { + loaders: [mswLoader], + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, + }, + decorators: [ + withI18nProvider, + withThemeProvider, + withDummyRouter, + withTooltipProvider, + ], + globalTypes: { + theme: { + name: "Theme", + description: "Global theme for components", + toolbar: { + icon: "circlehollow", + title: "Theme", + items: [ + { title: "System", value: "system", icon: "browser" }, + { title: "Light", value: "light", icon: "sun" }, + { title: "Light (high contrast)", value: "light-hc", icon: "sun" }, + { title: "Dark", value: "dark", icon: "moon" }, + { title: "Dark (high contrast)", value: "dark-hc", icon: "moon" }, + ], + }, + }, + + locale: { + name: "Locale", + description: "Locale for the app", + toolbar: { + title: "Language", + icon: "globe", + items: localazyMetadata.languages.map( + ({ language, localizedName, name }) => ({ + title: `${localizedName} (${name})`, + value: language, + }), + ), + }, + }, + }, initialGlobals: { locale: localazyMetadata.baseLocale, - locales, + theme: "system", }, - parameters: { - i18n, - }, - loaders: [mswLoader], tags: ["autodocs"], }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3bee4a8fc..ceb3534f4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -63,7 +63,6 @@ "postcss-nesting": "^13.0.2", "rimraf": "^6.0.1", "storybook": "^9.1.5", - "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", "vite": "7.1.7", @@ -8804,39 +8803,6 @@ } } }, - "node_modules/i18next-browser-languagedetector": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", - "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.23.2" - } - }, - "node_modules/i18next-http-backend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", - "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "cross-fetch": "4.0.0" - } - }, - "node_modules/i18next-http-backend/node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "node_modules/i18next-parser": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/i18next-parser/-/i18next-parser-9.3.0.tgz", @@ -12158,37 +12124,6 @@ } } }, - "node_modules/storybook-i18n": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/storybook-i18n/-/storybook-i18n-4.0.5.tgz", - "integrity": "sha512-uy6k7N5VU8PRSoMo6tVYo1WNSDRd8Z3goSku7J1Cz8A8WseBN5xAnGZ/IbO5DLUOVBetLZdaKHBVoLKbYidHjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@storybook/icons": "^1.4.0" - }, - "peerDependencies": { - "storybook": "^9.0.0" - } - }, - "node_modules/storybook-react-i18next": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/storybook-react-i18next/-/storybook-react-i18next-4.0.11.tgz", - "integrity": "sha512-p6gcz8//n7mtBaP75yZx910/t9Z4aIwOP+xzCvxwTzWL19NT1YGTR4GyR0ybzbEebqlPJtJVHnpGKQQD4wRyYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "storybook-i18n": "^4.0.5" - }, - "peerDependencies": { - "i18next": "^22.0.0 || ^23.0.0 || ^24.0.0 || ^25.0.0", - "i18next-browser-languagedetector": "^7.0.0 || ^8.0.0", - "i18next-http-backend": "^2.0.0 || ^3.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-i18next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", - "storybook": "^9.0.0" - } - }, "node_modules/storybook/node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 8800016b5..af23fc784 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -73,7 +73,6 @@ "postcss-nesting": "^13.0.2", "rimraf": "^6.0.1", "storybook": "^9.1.5", - "storybook-react-i18next": "4.0.11", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", "vite": "7.1.7", From 02e6160f6fcf378f9773e148b79146ae0f0e53cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:49:39 +0000 Subject: [PATCH 102/296] build(deps-dev): bump knip from 5.63.1 to 5.64.1 in /frontend Bumps [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) from 5.63.1 to 5.64.1. - [Release notes](https://github.com/webpro-nl/knip/releases) - [Changelog](https://github.com/webpro-nl/knip/blob/main/packages/knip/.release-it.json) - [Commits](https://github.com/webpro-nl/knip/commits/5.64.1/packages/knip) --- updated-dependencies: - dependency-name: knip dependency-version: 5.64.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 214 ++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 106 insertions(+), 110 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 51c19ca73..4a8a1c03e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -55,7 +55,7 @@ "graphql": "^16.11.0", "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", - "knip": "^5.63.1", + "knip": "^5.64.1", "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", @@ -3743,16 +3743,16 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.4.tgz", - "integrity": "sha512-+ZEtJPp8EF8h4kN6rLQECRor00H7jtDgBVtttIUoxuDkXLiQMaSBqju3LV/IEsMvqVG5pviUvR4jYhIA1xNm8w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.5.tgz", + "integrity": "sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { "@emnapi/core": "^1.5.0", "@emnapi/runtime": "^1.5.0", - "@tybys/wasm-util": "^0.10.0" + "@tybys/wasm-util": "^0.10.1" } }, "node_modules/@nodelib/fs.scandir": { @@ -3819,9 +3819,9 @@ "license": "MIT" }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.7.2.tgz", - "integrity": "sha512-ITflrd9l5pFPXW10w1gOGJqmyeO6LTO/yiXb3st4Uqr6bcPxCdsXZXAZop3QsSeE8DjjfGXv3Ws+Fb2KmYeCrA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.8.4.tgz", + "integrity": "sha512-6BjMji0TcvQfJ4EoSunOSyu/SiyHKficBD0V3Y0NxF0beaNnnZ7GYEi2lHmRNnRCuIPK8IuVqQ6XizYau+CkKw==", "cpu": [ "arm" ], @@ -3833,9 +3833,9 @@ ] }, "node_modules/@oxc-resolver/binding-android-arm64": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.7.2.tgz", - "integrity": "sha512-mjEqCGOZHBpIkjSskW0jkhhVSnaREMmXYW5oDaJKBx86kFSiufEjo8duLTwjRekQ0JlwlEtWiXA759eO4TJ7/w==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.8.4.tgz", + "integrity": "sha512-SxF4X6rzCBS9XNPXKZGoIHIABjfGmtQpEgRBDzpDHx5VTuLAUmwLTHXnVBAZoX5bmnhF79RiMElavzFdJ2cA1A==", "cpu": [ "arm64" ], @@ -3847,9 +3847,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-arm64": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.7.2.tgz", - "integrity": "sha512-sXgElUiNredwvWshUXKL7RbBr6ovSthg3fCTQViY8/jfWKnDRKhUFZiCwABma0CWXC1X2Ij6EkZj40cufRM0bA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.8.4.tgz", + "integrity": "sha512-8zWeERrzgscAniE6kh1TQ4E7GJyglYsvdoKrHYLBCbHWD+0/soffiwAYxZuckKEQSc2RXMSPjcu+JTCALaY0Dw==", "cpu": [ "arm64" ], @@ -3861,9 +3861,9 @@ ] }, "node_modules/@oxc-resolver/binding-darwin-x64": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.7.2.tgz", - "integrity": "sha512-EOqYSn1+L5KsShn5lZ303eU9MqjxHNzA7GOHthIcVXfCPtJ+zL89wXh25F+J7mSwiDilp444+rR1hc5Lh+eEWg==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.8.4.tgz", + "integrity": "sha512-BUwggKz8Hi5uEQ0AeVTSun1+sp4lzNcItn+L7fDsHu5Cx0Zueuo10BtVm+dIwmYVVPL5oGYOeD0fS7MKAazKiw==", "cpu": [ "x64" ], @@ -3875,9 +3875,9 @@ ] }, "node_modules/@oxc-resolver/binding-freebsd-x64": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.7.2.tgz", - "integrity": "sha512-Dyvdj++qc5ANVN3JzqJVAlb+IMUtYLPyLaiPFW4+JfvAQFf/iYkpFQv7maeXhhR+GK3rI+PUQXP2HSIiPsClRg==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.8.4.tgz", + "integrity": "sha512-fPO5TQhnn8gA6yP4o49lc4Gn8KeDwAp9uYd4PlE3Q00JVqU6cY9WecDhYHrWtiFcyoZ8UVBlIxuhRqT/DP4Z4A==", "cpu": [ "x64" ], @@ -3889,9 +3889,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.7.2.tgz", - "integrity": "sha512-wUSx/QqggWowrAiyTSci5YUdHvRFpeBbCn2pUwT8XwDoSY2CBuMYR5qzm68ijjzmrv/XyMhl9HxBLy8/UbczWQ==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.8.4.tgz", + "integrity": "sha512-QuNbdUaVGiP0W0GrXsvCDZjqeL4lZGU7aXlx/S2tCvyTk3wh6skoiLJgqUf/eeqXfUPnzTfntYqyfolzCAyBYA==", "cpu": [ "arm" ], @@ -3903,9 +3903,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.7.2.tgz", - "integrity": "sha512-6w91XhCno0OMqv+UqiuMahasl87Ae8sdSSEFBLF2ic+ySZg+BPpFO5VYUBtdSFJ6gWy7R66JudB5HUJpMbMZlA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.8.4.tgz", + "integrity": "sha512-p/zLMfza8OsC4BDKxqeZ9Qel+4eA/oiMSyKLRkMrTgt6OWQq1d5nHntjfG35Abcw4ev6Q9lRU3NOW5hj0xlUbw==", "cpu": [ "arm" ], @@ -3917,9 +3917,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-gnu": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.7.2.tgz", - "integrity": "sha512-S2FQ4cYK7JgmTCy0ay5UIUiRTrQdtKUSaAoC+En9yqaoZwHxcQy9HJ53k5jiAPIJnDR0NgAaOl3q11PUxd58XQ==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.8.4.tgz", + "integrity": "sha512-bvJF9wWxF1+a5YZATlS5JojpOMC7OsnTatA6sXVHoOb7MIigjledYB5ZMAeRrnWWexRMiEX3YSaA46oSfOzmOg==", "cpu": [ "arm64" ], @@ -3931,9 +3931,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-arm64-musl": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.7.2.tgz", - "integrity": "sha512-4Dq8KAJZ4RNe7uSISsoP2/O7fc/rZWqxgkch/5eqa0N0gHMrHd9moGzvdV9Hi9oRSnuTmHzRQTqy02S5L3Rc/g==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.8.4.tgz", + "integrity": "sha512-gf4nwGBfu+EFwOn5p7/T7VF4jmIdfodwJS9MRkOBHvuAm3LQgCX7O6d3Y80mm0TV7ZMRD/trfW628rHfd5++vQ==", "cpu": [ "arm64" ], @@ -3945,9 +3945,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.7.2.tgz", - "integrity": "sha512-/w0wJkrtcjvPUNthhmhbG269ySFgxr/DQCYzhBxICKWbiafmNvJTnmYGtEZKoI+wwnukFL8TT7LWbu7hzdp7mw==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.8.4.tgz", + "integrity": "sha512-T120R5GIzRd41rYWWKCI6cSYrZjmRQzf3X4xeE1WX396Uabz5DX8KU7RnVHihSK+KDxccCVOFBxcH3ITd+IEpw==", "cpu": [ "ppc64" ], @@ -3959,9 +3959,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.7.2.tgz", - "integrity": "sha512-sFg880S4QCzBw4yqgPDi48sAxGT1iRW6Gd+C/FW2WYXsDK7dnHgWQ8f6Rp509fHGkPAe+G2ZypjrgPhZP4Btew==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.8.4.tgz", + "integrity": "sha512-PVG7SxBFFjAaQ76p9O/0Xt5mTBlziRwpck+6cRNhy/hbWY/hSt8BFfPqw0EDSfnl40Uuh+NPsHFMnaWWyxbQEg==", "cpu": [ "riscv64" ], @@ -3973,9 +3973,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-riscv64-musl": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.7.2.tgz", - "integrity": "sha512-dypXqqwA67fVVpVUedpmHNEYn5vRe/y6zoAvDTfy7Se8QIbkeRvrp1EOL+Q8tfxMM72tdMxgOrfyvJ5SPRgy9Q==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.8.4.tgz", + "integrity": "sha512-L0OklUhM2qLGaKvPSyKmwWpoijfc++VJtPyVgz031ShOXyo0WjD0ZGzusyJMsA1a/gdulAmN6CQ/0Sf4LGXEcw==", "cpu": [ "riscv64" ], @@ -3987,9 +3987,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-s390x-gnu": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.7.2.tgz", - "integrity": "sha512-aYDSyViNixd3YpUNcPvfhxAYUiBIPNXfVriTTHEz1ftNg+PglYrOZl5IAssj9uveO6pn2PpNOp/zAezeTtlwmA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.8.4.tgz", + "integrity": "sha512-18Ajz5hqO4cRGuoHzLFUsIPod9GIaIRDiXFg2m6CS3NgVdHx7iCZscplYH7KtjdE42M8nGWYMyyq5BOk7QVgPw==", "cpu": [ "s390x" ], @@ -4001,9 +4001,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-gnu": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.7.2.tgz", - "integrity": "sha512-/f5rmPZYeD2/d/siP6wvGGOQsupl074qtvPfSteQnWLIM5lWuUDa/53atjYMJHRHFhfQ7b4B3l84TaO8lszAkA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.8.4.tgz", + "integrity": "sha512-uHvH4RyYBdQ/lFGV9H+R1ScHg6EBnAhE3mnX+u+mO/btnalvg7j80okuHf8Qw0tLQiP5P1sEBoVeE6zviXY9IA==", "cpu": [ "x64" ], @@ -4015,9 +4015,9 @@ ] }, "node_modules/@oxc-resolver/binding-linux-x64-musl": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.7.2.tgz", - "integrity": "sha512-5x9CGGTZfGWtemVnkNu4ZjqH4X9Oy+Ovm4wSlQTiKgpwCrSDjj0s4tITqiMif0mkWgoErxpdzfD8+hKQkOIgtw==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.8.4.tgz", + "integrity": "sha512-X5z44qh5DdJfVhcqXAQFTDFUpcxdpf6DT/lHL5CFcdQGIZxatjc7gFUy05IXPI9xwfq39RValjJBvFovUk9XBw==", "cpu": [ "x64" ], @@ -4029,9 +4029,9 @@ ] }, "node_modules/@oxc-resolver/binding-wasm32-wasi": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.7.2.tgz", - "integrity": "sha512-UlUxMVChYfi8nmuT9h9I7rQOfini6b40Ud4zYSeel5Qk8GvUT6eysVXAb+AUCJHMnuFCo6jgGqtXYb3yB5CWEQ==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.8.4.tgz", + "integrity": "sha512-z3906y+cd8RRhBGNwHRrRAFxnKjXsBeL3+rdQjZpBrUyrhhsaV5iKD/ROx64FNJ9GjL/9mfon8A5xx/McYIqHA==", "cpu": [ "wasm32" ], @@ -4039,16 +4039,16 @@ "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.0.4" + "@napi-rs/wasm-runtime": "^1.0.5" }, "engines": { "node": ">=14.0.0" } }, "node_modules/@oxc-resolver/binding-win32-arm64-msvc": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.7.2.tgz", - "integrity": "sha512-9S/VfFcl/Tty7TI/ijXgoh05YUzCwP1ApDZxPU8OPFoVTOqnFPQzR8ysR3i/ajQEcEaiCop0aIqXd0xt7wTxNg==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.8.4.tgz", + "integrity": "sha512-70vXFs74uA3X5iYOkpclbkWlQEF+MI325uAQ+Or2n8HJip2T0SEmuBlyw/sRL2E8zLC4oocb+1g25fmzlDVkmg==", "cpu": [ "arm64" ], @@ -4060,9 +4060,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-ia32-msvc": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.7.2.tgz", - "integrity": "sha512-6ruLagAgDx2CCYWVTJJofee4Lq9Oo9wBmKKZowNPwLgurSTGPO0zQDjPvytQ1PjJuOGisqCVLARBsMwbM20mvA==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-11.8.4.tgz", + "integrity": "sha512-SEOUAzTvr+nyMia3nx1dMtD7YUxZwuhQ3QAPnxy21261Lj0yT3JY4EIfwWH54lAWWfMdRSRRMFuGeF/dq7XjEw==", "cpu": [ "ia32" ], @@ -4074,9 +4074,9 @@ ] }, "node_modules/@oxc-resolver/binding-win32-x64-msvc": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.7.2.tgz", - "integrity": "sha512-gp4xNjGkeeNPxjutTSB1AkYm7JQQof6s7wswzzAKuVZO82L1q4HcOz8QYa5PKPP+r2VHUAJAI+FO/X0pNfWn3w==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.8.4.tgz", + "integrity": "sha512-1gARIQsOPOU7LJ7jvMyPmZEVMapL/PymeG3J7naOdLZDrIZKX6CTvgawJmETYKt+8icP8M6KbBinrVkKVqFd+A==", "cpu": [ "x64" ], @@ -9461,9 +9461,9 @@ } }, "node_modules/knip": { - "version": "5.63.1", - "resolved": "https://registry.npmjs.org/knip/-/knip-5.63.1.tgz", - "integrity": "sha512-wSznedUAzcU4o9e0O2WPqDnP7Jttu8cesq/R23eregRY8QYQ9NLJ3aGt9fadJfRzPBoU4tRyutwVQu6chhGDlA==", + "version": "5.64.1", + "resolved": "https://registry.npmjs.org/knip/-/knip-5.64.1.tgz", + "integrity": "sha512-80XnLsyeXuyxj1F4+NBtQFHxaRH0xWRw8EKwfQ6EkVZZ0bSz/kqqan08k/Qg8ajWsFPhFq+0S2RbLCBGIQtuOg==", "dev": true, "funding": [ { @@ -9480,16 +9480,15 @@ "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", - "jiti": "^2.5.1", + "jiti": "^2.6.0", "js-yaml": "^4.1.0", "minimist": "^1.2.8", - "oxc-resolver": "^11.6.2", + "oxc-resolver": "^11.8.3", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.4.1", "strip-json-comments": "5.0.2", - "zod": "^3.25.0", - "zod-validation-error": "^3.0.3" + "zod": "^4.1.11" }, "bin": { "knip": "bin/knip.js", @@ -9500,19 +9499,29 @@ }, "peerDependencies": { "@types/node": ">=18", - "typescript": ">=5.0.4" + "typescript": ">=5.0.4 <7" } }, "node_modules/knip/node_modules/jiti": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", - "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz", + "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==", "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/knip/node_modules/zod": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.11.tgz", + "integrity": "sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/lead": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz", @@ -10423,9 +10432,9 @@ "license": "MIT" }, "node_modules/oxc-resolver": { - "version": "11.7.2", - "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.7.2.tgz", - "integrity": "sha512-abgiTgtJ7FLVPdg5x+rcfoSqz5kpgS/j1Rk/BFNVlLbpAI56VXCj/MM7NyfQb+aVlQDBum0omdz4uFrOYEjNIw==", + "version": "11.8.4", + "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.8.4.tgz", + "integrity": "sha512-qpimS3tHHEf+kgESMAme+q+rj7aCzMya00u9YdKOKyX2o7q4lozjPo6d7ZTTi979KHEcVOPWdNTueAKdeNq72w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10436,25 +10445,25 @@ "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "@oxc-resolver/binding-android-arm-eabi": "11.7.2", - "@oxc-resolver/binding-android-arm64": "11.7.2", - "@oxc-resolver/binding-darwin-arm64": "11.7.2", - "@oxc-resolver/binding-darwin-x64": "11.7.2", - "@oxc-resolver/binding-freebsd-x64": "11.7.2", - "@oxc-resolver/binding-linux-arm-gnueabihf": "11.7.2", - "@oxc-resolver/binding-linux-arm-musleabihf": "11.7.2", - "@oxc-resolver/binding-linux-arm64-gnu": "11.7.2", - "@oxc-resolver/binding-linux-arm64-musl": "11.7.2", - "@oxc-resolver/binding-linux-ppc64-gnu": "11.7.2", - "@oxc-resolver/binding-linux-riscv64-gnu": "11.7.2", - "@oxc-resolver/binding-linux-riscv64-musl": "11.7.2", - "@oxc-resolver/binding-linux-s390x-gnu": "11.7.2", - "@oxc-resolver/binding-linux-x64-gnu": "11.7.2", - "@oxc-resolver/binding-linux-x64-musl": "11.7.2", - "@oxc-resolver/binding-wasm32-wasi": "11.7.2", - "@oxc-resolver/binding-win32-arm64-msvc": "11.7.2", - "@oxc-resolver/binding-win32-ia32-msvc": "11.7.2", - "@oxc-resolver/binding-win32-x64-msvc": "11.7.2" + "@oxc-resolver/binding-android-arm-eabi": "11.8.4", + "@oxc-resolver/binding-android-arm64": "11.8.4", + "@oxc-resolver/binding-darwin-arm64": "11.8.4", + "@oxc-resolver/binding-darwin-x64": "11.8.4", + "@oxc-resolver/binding-freebsd-x64": "11.8.4", + "@oxc-resolver/binding-linux-arm-gnueabihf": "11.8.4", + "@oxc-resolver/binding-linux-arm-musleabihf": "11.8.4", + "@oxc-resolver/binding-linux-arm64-gnu": "11.8.4", + "@oxc-resolver/binding-linux-arm64-musl": "11.8.4", + "@oxc-resolver/binding-linux-ppc64-gnu": "11.8.4", + "@oxc-resolver/binding-linux-riscv64-gnu": "11.8.4", + "@oxc-resolver/binding-linux-riscv64-musl": "11.8.4", + "@oxc-resolver/binding-linux-s390x-gnu": "11.8.4", + "@oxc-resolver/binding-linux-x64-gnu": "11.8.4", + "@oxc-resolver/binding-linux-x64-musl": "11.8.4", + "@oxc-resolver/binding-wasm32-wasi": "11.8.4", + "@oxc-resolver/binding-win32-arm64-msvc": "11.8.4", + "@oxc-resolver/binding-win32-ia32-msvc": "11.8.4", + "@oxc-resolver/binding-win32-x64-msvc": "11.8.4" } }, "node_modules/p-limit": { @@ -13862,19 +13871,6 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } - }, - "node_modules/zod-validation-error": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.5.3.tgz", - "integrity": "sha512-OT5Y8lbUadqVZCsnyFaTQ4/O2mys4tj7PqhdbBCp7McPwvIEKfPtdA6QfPeFQK2/Rz5LgwmAXRJTugBNBi0btw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } } } } diff --git a/frontend/package.json b/frontend/package.json index 42e602e3f..05a42fa56 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -65,7 +65,7 @@ "graphql": "^16.11.0", "happy-dom": "^18.0.1", "i18next-parser": "^9.3.0", - "knip": "^5.63.1", + "knip": "^5.64.1", "msw": "^2.11.2", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", From d321cc493e11a9edcb4f80f3247c9581e41f5cee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:49:47 +0000 Subject: [PATCH 103/296] build(deps-dev): bump happy-dom from 18.0.1 to 19.0.2 in /frontend Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 18.0.1 to 19.0.2. - [Release notes](https://github.com/capricorn86/happy-dom/releases) - [Commits](https://github.com/capricorn86/happy-dom/compare/v18.0.1...v19.0.2) --- updated-dependencies: - dependency-name: happy-dom dependency-version: 19.0.2 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 51c19ca73..8dba9e213 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -53,7 +53,7 @@ "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", "graphql": "^16.11.0", - "happy-dom": "^18.0.1", + "happy-dom": "^19.0.2", "i18next-parser": "^9.3.0", "knip": "^5.63.1", "msw": "^2.11.2", @@ -8607,9 +8607,9 @@ } }, "node_modules/happy-dom": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-18.0.1.tgz", - "integrity": "sha512-qn+rKOW7KWpVTtgIUi6RVmTBZJSe2k0Db0vh1f7CWrWclkkc7/Q+FrOfkZIb2eiErLyqu5AXEzE7XthO9JVxRA==", + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-19.0.2.tgz", + "integrity": "sha512-831CLbgDyjRbd2lApHZFsBDe56onuFcjsCBPodzWpzedTpeDr8CGZjs7iEIdNW1DVwSFRecfwzLpVyGBPamwGA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 42e602e3f..f9a9544b3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -63,7 +63,7 @@ "autoprefixer": "^10.4.21", "browserslist-to-esbuild": "^2.1.1", "graphql": "^16.11.0", - "happy-dom": "^18.0.1", + "happy-dom": "^19.0.2", "i18next-parser": "^9.3.0", "knip": "^5.63.1", "msw": "^2.11.2", From 61001ece7df4509c52f8c4e44ba2e7f935cb91f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:51:34 +0000 Subject: [PATCH 104/296] build(deps): bump regex from 1.11.2 to 1.11.3 Bumps [regex](https://github.com/rust-lang/regex) from 1.11.2 to 1.11.3. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.11.2...1.11.3) --- updated-dependencies: - dependency-name: regex dependency-version: 1.11.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a46acf3d..ca0435af5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4900,9 +4900,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -4912,9 +4912,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index b73535c58..e42e83b06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -492,7 +492,7 @@ version = "0.6.4" # Regular expressions [workspace.dependencies.regex] -version = "1.11.2" +version = "1.11.3" # High-level HTTP client [workspace.dependencies.reqwest] From 6513a3688b55e2f5ab1ded449d9a2748d5f0c631 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:52:42 +0000 Subject: [PATCH 105/296] build(deps): bump zeroize from 1.8.1 to 1.8.2 Bumps [zeroize](https://github.com/RustCrypto/utils) from 1.8.1 to 1.8.2. - [Commits](https://github.com/RustCrypto/utils/compare/zeroize-v1.8.1...zeroize-v1.8.2) --- updated-dependencies: - dependency-name: zeroize dependency-version: 1.8.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a46acf3d..f2b560a90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7834,9 +7834,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" diff --git a/Cargo.toml b/Cargo.toml index b73535c58..c1a5bb2ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -735,7 +735,7 @@ version = "0.5.5" # Zero memory after use [workspace.dependencies.zeroize] -version = "1.8.1" +version = "1.8.2" # Password strength estimation [workspace.dependencies.zxcvbn] From 57a035640678996220e580625273282cdb014724 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:53:07 +0000 Subject: [PATCH 106/296] build(deps): bump psl from 2.1.145 to 2.1.146 Bumps [psl](https://github.com/addr-rs/psl) from 2.1.145 to 2.1.146. - [Release notes](https://github.com/addr-rs/psl/releases) - [Commits](https://github.com/addr-rs/psl/compare/v2.1.145...v2.1.146) --- updated-dependencies: - dependency-name: psl dependency-version: 2.1.146 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a46acf3d..6adde1146 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4677,9 +4677,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.145" +version = "2.1.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bc7bed4cdf5168c58514ad64f37615f6683882209e2b6ba345cda0c6b8d949" +checksum = "5d3e8d3ee29451fe165c689769401440c0d028cf015123f4a8b6c9ca9bbf2b82" dependencies = [ "psl-types", ] diff --git a/Cargo.toml b/Cargo.toml index b73535c58..2394e8f7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -476,7 +476,7 @@ features = ["std", "pkcs5", "encryption"] # Public Suffix List [workspace.dependencies.psl] -version = "2.1.145" +version = "2.1.146" # High-precision clock [workspace.dependencies.quanta] From e18090b1c459d8daa01f00a67328315d9c894de3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 09:57:23 +0000 Subject: [PATCH 107/296] build(deps-dev): bump msw from 2.11.2 to 2.11.3 in /frontend Bumps [msw](https://github.com/mswjs/msw) from 2.11.2 to 2.11.3. - [Release notes](https://github.com/mswjs/msw/releases) - [Changelog](https://github.com/mswjs/msw/blob/main/CHANGELOG.md) - [Commits](https://github.com/mswjs/msw/compare/v2.11.2...v2.11.3) --- updated-dependencies: - dependency-name: msw dependency-version: 2.11.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 20 +++++++++++++++----- frontend/package.json | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6d4e2bb28..a9e2d8889 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -56,7 +56,7 @@ "happy-dom": "^19.0.2", "i18next-parser": "^9.3.0", "knip": "^5.64.1", - "msw": "^2.11.2", + "msw": "^2.11.3", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", @@ -10112,9 +10112,9 @@ "license": "MIT" }, "node_modules/msw": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.2.tgz", - "integrity": "sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==", + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.11.3.tgz", + "integrity": "sha512-878imp8jxIpfzuzxYfX0qqTq1IFQz/1/RBHs/PyirSjzi+xKM/RRfIpIqHSCWjH0GxidrjhgiiXC+DWXNDvT9w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10124,7 +10124,6 @@ "@inquirer/confirm": "^5.0.0", "@mswjs/interceptors": "^0.39.1", "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/until": "^2.1.0", "@types/cookie": "^0.6.0", "@types/statuses": "^2.0.4", "graphql": "^16.8.1", @@ -10137,6 +10136,7 @@ "strict-event-emitter": "^0.5.1", "tough-cookie": "^6.0.0", "type-fest": "^4.26.1", + "until-async": "^3.0.2", "yargs": "^17.7.2" }, "bin": { @@ -13062,6 +13062,16 @@ "node": ">=14.0.0" } }, + "node_modules/until-async": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/until-async/-/until-async-3.0.2.tgz", + "integrity": "sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/kettanaito" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index ea0c6aa32..c6814699d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -66,7 +66,7 @@ "happy-dom": "^19.0.2", "i18next-parser": "^9.3.0", "knip": "^5.64.1", - "msw": "^2.11.2", + "msw": "^2.11.3", "msw-storybook-addon": "^2.0.5", "postcss": "^8.5.6", "postcss-import": "^16.1.1", From 10efae35fec78c1d06456ef41e59bbc4a1e3eb4f Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 12:07:13 +0200 Subject: [PATCH 108/296] Admin API: add endpoint to get an Upstream OAuth Provider by ID --- crates/handlers/src/admin/v1/mod.rs | 7 + .../admin/v1/upstream_oauth_providers/get.rs | 196 ++++++++++++++++++ .../admin/v1/upstream_oauth_providers/mod.rs | 6 +- docs/api/spec.json | 78 +++++++ 4 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index 8a182bf2f..c0b5d8ddb 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -195,4 +195,11 @@ where self::upstream_oauth_providers::list_doc, ), ) + .api_route( + "/upstream-oauth-providers/{id}", + get_with( + self::upstream_oauth_providers::get, + self::upstream_oauth_providers::get_doc, + ), + ) } diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs new file mode 100644 index 000000000..3700e1a65 --- /dev/null +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/get.rs @@ -0,0 +1,196 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::{OperationIo, transform::TransformOperation}; +use axum::{Json, response::IntoResponse}; +use hyper::StatusCode; +use mas_axum_utils::record_error; +use mas_storage::{RepositoryAccess, upstream_oauth2::UpstreamOAuthProviderRepository}; + +use crate::{ + admin::{ + call_context::CallContext, + model::UpstreamOAuthProvider, + params::UlidPathParam, + response::{ErrorResponse, SingleResponse}, + }, + impl_from_error_for_route, +}; + +#[derive(Debug, thiserror::Error, OperationIo)] +#[aide(output_with = "Json")] +pub enum RouteError { + #[error(transparent)] + Internal(Box), + + #[error("Provider not found")] + NotFound, +} + +impl_from_error_for_route!(mas_storage::RepositoryError); + +impl IntoResponse for RouteError { + fn into_response(self) -> axum::response::Response { + let error = ErrorResponse::from_error(&self); + let sentry_event_id = record_error!(self, Self::Internal(_)); + let status = match self { + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound => StatusCode::NOT_FOUND, + }; + + (status, sentry_event_id, Json(error)).into_response() + } +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("getUpstreamOAuthProvider") + .summary("Get upstream OAuth provider") + .tag("upstream-oauth-provider") + .response_with::<200, Json>, _>(|t| { + let [sample, ..] = UpstreamOAuthProvider::samples(); + t.description("The upstream OAuth provider") + .example(SingleResponse::new_canonical(sample)) + }) + .response_with::<404, Json, _>(|t| t.description("Provider not found")) +} + +#[tracing::instrument(name = "handler.admin.v1.upstream_oauth_providers.get", skip_all)] +pub async fn handler( + CallContext { mut repo, .. }: CallContext, + id: UlidPathParam, +) -> Result>, RouteError> { + let provider = repo + .upstream_oauth_provider() + .lookup(*id) + .await? + .ok_or(RouteError::NotFound)?; + + Ok(Json(SingleResponse::new_canonical( + UpstreamOAuthProvider::from(provider), + ))) +} + +#[cfg(test)] +mod tests { + use hyper::{Request, StatusCode}; + use mas_data_model::{ + UpstreamOAuthProvider, UpstreamOAuthProviderClaimsImports, + UpstreamOAuthProviderDiscoveryMode, UpstreamOAuthProviderOnBackchannelLogout, + UpstreamOAuthProviderPkceMode, UpstreamOAuthProviderTokenAuthMethod, + }; + use mas_iana::jose::JsonWebSignatureAlg; + use mas_storage::{ + RepositoryAccess, + upstream_oauth2::{UpstreamOAuthProviderParams, UpstreamOAuthProviderRepository}, + }; + use oauth2_types::scope::{OPENID, Scope}; + use sqlx::PgPool; + use ulid::Ulid; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + async fn create_test_provider(state: &mut TestState) -> UpstreamOAuthProvider { + let mut repo = state.repository().await.unwrap(); + + let params = UpstreamOAuthProviderParams { + issuer: Some("https://accounts.google.com".to_owned()), + human_name: Some("Google".to_owned()), + brand_name: Some("google".to_owned()), + discovery_mode: UpstreamOAuthProviderDiscoveryMode::Oidc, + pkce_mode: UpstreamOAuthProviderPkceMode::Auto, + jwks_uri_override: None, + authorization_endpoint_override: None, + token_endpoint_override: None, + userinfo_endpoint_override: None, + fetch_userinfo: true, + userinfo_signed_response_alg: None, + client_id: "google-client-id".to_owned(), + encrypted_client_secret: Some("encrypted-secret".to_owned()), + token_endpoint_signing_alg: None, + token_endpoint_auth_method: UpstreamOAuthProviderTokenAuthMethod::ClientSecretPost, + id_token_signed_response_alg: JsonWebSignatureAlg::Rs256, + response_mode: None, + scope: Scope::from_iter([OPENID]), + claims_imports: UpstreamOAuthProviderClaimsImports::default(), + additional_authorization_parameters: vec![], + forward_login_hint: false, + on_backchannel_logout: UpstreamOAuthProviderOnBackchannelLogout::DoNothing, + ui_order: 0, + }; + + let provider = repo + .upstream_oauth_provider() + .add(&mut state.rng(), &state.clock, params) + .await + .unwrap(); + + Box::new(repo).save().await.unwrap(); + + provider + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_get_provider(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + let provider = create_test_provider(&mut state).await; + + let request = Request::get(format!( + "/api/admin/v1/upstream-oauth-providers/{}", + provider.id + )) + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json::(); + + assert_eq!(body["data"]["type"], "upstream-oauth-provider"); + assert_eq!(body["data"]["id"], provider.id.to_string()); + assert_eq!(body["data"]["attributes"]["human_name"], "Google"); + + insta::assert_json_snapshot!(body, @r###" + { + "data": { + "type": "upstream-oauth-provider", + "id": "01FSHN9AG0MZAA6S4AF7CTV32E", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "2022-01-16T14:40:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01FSHN9AG0MZAA6S4AF7CTV32E" + } + } + "###); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_not_found(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let admin_token = state.token_with_scope("urn:mas:admin").await; + + let provider_id = Ulid::nil(); + let request = Request::get(format!( + "/api/admin/v1/upstream-oauth-providers/{provider_id}" + )) + .bearer(&admin_token) + .empty(); + + let response = state.request(request).await; + response.assert_status(StatusCode::NOT_FOUND); + } +} diff --git a/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs b/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs index a04301246..18ffe5af6 100644 --- a/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs +++ b/crates/handlers/src/admin/v1/upstream_oauth_providers/mod.rs @@ -3,6 +3,10 @@ // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. +mod get; mod list; -pub use self::list::{doc as list_doc, handler as list}; +pub use self::{ + get::{doc as get_doc, handler as get}, + list::{doc as list_doc, handler as list}, +}; diff --git a/docs/api/spec.json b/docs/api/spec.json index 154fa08e3..17403f538 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -3552,6 +3552,68 @@ } } } + }, + "/api/admin/v1/upstream-oauth-providers/{id}": { + "get": { + "tags": [ + "upstream-oauth-provider" + ], + "summary": "Get upstream OAuth provider", + "operationId": "getUpstreamOAuthProvider", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "The ID of the resource", + "$ref": "#/components/schemas/ULID" + }, + "style": "simple" + } + ], + "responses": { + "200": { + "description": "The upstream OAuth provider", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SingleResponse_for_UpstreamOAuthProvider" + }, + "example": { + "data": { + "type": "upstream-oauth-provider", + "id": "01040G2081040G2081040G2081", + "attributes": { + "issuer": "https://accounts.google.com", + "human_name": "Google", + "brand_name": "google", + "created_at": "1970-01-01T00:00:00Z", + "disabled_at": null + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" + } + }, + "links": { + "self": "/api/admin/v1/upstream-oauth-providers/01040G2081040G2081040G2081" + } + } + } + } + }, + "404": { + "description": "Provider not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } } }, "components": { @@ -5243,6 +5305,22 @@ "nullable": true } } + }, + "SingleResponse_for_UpstreamOAuthProvider": { + "description": "A top-level response with a single resource", + "type": "object", + "required": [ + "data", + "links" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/SingleResource_for_UpstreamOAuthProvider" + }, + "links": { + "$ref": "#/components/schemas/SelfLinks" + } + } } } }, From f8b078efe8284c8d2a44fbafef6da0724463768a Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 12:13:15 +0200 Subject: [PATCH 109/296] Update msw to 2.11.3 --- frontend/.storybook/public/mockServiceWorker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/.storybook/public/mockServiceWorker.js b/frontend/.storybook/public/mockServiceWorker.js index 2eec3ee33..15623f109 100644 --- a/frontend/.storybook/public/mockServiceWorker.js +++ b/frontend/.storybook/public/mockServiceWorker.js @@ -7,7 +7,7 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.11.2' +const PACKAGE_VERSION = '2.11.3' const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() From 50a8d00dc6966312540526ba7c70d2d87575819b Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 13:23:54 +0200 Subject: [PATCH 110/296] Admin API: make sure the meta fields are nullable --- crates/handlers/src/admin/response.rs | 2 + docs/api/spec.json | 84 +++++++++++++-------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/crates/handlers/src/admin/response.rs b/crates/handlers/src/admin/response.rs index 2ed50d8ce..257773cd2 100644 --- a/crates/handlers/src/admin/response.rs +++ b/crates/handlers/src/admin/response.rs @@ -59,6 +59,7 @@ impl PaginationMeta { pub struct PaginatedResponse { /// Response metadata #[serde(skip_serializing_if = "PaginationMeta::is_empty")] + #[schemars(with = "Option")] meta: PaginationMeta, /// The list of resources @@ -183,6 +184,7 @@ struct SingleResource { /// Metadata about the resource #[serde(skip_serializing_if = "SingleResourceMeta::is_empty")] + #[schemars(with = "Option")] meta: SingleResourceMeta, } diff --git a/docs/api/spec.json b/docs/api/spec.json index 17403f538..98f8b2532 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -3810,13 +3810,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -3851,7 +3851,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -3873,7 +3872,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4132,13 +4132,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -4161,7 +4161,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4183,7 +4182,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4306,7 +4306,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4328,7 +4327,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4387,13 +4387,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -4416,7 +4416,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4438,7 +4437,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4593,13 +4593,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -4622,7 +4622,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4644,7 +4643,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4733,13 +4733,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -4762,7 +4762,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4784,7 +4783,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -4875,13 +4875,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -4904,7 +4904,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -4926,7 +4925,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -5069,13 +5069,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -5098,7 +5098,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -5120,7 +5119,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, @@ -5216,13 +5216,13 @@ "description": "A top-level response with a page of resources", "type": "object", "required": [ - "links", - "meta" + "links" ], "properties": { "meta": { "description": "Response metadata", - "$ref": "#/components/schemas/PaginationMeta" + "$ref": "#/components/schemas/PaginationMeta", + "nullable": true }, "data": { "description": "The list of resources", @@ -5245,7 +5245,6 @@ "attributes", "id", "links", - "meta", "type" ], "properties": { @@ -5267,7 +5266,8 @@ }, "meta": { "description": "Metadata about the resource", - "$ref": "#/components/schemas/SingleResourceMeta" + "$ref": "#/components/schemas/SingleResourceMeta", + "nullable": true } } }, From 63c288e3d49f1cc1f95647fabd2f365b0ad16262 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:33:36 +0000 Subject: [PATCH 111/296] build(deps-dev): bump the storybook group in /frontend with 3 updates Bumps the storybook group in /frontend with 3 updates: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite) and [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core). Updates `@storybook/addon-docs` from 9.1.8 to 9.1.9 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.9/code/addons/docs) Updates `@storybook/react-vite` from 9.1.8 to 9.1.9 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.9/code/frameworks/react-vite) Updates `storybook` from 9.1.8 to 9.1.9 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.9/code/core) --- updated-dependencies: - dependency-name: "@storybook/addon-docs" dependency-version: 9.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/react-vite" dependency-version: 9.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-version: 9.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 70 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c47ec39d3..265f9d281 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,8 +36,8 @@ "@graphql-codegen/cli": "^6.0.0", "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.8", - "@storybook/react-vite": "^9.1.8", + "@storybook/addon-docs": "^9.1.9", + "@storybook/react-vite": "^9.1.9", "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", @@ -5161,16 +5161,16 @@ "license": "Apache-2.0" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.8.tgz", - "integrity": "sha512-GVrNVEdNRRo6r1hawfgyy6x+HJqPx1oOHm0U0wz0SGAxgS/Xh6SQVZL+RDoh7NpXkNi1GbezVlT931UsHQTyvQ==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.9.tgz", + "integrity": "sha512-76OHwsYCC6u8Nu5IUQ3E580BVnto6u4UgQC66inf+ot0+LI9fFPieg7fmcnQtYoFwiAyya3/JEwhY2GuFk7eMg==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.8", + "@storybook/csf-plugin": "9.1.9", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.8", + "@storybook/react-dom-shim": "9.1.9", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -5180,17 +5180,17 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.8" + "storybook": "^9.1.9" } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.8.tgz", - "integrity": "sha512-JjvBag0nM1N51O3VF5++op9Ly5OC8Q+y4PrWLgi2dKhMxJFs8fD9D4PeI/v41PUiQcI0suQxN9BoYoKn2QxUZw==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.9.tgz", + "integrity": "sha512-tCQ2Bv07D0roTg6+c1dCrX6PmAwEpKkwX4eqq32vGYiQ0CTzWP1ivBUAzBvIIHD2FY/zLXzXSrDo/qtrQppCGw==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.8", + "@storybook/csf-plugin": "9.1.9", "ts-dedent": "^2.0.0" }, "funding": { @@ -5198,14 +5198,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.8", + "storybook": "^9.1.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.8.tgz", - "integrity": "sha512-KnrXPz87bn+8ZGkzFEBc7TT5HkWpR1Xz7ojxPclSvkKxTfzazuaw0JlOQMzJoI1+wHXDAIw/4MIsO8HEiaWyfQ==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.9.tgz", + "integrity": "sha512-8tMZaGqer9PkPl7xRD/d97pgzl6Aw5/rWH+q8fAA09bvjLllKOlytj3vTckGJ4DlkKKXGvxoECG/n35AbJOYIA==", "dev": true, "license": "MIT", "dependencies": { @@ -5216,7 +5216,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.8" + "storybook": "^9.1.9" } }, "node_modules/@storybook/global": { @@ -5241,14 +5241,14 @@ } }, "node_modules/@storybook/react": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.8.tgz", - "integrity": "sha512-EULkwHroJ4IDYcjIBj9VpGhaZ9E5b8LI84hlfBkJ9rnK44a/GrK1yFRIusukO58qTJSh2Y7zfAFKNuiaWh3Sfw==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.9.tgz", + "integrity": "sha512-S06dZv8ebUmCrIP2GfIqD3g1F5LKBf0Lc1daSd2++2MI6i8zw8kZ8IAGg5bYrWb0nk56JHALCwXAzsGyRepEww==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "9.1.8" + "@storybook/react-dom-shim": "9.1.9" }, "engines": { "node": ">=20.0.0" @@ -5260,7 +5260,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.8", + "storybook": "^9.1.9", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -5270,9 +5270,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.8.tgz", - "integrity": "sha512-OepccjVZh/KQugTH8/RL2CIyf1g5Lwc5ESC8x8BH3iuYc82WMQBwMJzRI5EofQdirau63NGrqkWCgQASoVreEA==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.9.tgz", + "integrity": "sha512-RFaB+N63XXEEo8l5INlvWnqxDUH7UGZ++MOsFsVUqfn7lAzxfR9HcJTGN3WOyIDBoS0vD3+LfnplqFyQU/anuw==", "dev": true, "license": "MIT", "funding": { @@ -5282,20 +5282,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.8" + "storybook": "^9.1.9" } }, "node_modules/@storybook/react-vite": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.8.tgz", - "integrity": "sha512-DIxp76vcelyFOUJupeQEIHXDrSPP6KDXj6Z+Z9thS1HH7JY+OdGtcMLy4fbiD77Zyc8TV9RRZ1D33z2Ot/v9Vw==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.9.tgz", + "integrity": "sha512-k+wbLdM8963YkQmVSFEuigUfGZKEgUdA7tTazXGzkL65j0il93JbtFCso8spKePlgeQ2uD6RxbXUp+E3qLeRSw==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "9.1.8", - "@storybook/react": "9.1.8", + "@storybook/builder-vite": "9.1.9", + "@storybook/react": "9.1.9", "find-up": "^7.0.0", "magic-string": "^0.30.0", "react-docgen": "^8.0.0", @@ -5312,7 +5312,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.8", + "storybook": "^9.1.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -12098,9 +12098,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "9.1.8", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.8.tgz", - "integrity": "sha512-/iP+DvieJ6Mnixy4PFY/KXnhsg/IHIDlTbZqly3EDbveuhsCuIUELfGnj+QSRGf9C6v/f4sZf9sZ3r80ZnKuEA==", + "version": "9.1.9", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.9.tgz", + "integrity": "sha512-KEazHA1iD2L8Fll+Kw9c/z0Pjv3Z+1GHYejmk+JlrIt+/mXDG2HVF7eelvk3tYCbuxqyuCL57pYhJUfkHwA6Fw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index a316bb91c..7ef641218 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,8 +46,8 @@ "@graphql-codegen/cli": "^6.0.0", "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.8", - "@storybook/react-vite": "^9.1.8", + "@storybook/addon-docs": "^9.1.9", + "@storybook/react-vite": "^9.1.9", "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", From 1e2e2abf6da1e44e34631eefcd9709f379cf6d74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:34:29 +0000 Subject: [PATCH 112/296] build(deps): bump swagger-ui-dist from 5.29.0 to 5.29.1 in /frontend Bumps [swagger-ui-dist](https://github.com/swagger-api/swagger-ui) from 5.29.0 to 5.29.1. - [Release notes](https://github.com/swagger-api/swagger-ui/releases) - [Changelog](https://github.com/swagger-api/swagger-ui/blob/master/.releaserc) - [Commits](https://github.com/swagger-api/swagger-ui/compare/v5.29.0...v5.29.1) --- updated-dependencies: - dependency-name: swagger-ui-dist dependency-version: 5.29.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c47ec39d3..58f184036 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -24,7 +24,7 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^16.0.0", - "swagger-ui-dist": "^5.29.0", + "swagger-ui-dist": "^5.29.1", "valibot": "^1.1.0", "vaul": "^1.1.2" }, @@ -12368,9 +12368,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.29.0.tgz", - "integrity": "sha512-gqs7Md3AxP4mbpXAq31o5QW+wGUZsUzVatg70yXpUR245dfIis5jAzufBd+UQM/w2xSfrhvA1eqsrgnl2PbezQ==", + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.29.1.tgz", + "integrity": "sha512-qyjpz0qgcomRr41a5Aye42o69TKwCeHM9F8htLGVeUMKekNS6qAqz9oS7CtSvgGJSppSNAYAIh7vrfrSdHj9zw==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" diff --git a/frontend/package.json b/frontend/package.json index a316bb91c..1e7f5bdd2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,7 +34,7 @@ "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^16.0.0", - "swagger-ui-dist": "^5.29.0", + "swagger-ui-dist": "^5.29.1", "valibot": "^1.1.0", "vaul": "^1.1.2" }, From 25af5f05e71c7393b4fe1b884385f2fdefb22829 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:34:37 +0000 Subject: [PATCH 113/296] build(deps): bump the axum group with 2 updates Bumps the axum group with 2 updates: [axum](https://github.com/tokio-rs/axum) and [axum-extra](https://github.com/tokio-rs/axum). Updates `axum` from 0.8.5 to 0.8.6 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-v0.8.5...axum-v0.8.6) Updates `axum-extra` from 0.10.2 to 0.10.3 - [Release notes](https://github.com/tokio-rs/axum/releases) - [Changelog](https://github.com/tokio-rs/axum/blob/main/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/axum/compare/axum-extra-v0.10.2...axum-extra-v0.10.3) --- updated-dependencies: - dependency-name: axum dependency-version: 0.8.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: axum - dependency-name: axum-extra dependency-version: 0.10.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: axum ... Signed-off-by: dependabot[bot] --- Cargo.lock | 12 ++++++------ Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57bca5291..f0275749d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,9 +553,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98e529aee37b5c8206bb4bf4c44797127566d72f76952c970bd3d1e85de8f4e2" +checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871" dependencies = [ "axum-core", "bytes", @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ac7a6beb1182c7e30253ee75c3e918080bfb83f5a3023bcdf7209d85fd147e6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -605,9 +605,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86d701cd16f401888ebe9c3214dc838c7ef27a405d5726196765a913603b5dd" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" dependencies = [ "axum", "axum-core", diff --git a/Cargo.toml b/Cargo.toml index 9b78abeb2..755da3a35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,11 +96,11 @@ version = "1.5.0" # HTTP router [workspace.dependencies.axum] -version = "0.8.5" +version = "0.8.6" # Extra utilities for Axum [workspace.dependencies.axum-extra] -version = "0.10.2" +version = "0.10.3" features = ["cookie-private", "cookie-key-expansion", "typed-header"] # Axum macros From d3629dff52ed5ec7c2efbd62ea1d359ee6e7d8b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:37:55 +0000 Subject: [PATCH 114/296] build(deps): bump thiserror from 2.0.16 to 2.0.17 Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.16 to 2.0.17. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/2.0.16...2.0.17) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 86 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57bca5291..47e98f515 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,7 +100,7 @@ dependencies = [ "serde", "serde_json", "serde_qs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tower-layer", "tower-service", "tracing", @@ -1022,7 +1022,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -1621,7 +1621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb333721800c025e363e902b293040778f8ac79913db4f013abf1f1d7d382fd7" dependencies = [ "rust_decimal", - "thiserror 2.0.16", + "thiserror 2.0.17", "winnow 0.7.13", ] @@ -3129,7 +3129,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "ulid", @@ -3274,7 +3274,7 @@ dependencies = [ "ruma-common", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "ulid", "url", "woothee", @@ -3287,7 +3287,7 @@ dependencies = [ "async-trait", "lettre", "mas-templates", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -3357,7 +3357,7 @@ dependencies = [ "serde_with", "sha2", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tower", @@ -3410,7 +3410,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "writeable", ] @@ -3478,7 +3478,7 @@ dependencies = [ "serde_with", "sha2", "signature", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", ] @@ -3507,7 +3507,7 @@ dependencies = [ "rsa", "sec1", "spki", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3524,7 +3524,7 @@ dependencies = [ "pin-project-lite", "rustls-pemfile", "socket2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-rustls", "tokio-test", @@ -3556,7 +3556,7 @@ dependencies = [ "mas-matrix", "reqwest", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", "urlencoding", @@ -3591,7 +3591,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "url", @@ -3610,7 +3610,7 @@ dependencies = [ "schemars 0.8.22", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", ] @@ -3632,7 +3632,7 @@ version = "1.3.0" dependencies = [ "camino", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3650,7 +3650,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "tracing-opentelemetry", "ulid", @@ -3677,7 +3677,7 @@ dependencies = [ "sea-query-binder", "serde_json", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "ulid", "url", @@ -3708,7 +3708,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tracing", @@ -3737,7 +3737,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "ulid", @@ -4032,7 +4032,7 @@ dependencies = [ "serde_json", "serde_with", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", ] @@ -4088,7 +4088,7 @@ dependencies = [ "sha1", "sha2", "sprintf", - "thiserror 2.0.16", + "thiserror 1.0.69", "tokio", "tracing", "urlencoding", @@ -4118,7 +4118,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -4156,7 +4156,7 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4223,7 +4223,7 @@ dependencies = [ "percent-encoding", "rand 0.9.2", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -4377,7 +4377,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "ucd-trie", ] @@ -5031,7 +5031,7 @@ dependencies = [ "serde", "serde_html_form", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tracing", "url", @@ -5046,7 +5046,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ad674b5e5368c53a2c90fde7dac7e30747004aaf7b1827b72874a25fc06d4d8" dependencies = [ "js_int", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -5345,7 +5345,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -5501,7 +5501,7 @@ dependencies = [ "rand 0.9.2", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "url", "uuid", @@ -5596,7 +5596,7 @@ dependencies = [ "futures", "percent-encoding", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -5809,7 +5809,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78222247fc55e10208ed1ba60f8296390bc67a489bc27a36231765d8d6f60ec5" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -5855,7 +5855,7 @@ dependencies = [ "serde_json", "sha2", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -5940,7 +5940,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -5980,7 +5980,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "uuid", "whoami", @@ -6006,7 +6006,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", "uuid", @@ -6126,7 +6126,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "thiserror-ext", "tokio", "tokio-util", @@ -6195,11 +6195,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -6208,7 +6208,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fb7e61141f4141832ca9aad63c3c90023843f944a1975460abdacc64d03f534" dependencies = [ - "thiserror 2.0.16", + "thiserror 2.0.17", "thiserror-ext-derive", ] @@ -6237,9 +6237,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -7129,7 +7129,7 @@ dependencies = [ "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 2.0.16", + "thiserror 2.0.17", "wasmparser", "wasmtime-environ", "wasmtime-internal-math", diff --git a/Cargo.toml b/Cargo.toml index 9b78abeb2..f7543c463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -637,7 +637,7 @@ features = [ # Custom error types [workspace.dependencies.thiserror] -version = "2.0.16" +version = "2.0.17" [workspace.dependencies.thiserror-ext] version = "0.3.0" From c3d77e01d242dccd49318e0ce31f50b163990b52 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 15:53:18 +0200 Subject: [PATCH 115/296] Admin API to finish a user session --- crates/handlers/src/admin/v1/mod.rs | 4 + .../src/admin/v1/user_sessions/finish.rs | 216 ++++++++++++++++++ .../src/admin/v1/user_sessions/mod.rs | 2 + docs/api/spec.json | 88 +++++++ 4 files changed, 310 insertions(+) create mode 100644 crates/handlers/src/admin/v1/user_sessions/finish.rs diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index c0b5d8ddb..cb2be5a8d 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -130,6 +130,10 @@ where "/user-sessions/{id}", get_with(self::user_sessions::get, self::user_sessions::get_doc), ) + .api_route( + "/user-sessions/{id}/finish", + post_with(self::user_sessions::finish, self::user_sessions::finish_doc), + ) .api_route( "/user-registration-tokens", get_with( diff --git a/crates/handlers/src/admin/v1/user_sessions/finish.rs b/crates/handlers/src/admin/v1/user_sessions/finish.rs new file mode 100644 index 000000000..a50253f11 --- /dev/null +++ b/crates/handlers/src/admin/v1/user_sessions/finish.rs @@ -0,0 +1,216 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::{OperationIo, transform::TransformOperation}; +use axum::{Json, response::IntoResponse}; +use hyper::StatusCode; +use mas_axum_utils::record_error; +use ulid::Ulid; + +use crate::{ + admin::{ + call_context::CallContext, + model::{Resource, UserSession}, + params::UlidPathParam, + response::{ErrorResponse, SingleResponse}, + }, + impl_from_error_for_route, +}; + +#[derive(Debug, thiserror::Error, OperationIo)] +#[aide(output_with = "Json")] +pub enum RouteError { + #[error(transparent)] + Internal(Box), + + #[error("User session with ID {0} not found")] + NotFound(Ulid), + + #[error("User session with ID {0} is already finished")] + AlreadyFinished(Ulid), +} + +impl_from_error_for_route!(mas_storage::RepositoryError); + +impl IntoResponse for RouteError { + fn into_response(self) -> axum::response::Response { + let error = ErrorResponse::from_error(&self); + let sentry_event_id = record_error!(self, Self::Internal(_)); + let status = match self { + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound(_) => StatusCode::NOT_FOUND, + Self::AlreadyFinished(_) => StatusCode::BAD_REQUEST, + }; + (status, sentry_event_id, Json(error)).into_response() + } +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("finishUserSession") + .summary("Finish a user session") + .description( + "Calling this endpoint will finish the user session, preventing any further use.", + ) + .tag("user-session") + .response_with::<200, Json>, _>(|t| { + // Get the finished session sample + let [_, _, finished_session] = UserSession::samples(); + let id = finished_session.id(); + let response = SingleResponse::new( + finished_session, + format!("/api/admin/v1/user-sessions/{id}/finish"), + ); + t.description("User session was finished").example(response) + }) + .response_with::<400, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::AlreadyFinished(Ulid::nil())); + t.description("Session is already finished") + .example(response) + }) + .response_with::<404, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::NotFound(Ulid::nil())); + t.description("User session was not found") + .example(response) + }) +} + +#[tracing::instrument(name = "handler.admin.v1.user_sessions.finish", skip_all)] +pub async fn handler( + CallContext { + mut repo, clock, .. + }: CallContext, + id: UlidPathParam, +) -> Result>, RouteError> { + let id = *id; + let session = repo + .browser_session() + .lookup(id) + .await? + .ok_or(RouteError::NotFound(id))?; + + // Check if the session is already finished + if session.finished_at.is_some() { + return Err(RouteError::AlreadyFinished(id)); + } + + // Finish the session + let session = repo.browser_session().finish(&clock, session).await?; + + repo.save().await?; + + Ok(Json(SingleResponse::new( + UserSession::from(session), + format!("/api/admin/v1/user-sessions/{id}/finish"), + ))) +} + +#[cfg(test)] +mod tests { + use chrono::Duration; + use hyper::{Request, StatusCode}; + use mas_data_model::Clock as _; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + let mut rng = state.rng(); + + // Provision a user and a user session + let mut repo = state.repository().await.unwrap(); + let user = repo + .user() + .add(&mut rng, &state.clock, "alice".to_owned()) + .await + .unwrap(); + let session = repo + .browser_session() + .add(&mut rng, &state.clock, &user, None) + .await + .unwrap(); + repo.save().await.unwrap(); + + let request = Request::post(format!("/api/admin/v1/user-sessions/{}/finish", session.id)) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + + // The finished_at timestamp should be the same as the current time + assert_eq!( + body["data"]["attributes"]["finished_at"], + serde_json::json!(state.clock.now()) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_already_finished_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + let mut rng = state.rng(); + + // Provision a user and a user session + let mut repo = state.repository().await.unwrap(); + let user = repo + .user() + .add(&mut rng, &state.clock, "alice".to_owned()) + .await + .unwrap(); + let session = repo + .browser_session() + .add(&mut rng, &state.clock, &user, None) + .await + .unwrap(); + + // Finish the session first + let session = repo + .browser_session() + .finish(&state.clock, session) + .await + .unwrap(); + + repo.save().await.unwrap(); + + // Move the clock forward + state.clock.advance(Duration::try_minutes(1).unwrap()); + + let request = Request::post(format!("/api/admin/v1/user-sessions/{}/finish", session.id)) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::BAD_REQUEST); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + format!("User session with ID {} is already finished", session.id) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_unknown_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + let request = + Request::post("/api/admin/v1/user-sessions/01040G2081040G2081040G2081/finish") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::NOT_FOUND); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + "User session with ID 01040G2081040G2081040G2081 not found" + ); + } +} diff --git a/crates/handlers/src/admin/v1/user_sessions/mod.rs b/crates/handlers/src/admin/v1/user_sessions/mod.rs index 18ffe5af6..db7b17ff5 100644 --- a/crates/handlers/src/admin/v1/user_sessions/mod.rs +++ b/crates/handlers/src/admin/v1/user_sessions/mod.rs @@ -3,10 +3,12 @@ // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. +mod finish; mod get; mod list; pub use self::{ + finish::{doc as finish_doc, handler as finish}, get::{doc as get_doc, handler as get}, list::{doc as list_doc, handler as list}, }; diff --git a/docs/api/spec.json b/docs/api/spec.json index 98f8b2532..a58401b75 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -2399,6 +2399,94 @@ } } }, + "/api/admin/v1/user-sessions/{id}/finish": { + "post": { + "tags": [ + "user-session" + ], + "summary": "Finish a user session", + "description": "Calling this endpoint will finish the user session, preventing any further use.", + "operationId": "finishUserSession", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "The ID of the resource", + "$ref": "#/components/schemas/ULID" + }, + "style": "simple" + } + ], + "responses": { + "200": { + "description": "User session was finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SingleResponse_for_UserSession" + }, + "example": { + "data": { + "type": "user-session", + "id": "030C1G60R30C1G60R30C1G60R3", + "attributes": { + "created_at": "1970-01-01T00:00:00Z", + "finished_at": "1970-01-01T00:00:00Z", + "user_id": "040G2081040G2081040G208104", + "user_agent": "Mozilla/5.0", + "last_active_at": "1970-01-01T00:00:00Z", + "last_active_ip": "127.0.0.1" + }, + "links": { + "self": "/api/admin/v1/user-sessions/030C1G60R30C1G60R30C1G60R3" + } + }, + "links": { + "self": "/api/admin/v1/user-sessions/030C1G60R30C1G60R30C1G60R3/finish" + } + } + } + } + }, + "400": { + "description": "Session is already finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "User session with ID 00000000000000000000000000 is already finished" + } + ] + } + } + } + }, + "404": { + "description": "User session was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "User session with ID 00000000000000000000000000 not found" + } + ] + } + } + } + } + } + } + }, "/api/admin/v1/user-registration-tokens": { "get": { "tags": [ From f7e01450da63e4b7b1b8973b1fa4407d9581d332 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 16:37:02 +0200 Subject: [PATCH 116/296] Admin API to finish an OAuth2 session --- crates/handlers/src/admin/v1/mod.rs | 7 + .../src/admin/v1/oauth2_sessions/finish.rs | 234 ++++++++++++++++++ .../src/admin/v1/oauth2_sessions/mod.rs | 2 + docs/api/spec.json | 92 +++++++ 4 files changed, 335 insertions(+) create mode 100644 crates/handlers/src/admin/v1/oauth2_sessions/finish.rs diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index cb2be5a8d..c6cb466ac 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -60,6 +60,13 @@ where "/oauth2-sessions/{id}", get_with(self::oauth2_sessions::get, self::oauth2_sessions::get_doc), ) + .api_route( + "/oauth2-sessions/{id}/finish", + post_with( + self::oauth2_sessions::finish, + self::oauth2_sessions::finish_doc, + ), + ) .api_route( "/policy-data", post_with(self::policy_data::set, self::policy_data::set_doc), diff --git a/crates/handlers/src/admin/v1/oauth2_sessions/finish.rs b/crates/handlers/src/admin/v1/oauth2_sessions/finish.rs new file mode 100644 index 000000000..23edef30a --- /dev/null +++ b/crates/handlers/src/admin/v1/oauth2_sessions/finish.rs @@ -0,0 +1,234 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::{NoApi, OperationIo, transform::TransformOperation}; +use axum::{Json, response::IntoResponse}; +use hyper::StatusCode; +use mas_axum_utils::record_error; +use mas_data_model::BoxRng; +use mas_storage::queue::{QueueJobRepositoryExt as _, SyncDevicesJob}; +use ulid::Ulid; + +use crate::{ + admin::{ + call_context::CallContext, + model::{OAuth2Session, Resource}, + params::UlidPathParam, + response::{ErrorResponse, SingleResponse}, + }, + impl_from_error_for_route, +}; + +#[derive(Debug, thiserror::Error, OperationIo)] +#[aide(output_with = "Json")] +pub enum RouteError { + #[error(transparent)] + Internal(Box), + + #[error("OAuth 2.0 session with ID {0} not found")] + NotFound(Ulid), + + #[error("OAuth 2.0 session with ID {0} is already finished")] + AlreadyFinished(Ulid), +} + +impl_from_error_for_route!(mas_storage::RepositoryError); + +impl IntoResponse for RouteError { + fn into_response(self) -> axum::response::Response { + let error = ErrorResponse::from_error(&self); + let sentry_event_id = record_error!(self, Self::Internal(_)); + let status = match self { + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound(_) => StatusCode::NOT_FOUND, + Self::AlreadyFinished(_) => StatusCode::BAD_REQUEST, + }; + (status, sentry_event_id, Json(error)).into_response() + } +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("finishOAuth2Session") + .summary("Finish an OAuth 2.0 session") + .description( + "Calling this endpoint will finish the OAuth 2.0 session, preventing any further use. If the session has a user associated with it, a job will be scheduled to sync the user's devices with the homeserver.", + ) + .tag("oauth2-session") + .response_with::<200, Json>, _>(|t| { + // Get the finished session sample + let [_, _, finished_session] = OAuth2Session::samples(); + let id = finished_session.id(); + let response = SingleResponse::new( + finished_session, + format!("/api/admin/v1/oauth2-sessions/{id}/finish"), + ); + t.description("OAuth 2.0 session was finished").example(response) + }) + .response_with::<400, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::AlreadyFinished(Ulid::nil())); + t.description("Session is already finished") + .example(response) + }) + .response_with::<404, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::NotFound(Ulid::nil())); + t.description("OAuth 2.0 session was not found") + .example(response) + }) +} + +#[tracing::instrument(name = "handler.admin.v1.oauth2_sessions.finish", skip_all)] +pub async fn handler( + CallContext { + mut repo, clock, .. + }: CallContext, + NoApi(mut rng): NoApi, + id: UlidPathParam, +) -> Result>, RouteError> { + let id = *id; + let session = repo + .oauth2_session() + .lookup(id) + .await? + .ok_or(RouteError::NotFound(id))?; + + // Check if the session is already finished + if session.finished_at().is_some() { + return Err(RouteError::AlreadyFinished(id)); + } + + // If the session has a user associated with it, schedule a job to sync devices + if let Some(user_id) = session.user_id { + tracing::info!(user.id = %user_id, "Scheduling device sync job for user"); + let job = SyncDevicesJob::new_for_id(user_id); + repo.queue_job().schedule_job(&mut rng, &clock, job).await?; + } + + // Finish the session + let session = repo.oauth2_session().finish(&clock, session).await?; + + repo.save().await?; + + Ok(Json(SingleResponse::new( + OAuth2Session::from(session), + format!("/api/admin/v1/oauth2-sessions/{id}/finish"), + ))) +} + +#[cfg(test)] +mod tests { + use chrono::Duration; + use hyper::{Request, StatusCode}; + use mas_data_model::{AccessToken, Clock as _}; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + // Get the session ID from the token we just created + let mut repo = state.repository().await.unwrap(); + let AccessToken { session_id, .. } = repo + .oauth2_access_token() + .find_by_token(&token) + .await + .unwrap() + .unwrap(); + repo.save().await.unwrap(); + + let request = Request::post(format!("/api/admin/v1/oauth2-sessions/{session_id}/finish")) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + + // The finished_at timestamp should be the same as the current time + assert_eq!( + body["data"]["attributes"]["finished_at"], + serde_json::json!(state.clock.now()) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_already_finished_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + + // Create first admin token for the API call + let admin_token = state.token_with_scope("urn:mas:admin").await; + + // Create a second admin session that we'll finish + let second_admin_token = state.token_with_scope("urn:mas:admin").await; + + // Get the second session and finish it first + let mut repo = state.repository().await.unwrap(); + let AccessToken { session_id, .. } = repo + .oauth2_access_token() + .find_by_token(&second_admin_token) + .await + .unwrap() + .unwrap(); + + let session = repo + .oauth2_session() + .lookup(session_id) + .await + .unwrap() + .unwrap(); + + // Finish the session first + let session = repo + .oauth2_session() + .finish(&state.clock, session) + .await + .unwrap(); + + repo.save().await.unwrap(); + + // Move the clock forward + state.clock.advance(Duration::try_minutes(1).unwrap()); + + let request = Request::post(format!( + "/api/admin/v1/oauth2-sessions/{}/finish", + session.id + )) + .bearer(&admin_token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::BAD_REQUEST); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + format!( + "OAuth 2.0 session with ID {} is already finished", + session.id + ) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_unknown_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + let request = + Request::post("/api/admin/v1/oauth2-sessions/01040G2081040G2081040G2081/finish") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::NOT_FOUND); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + "OAuth 2.0 session with ID 01040G2081040G2081040G2081 not found" + ); + } +} diff --git a/crates/handlers/src/admin/v1/oauth2_sessions/mod.rs b/crates/handlers/src/admin/v1/oauth2_sessions/mod.rs index 9b6272cef..5ac2e049e 100644 --- a/crates/handlers/src/admin/v1/oauth2_sessions/mod.rs +++ b/crates/handlers/src/admin/v1/oauth2_sessions/mod.rs @@ -4,10 +4,12 @@ // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. +mod finish; mod get; mod list; pub use self::{ + finish::{doc as finish_doc, handler as finish}, get::{doc as get_doc, handler as get}, list::{doc as list_doc, handler as list}, }; diff --git a/docs/api/spec.json b/docs/api/spec.json index a58401b75..02a07a408 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -687,6 +687,98 @@ } } }, + "/api/admin/v1/oauth2-sessions/{id}/finish": { + "post": { + "tags": [ + "oauth2-session" + ], + "summary": "Finish an OAuth 2.0 session", + "description": "Calling this endpoint will finish the OAuth 2.0 session, preventing any further use. If the session has a user associated with it, a job will be scheduled to sync the user's devices with the homeserver.", + "operationId": "finishOAuth2Session", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "The ID of the resource", + "$ref": "#/components/schemas/ULID" + }, + "style": "simple" + } + ], + "responses": { + "200": { + "description": "OAuth 2.0 session was finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SingleResponse_for_OAuth2Session" + }, + "example": { + "data": { + "type": "oauth2-session", + "id": "030C1G60R30C1G60R30C1G60R3", + "attributes": { + "created_at": "1970-01-01T00:00:00Z", + "finished_at": "1970-01-01T00:00:00Z", + "user_id": "040G2081040G2081040G208104", + "user_session_id": "050M2GA1850M2GA1850M2GA185", + "client_id": "060R30C1G60R30C1G60R30C1G6", + "scope": "urn:matrix:client:api:*", + "user_agent": "Mozilla/5.0", + "last_active_at": "1970-01-01T00:00:00Z", + "last_active_ip": "127.0.0.1", + "human_name": null + }, + "links": { + "self": "/api/admin/v1/oauth2-sessions/030C1G60R30C1G60R30C1G60R3" + } + }, + "links": { + "self": "/api/admin/v1/oauth2-sessions/030C1G60R30C1G60R30C1G60R3/finish" + } + } + } + } + }, + "400": { + "description": "Session is already finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "OAuth 2.0 session with ID 00000000000000000000000000 is already finished" + } + ] + } + } + } + }, + "404": { + "description": "OAuth 2.0 session was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "OAuth 2.0 session with ID 00000000000000000000000000 not found" + } + ] + } + } + } + } + } + } + }, "/api/admin/v1/policy-data": { "post": { "tags": [ From 4423ee130f6f725f2642f76ab6acc0c7d624cb99 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 30 Sep 2025 16:44:17 +0200 Subject: [PATCH 117/296] Admin API to finish a compatibility session --- .../src/admin/v1/compat_sessions/finish.rs | 246 ++++++++++++++++++ .../src/admin/v1/compat_sessions/mod.rs | 2 + crates/handlers/src/admin/v1/mod.rs | 7 + docs/api/spec.json | 92 +++++++ 4 files changed, 347 insertions(+) create mode 100644 crates/handlers/src/admin/v1/compat_sessions/finish.rs diff --git a/crates/handlers/src/admin/v1/compat_sessions/finish.rs b/crates/handlers/src/admin/v1/compat_sessions/finish.rs new file mode 100644 index 000000000..c0299d960 --- /dev/null +++ b/crates/handlers/src/admin/v1/compat_sessions/finish.rs @@ -0,0 +1,246 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::{NoApi, OperationIo, transform::TransformOperation}; +use axum::{Json, response::IntoResponse}; +use hyper::StatusCode; +use mas_axum_utils::record_error; +use mas_data_model::BoxRng; +use mas_storage::queue::{QueueJobRepositoryExt as _, SyncDevicesJob}; +use ulid::Ulid; + +use crate::{ + admin::{ + call_context::CallContext, + model::{CompatSession, Resource}, + params::UlidPathParam, + response::{ErrorResponse, SingleResponse}, + }, + impl_from_error_for_route, +}; + +#[derive(Debug, thiserror::Error, OperationIo)] +#[aide(output_with = "Json")] +pub enum RouteError { + #[error(transparent)] + Internal(Box), + + #[error("Compatibility session with ID {0} not found")] + NotFound(Ulid), + + #[error("Compatibility session with ID {0} is already finished")] + AlreadyFinished(Ulid), +} + +impl_from_error_for_route!(mas_storage::RepositoryError); + +impl IntoResponse for RouteError { + fn into_response(self) -> axum::response::Response { + let error = ErrorResponse::from_error(&self); + let sentry_event_id = record_error!(self, Self::Internal(_)); + let status = match self { + Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::NotFound(_) => StatusCode::NOT_FOUND, + Self::AlreadyFinished(_) => StatusCode::BAD_REQUEST, + }; + (status, sentry_event_id, Json(error)).into_response() + } +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("finishCompatSession") + .summary("Finish a compatibility session") + .description( + "Calling this endpoint will finish the compatibility session, preventing any further use. A job will be scheduled to sync the user's devices with the homeserver.", + ) + .tag("compat-session") + .response_with::<200, Json>, _>(|t| { + // Get the finished session sample + let [_, finished_session, _] = CompatSession::samples(); + let id = finished_session.id(); + let response = SingleResponse::new( + finished_session, + format!("/api/admin/v1/compat-sessions/{id}/finish"), + ); + t.description("Compatibility session was finished").example(response) + }) + .response_with::<400, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::AlreadyFinished(Ulid::nil())); + t.description("Session is already finished") + .example(response) + }) + .response_with::<404, RouteError, _>(|t| { + let response = ErrorResponse::from_error(&RouteError::NotFound(Ulid::nil())); + t.description("Compatibility session was not found") + .example(response) + }) +} + +#[tracing::instrument(name = "handler.admin.v1.compat_sessions.finish", skip_all)] +pub async fn handler( + CallContext { + mut repo, clock, .. + }: CallContext, + NoApi(mut rng): NoApi, + id: UlidPathParam, +) -> Result>, RouteError> { + let id = *id; + let session = repo + .compat_session() + .lookup(id) + .await? + .ok_or(RouteError::NotFound(id))?; + + // Check if the session is already finished + if session.finished_at().is_some() { + return Err(RouteError::AlreadyFinished(id)); + } + + // Load the user to schedule a device sync job + let user = repo + .user() + .lookup(session.user_id) + .await? + .ok_or_else(|| RouteError::Internal("User not found for session".into()))?; + + // Schedule a job to sync the devices of the user with the homeserver + tracing::info!(user.id = %user.id, "Scheduling device sync job for user"); + repo.queue_job() + .schedule_job(&mut rng, &clock, SyncDevicesJob::new(&user)) + .await?; + + // Finish the session + let session = repo.compat_session().finish(&clock, session).await?; + + // Get the SSO login info for the response + let sso_login = repo.compat_sso_login().find_for_session(&session).await?; + + repo.save().await?; + + Ok(Json(SingleResponse::new( + CompatSession::from((session, sso_login)), + format!("/api/admin/v1/compat-sessions/{id}/finish"), + ))) +} + +#[cfg(test)] +mod tests { + use chrono::Duration; + use hyper::{Request, StatusCode}; + use mas_data_model::{Clock as _, Device}; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + let mut rng = state.rng(); + + // Provision a user and a compat session + let mut repo = state.repository().await.unwrap(); + let user = repo + .user() + .add(&mut rng, &state.clock, "alice".to_owned()) + .await + .unwrap(); + let device = Device::generate(&mut rng); + let session = repo + .compat_session() + .add(&mut rng, &state.clock, &user, device, None, false, None) + .await + .unwrap(); + repo.save().await.unwrap(); + + let request = Request::post(format!( + "/api/admin/v1/compat-sessions/{}/finish", + session.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::OK); + let body: serde_json::Value = response.json(); + + // The finished_at timestamp should be the same as the current time + assert_eq!( + body["data"]["attributes"]["finished_at"], + serde_json::json!(state.clock.now()) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_already_finished_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + let mut rng = state.rng(); + + // Provision a user and a compat session + let mut repo = state.repository().await.unwrap(); + let user = repo + .user() + .add(&mut rng, &state.clock, "alice".to_owned()) + .await + .unwrap(); + let device = Device::generate(&mut rng); + let session = repo + .compat_session() + .add(&mut rng, &state.clock, &user, device, None, false, None) + .await + .unwrap(); + + // Finish the session first + let session = repo + .compat_session() + .finish(&state.clock, session) + .await + .unwrap(); + + repo.save().await.unwrap(); + + // Move the clock forward + state.clock.advance(Duration::try_minutes(1).unwrap()); + + let request = Request::post(format!( + "/api/admin/v1/compat-sessions/{}/finish", + session.id + )) + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::BAD_REQUEST); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + format!( + "Compatibility session with ID {} is already finished", + session.id + ) + ); + } + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_finish_unknown_session(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + let request = + Request::post("/api/admin/v1/compat-sessions/01040G2081040G2081040G2081/finish") + .bearer(&token) + .empty(); + let response = state.request(request).await; + response.assert_status(StatusCode::NOT_FOUND); + let body: serde_json::Value = response.json(); + assert_eq!( + body["errors"][0]["title"], + "Compatibility session with ID 01040G2081040G2081040G2081 not found" + ); + } +} diff --git a/crates/handlers/src/admin/v1/compat_sessions/mod.rs b/crates/handlers/src/admin/v1/compat_sessions/mod.rs index 18ffe5af6..db7b17ff5 100644 --- a/crates/handlers/src/admin/v1/compat_sessions/mod.rs +++ b/crates/handlers/src/admin/v1/compat_sessions/mod.rs @@ -3,10 +3,12 @@ // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. +mod finish; mod get; mod list; pub use self::{ + finish::{doc as finish_doc, handler as finish}, get::{doc as get_doc, handler as get}, list::{doc as list_doc, handler as list}, }; diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index c6cb466ac..7146328be 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -52,6 +52,13 @@ where "/compat-sessions/{id}", get_with(self::compat_sessions::get, self::compat_sessions::get_doc), ) + .api_route( + "/compat-sessions/{id}/finish", + post_with( + self::compat_sessions::finish, + self::compat_sessions::finish_doc, + ), + ) .api_route( "/oauth2-sessions", get_with(self::oauth2_sessions::list, self::oauth2_sessions::list_doc), diff --git a/docs/api/spec.json b/docs/api/spec.json index 02a07a408..8e003268a 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -342,6 +342,98 @@ } } }, + "/api/admin/v1/compat-sessions/{id}/finish": { + "post": { + "tags": [ + "compat-session" + ], + "summary": "Finish a compatibility session", + "description": "Calling this endpoint will finish the compatibility session, preventing any further use. A job will be scheduled to sync the user's devices with the homeserver.", + "operationId": "finishCompatSession", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "title": "The ID of the resource", + "$ref": "#/components/schemas/ULID" + }, + "style": "simple" + } + ], + "responses": { + "200": { + "description": "Compatibility session was finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SingleResponse_for_CompatSession" + }, + "example": { + "data": { + "type": "compat-session", + "id": "02081040G2081040G2081040G2", + "attributes": { + "user_id": "01040G2081040G2081040G2081", + "device_id": "FFGGHHIIJJ", + "user_session_id": "0J289144GJ289144GJ289144GJ", + "redirect_uri": null, + "created_at": "1970-01-01T00:00:00Z", + "user_agent": "Mozilla/5.0", + "last_active_at": "1970-01-01T00:00:00Z", + "last_active_ip": "1.2.3.4", + "finished_at": "1970-01-01T00:00:00Z", + "human_name": null + }, + "links": { + "self": "/api/admin/v1/compat-sessions/02081040G2081040G2081040G2" + } + }, + "links": { + "self": "/api/admin/v1/compat-sessions/02081040G2081040G2081040G2/finish" + } + } + } + } + }, + "400": { + "description": "Session is already finished", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "Compatibility session with ID 00000000000000000000000000 is already finished" + } + ] + } + } + } + }, + "404": { + "description": "Compatibility session was not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "example": { + "errors": [ + { + "title": "Compatibility session with ID 00000000000000000000000000 not found" + } + ] + } + } + } + } + } + } + }, "/api/admin/v1/oauth2-sessions": { "get": { "tags": [ From 3f10426949b1a2c0027ff0bd31d1a74e3ca1b67d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 13:19:50 +0000 Subject: [PATCH 118/296] build(deps): bump psl from 2.1.146 to 2.1.147 Bumps [psl](https://github.com/addr-rs/psl) from 2.1.146 to 2.1.147. - [Release notes](https://github.com/addr-rs/psl/releases) - [Commits](https://github.com/addr-rs/psl/compare/v2.1.146...v2.1.147) --- updated-dependencies: - dependency-name: psl dependency-version: 2.1.147 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253308775..cedd0b4d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4088,7 +4088,7 @@ dependencies = [ "sha1", "sha2", "sprintf", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", "urlencoding", @@ -4677,9 +4677,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.146" +version = "2.1.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3e8d3ee29451fe165c689769401440c0d028cf015123f4a8b6c9ca9bbf2b82" +checksum = "1b0efc2f09945ea5ef176dc4f1cb703b0efa41b112d5eb27489afc880db860a7" dependencies = [ "psl-types", ] diff --git a/Cargo.toml b/Cargo.toml index 8d525c706..0a969bf41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -476,7 +476,7 @@ features = ["std", "pkcs5", "encryption"] # Public Suffix List [workspace.dependencies.psl] -version = "2.1.146" +version = "2.1.147" # High-precision clock [workspace.dependencies.quanta] From 671dae3345e73768fa83e234750535abe8dcbabe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:14:53 +0000 Subject: [PATCH 119/296] build(deps-dev): bump @testing-library/jest-dom in /frontend Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 6.8.0 to 6.9.1. - [Release notes](https://github.com/testing-library/jest-dom/releases) - [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md) - [Commits](https://github.com/testing-library/jest-dom/compare/v6.8.0...v6.9.1) --- updated-dependencies: - dependency-name: "@testing-library/jest-dom" dependency-version: 6.9.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0cdfed463..847bd5105 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -41,7 +41,7 @@ "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", - "@testing-library/jest-dom": "^6.8.0", + "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^24.6.0", @@ -5663,9 +5663,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", - "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 41f6ae5ce..6036bd4f3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -51,7 +51,7 @@ "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", - "@testing-library/jest-dom": "^6.8.0", + "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^24.6.0", From 0f5dcc3c39b8131a371a616d3a3d26e450d67b6c Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 3 Oct 2025 11:41:02 +0200 Subject: [PATCH 120/296] Inject the version in the app state --- crates/cli/src/app_state.rs | 10 ++++++++-- crates/data-model/src/lib.rs | 2 ++ crates/data-model/src/version.rs | 8 ++++++++ crates/handlers/src/admin/mod.rs | 3 ++- crates/handlers/src/bin/api-schema.rs | 1 + crates/handlers/src/test_utils.rs | 8 +++++++- 6 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 crates/data-model/src/version.rs diff --git a/crates/cli/src/app_state.rs b/crates/cli/src/app_state.rs index f9f761338..f211fc29c 100644 --- a/crates/cli/src/app_state.rs +++ b/crates/cli/src/app_state.rs @@ -9,7 +9,7 @@ use std::{convert::Infallible, net::IpAddr, sync::Arc}; use axum::extract::{FromRef, FromRequestParts}; use ipnetwork::IpNetwork; use mas_context::LogContext; -use mas_data_model::{BoxClock, BoxRng, SiteConfig, SystemClock}; +use mas_data_model::{AppVersion, BoxClock, BoxRng, SiteConfig, SystemClock}; use mas_handlers::{ ActivityTracker, BoundActivityTracker, CookieManager, ErrorWrapper, GraphQLSchema, Limiter, MetadataCache, RequesterFingerprint, passwords::PasswordManager, @@ -27,7 +27,7 @@ use rand::SeedableRng; use sqlx::PgPool; use tracing::Instrument; -use crate::telemetry::METER; +use crate::{VERSION, telemetry::METER}; #[derive(Clone)] pub struct AppState { @@ -214,6 +214,12 @@ impl FromRef for Arc { } } +impl FromRef for AppVersion { + fn from_ref(_input: &AppState) -> Self { + AppVersion(VERSION) + } +} + impl FromRequestParts for BoxClock { type Rejection = Infallible; diff --git a/crates/data-model/src/lib.rs b/crates/data-model/src/lib.rs index 6be06b4d9..337c05d89 100644 --- a/crates/data-model/src/lib.rs +++ b/crates/data-model/src/lib.rs @@ -18,6 +18,7 @@ pub(crate) mod upstream_oauth2; pub(crate) mod user_agent; pub(crate) mod users; mod utils; +mod version; /// Error when an invalid state transition is attempted. #[derive(Debug, Error)] @@ -57,4 +58,5 @@ pub use self::{ UserRecoveryTicket, UserRegistration, UserRegistrationPassword, UserRegistrationToken, }, utils::{BoxClock, BoxRng}, + version::AppVersion, }; diff --git a/crates/data-model/src/version.rs b/crates/data-model/src/version.rs new file mode 100644 index 000000000..86d890fc1 --- /dev/null +++ b/crates/data-model/src/version.rs @@ -0,0 +1,8 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +/// A structure which holds information about the running version of the app +#[derive(Debug, Clone, Copy)] +pub struct AppVersion(pub &'static str); diff --git a/crates/handlers/src/admin/mod.rs b/crates/handlers/src/admin/mod.rs index e5e158be3..194f839f3 100644 --- a/crates/handlers/src/admin/mod.rs +++ b/crates/handlers/src/admin/mod.rs @@ -20,7 +20,7 @@ use axum::{ use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE}; use indexmap::IndexMap; use mas_axum_utils::InternalError; -use mas_data_model::{BoxRng, SiteConfig}; +use mas_data_model::{AppVersion, BoxRng, SiteConfig}; use mas_http::CorsLayerExt; use mas_matrix::HomeserverConnection; use mas_policy::PolicyFactory; @@ -164,6 +164,7 @@ where UrlBuilder: FromRef, Arc: FromRef, SiteConfig: FromRef, + AppVersion: FromRef, { // We *always* want to explicitly set the possible responses, beacuse the // infered ones are not necessarily correct diff --git a/crates/handlers/src/bin/api-schema.rs b/crates/handlers/src/bin/api-schema.rs index 6eed219da..1b73c05c3 100644 --- a/crates/handlers/src/bin/api-schema.rs +++ b/crates/handlers/src/bin/api-schema.rs @@ -60,6 +60,7 @@ impl_from_ref!(mas_keystore::Keystore); impl_from_ref!(mas_handlers::passwords::PasswordManager); impl_from_ref!(Arc); impl_from_ref!(mas_data_model::SiteConfig); +impl_from_ref!(mas_data_model::AppVersion); fn main() -> Result<(), Box> { let (mut api, _) = mas_handlers::admin_api_router::(); diff --git a/crates/handlers/src/test_utils.rs b/crates/handlers/src/test_utils.rs index e43194776..a25fda9dc 100644 --- a/crates/handlers/src/test_utils.rs +++ b/crates/handlers/src/test_utils.rs @@ -28,7 +28,7 @@ use mas_axum_utils::{ cookies::{CookieJar, CookieManager}, }; use mas_config::RateLimitingConfig; -use mas_data_model::{BoxClock, BoxRng, SiteConfig, clock::MockClock}; +use mas_data_model::{AppVersion, BoxClock, BoxRng, SiteConfig, clock::MockClock}; use mas_email::{MailTransport, Mailer}; use mas_i18n::Translator; use mas_keystore::{Encrypter, JsonWebKey, JsonWebKeySet, Keystore, PrivateKey}; @@ -575,6 +575,12 @@ impl FromRef for reqwest::Client { } } +impl FromRef for AppVersion { + fn from_ref(_input: &TestState) -> Self { + AppVersion("v0.0.0-test") + } +} + impl FromRequestParts for ActivityTracker { type Rejection = Infallible; From ce1aabdb8af15d71ed8074e98927abb4b268cf47 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Fri, 3 Oct 2025 11:58:53 +0200 Subject: [PATCH 121/296] Admin API to get the version of the service --- crates/handlers/src/admin/v1/mod.rs | 8 +++- crates/handlers/src/admin/v1/version.rs | 62 +++++++++++++++++++++++++ docs/api/spec.json | 36 ++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 crates/handlers/src/admin/v1/version.rs diff --git a/crates/handlers/src/admin/v1/mod.rs b/crates/handlers/src/admin/v1/mod.rs index c0b5d8ddb..dc09c90b4 100644 --- a/crates/handlers/src/admin/v1/mod.rs +++ b/crates/handlers/src/admin/v1/mod.rs @@ -11,7 +11,7 @@ use aide::axum::{ routing::{get_with, post_with}, }; use axum::extract::{FromRef, FromRequestParts}; -use mas_data_model::{BoxRng, SiteConfig}; +use mas_data_model::{AppVersion, BoxRng, SiteConfig}; use mas_matrix::HomeserverConnection; use mas_policy::PolicyFactory; @@ -28,6 +28,7 @@ mod user_emails; mod user_registration_tokens; mod user_sessions; mod users; +mod version; pub fn router() -> ApiRouter where @@ -35,6 +36,7 @@ where Arc: FromRef, PasswordManager: FromRef, SiteConfig: FromRef, + AppVersion: FromRef, Arc: FromRef, BoxRng: FromRequestParts, CallContext: FromRequestParts, @@ -44,6 +46,10 @@ where "/site-config", get_with(self::site_config::handler, self::site_config::doc), ) + .api_route( + "/version", + get_with(self::version::handler, self::version::doc), + ) .api_route( "/compat-sessions", get_with(self::compat_sessions::list, self::compat_sessions::list_doc), diff --git a/crates/handlers/src/admin/v1/version.rs b/crates/handlers/src/admin/v1/version.rs new file mode 100644 index 000000000..2fe53940b --- /dev/null +++ b/crates/handlers/src/admin/v1/version.rs @@ -0,0 +1,62 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use aide::transform::TransformOperation; +use axum::{Json, extract::State}; +use mas_data_model::AppVersion; +use schemars::JsonSchema; +use serde::Serialize; + +use crate::admin::call_context::CallContext; + +#[derive(Serialize, JsonSchema)] +pub struct Version { + /// The semver version of the app + pub version: &'static str, +} + +pub fn doc(operation: TransformOperation) -> TransformOperation { + operation + .id("version") + .tag("server") + .summary("Get the version currently running") + .response_with::<200, Json, _>(|t| t.example(Version { version: "v1.0.0" })) +} + +#[tracing::instrument(name = "handler.admin.v1.version", skip_all)] +pub async fn handler( + _: CallContext, + State(AppVersion(version)): State, +) -> Json { + Json(Version { version }) +} + +#[cfg(test)] +mod tests { + use hyper::{Request, StatusCode}; + use insta::assert_json_snapshot; + use sqlx::PgPool; + + use crate::test_utils::{RequestBuilderExt, ResponseExt, TestState, setup}; + + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_add_user(pool: PgPool) { + setup(); + let mut state = TestState::from_pool(pool).await.unwrap(); + let token = state.token_with_scope("urn:mas:admin").await; + + let request = Request::get("/api/admin/v1/version").bearer(&token).empty(); + + let response = state.request(request).await; + + assert_eq!(response.status(), StatusCode::OK); + let body: serde_json::Value = response.json(); + assert_json_snapshot!(body, @r#" + { + "version": "v0.0.0-test" + } + "#); + } +} diff --git a/docs/api/spec.json b/docs/api/spec.json index 98f8b2532..74e42f734 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -50,6 +50,30 @@ } } }, + "/api/admin/v1/version": { + "get": { + "tags": [ + "server" + ], + "summary": "Get the version currently running", + "operationId": "version", + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Version" + }, + "example": { + "version": "v1.0.0" + } + } + } + } + } + } + }, "/api/admin/v1/compat-sessions": { "get": { "tags": [ @@ -3710,6 +3734,18 @@ } } }, + "Version": { + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "description": "The semver version of the app", + "type": "string" + } + } + }, "PaginationParams": { "type": "object", "properties": { From 0502b75ecf1ca413dcdfcea4722bb30441a8768c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Oct 2025 13:16:19 +0000 Subject: [PATCH 122/296] build(deps): bump pest from 2.8.2 to 2.8.3 Bumps [pest](https://github.com/pest-parser/pest) from 2.8.2 to 2.8.3. - [Release notes](https://github.com/pest-parser/pest/releases) - [Commits](https://github.com/pest-parser/pest/compare/v2.8.2...v2.8.3) --- updated-dependencies: - dependency-name: pest dependency-version: 2.8.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 7 +++---- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253308775..28542b282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4088,7 +4088,7 @@ dependencies = [ "sha1", "sha2", "sprintf", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", "urlencoding", @@ -4372,12 +4372,11 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.17", "ucd-trie", ] diff --git a/Cargo.toml b/Cargo.toml index 8d525c706..e7f47b277 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -454,7 +454,7 @@ features = ["std"] # Parser generator [workspace.dependencies.pest] -version = "2.8.2" +version = "2.8.3" # Pest derive macros [workspace.dependencies.pest_derive] From 4920bab2545a00283f22d7d7f3f3f78f3a781712 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Fri, 26 Sep 2025 12:47:34 +0100 Subject: [PATCH 123/296] Add tables for personal access tokens --- .../20250924132713_personal_access_tokens.sql | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql diff --git a/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql b/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql new file mode 100644 index 000000000..62df7bc3e --- /dev/null +++ b/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql @@ -0,0 +1,55 @@ +-- Copyright 2025 New Vector Ltd. +-- +-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +-- Please see LICENSE in the repository root for full details. + +-- A family of personal access tokens. This is a long-lived wrapper around the personal access tokens +-- themselves, allowing tokens to be regenerated whilst still retaining a persistent identifier for them. +CREATE TABLE personal_sessions ( + personal_session_id UUID NOT NULL PRIMARY KEY, + owner_user_id UUID NOT NULL REFERENCES users(user_id), + actor_user_id UUID NOT NULL REFERENCES users(user_id), + -- A human-readable label, intended to describe what the session is for. + human_name TEXT NOT NULL, + -- The OAuth2 scopes for the session, identical to OAuth2 sessions. + -- May include a device ID, but this is optional (sessions can be deviceless). + scope_list TEXT[] NOT NULL, + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + -- If set, none of the tokens will be valid anymore. + revoked_at TIMESTAMP WITH TIME ZONE, + last_active_at TIMESTAMP WITH TIME ZONE, + last_active_ip INET +); + +-- Individual tokens. +CREATE TABLE personal_access_tokens ( + -- The family this access token belongs to. + personal_access_token_id UUID NOT NULL PRIMARY KEY, + personal_session_id UUID NOT NULL REFERENCES personal_sessions(personal_session_id), + -- SHA256 of the access token. + -- This is a lightweight measure to stop a database backup (or other + -- unauthorised read-only database access) escalating into real permissions + -- on a live system. + -- We could have used a hash with secret key, but this would no longer be + -- 'free' protection because it would need configuration (and introduce + -- potential issues with configuring it wrong). + -- This is currently inconsistent with other access token tables but it would + -- make sense to migrate those to match in the future. + access_token_sha256 BYTEA NOT NULL UNIQUE + -- A SHA256 hash is 32 bytes long + CHECK (octet_length(access_token_sha256) = 32), + created_at TIMESTAMP WITH TIME ZONE NOT NULL, + -- If set, the token won't be valid after this time. + -- If not set, the token never automatically expires. + expires_at TIMESTAMP WITH TIME ZONE, + -- If set, this token is not valid anymore. + revoked_at TIMESTAMP WITH TIME ZONE +); + +-- Ensure we can only have one active personal access token in each family. +CREATE UNIQUE INDEX ON personal_access_tokens (personal_session_id) WHERE revoked_at IS NOT NULL; + +-- Add indices to satisfy foreign key backward checks +-- (and likely filter queries) +CREATE INDEX ON personal_sessions (owner_user_id); +CREATE INDEX ON personal_sessions (actor_user_id); From 0d05b40e6414c3cab02ec2823e54ea7c72fdc22b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:01:54 +0000 Subject: [PATCH 124/296] Translations updates --- frontend/.storybook/locales.ts | 62 ++++++------ frontend/locales/de.json | 166 ++++++++++++++++----------------- translations/de.json | 124 ++++++++++++------------ translations/zh-Hans.json | 1 + 4 files changed, 177 insertions(+), 176 deletions(-) diff --git a/frontend/.storybook/locales.ts b/frontend/.storybook/locales.ts index c2acf82ed..090812bf0 100644 --- a/frontend/.storybook/locales.ts +++ b/frontend/.storybook/locales.ts @@ -27,7 +27,7 @@ export type LocalazyMetadata = { }; const localazyMetadata: LocalazyMetadata = { - projectUrl: "https://localazy.com/p/matrix-authentication-service!v1.3", + projectUrl: "https://localazy.com/p/matrix-authentication-service", baseLocale: "en", languages: [ { @@ -172,21 +172,21 @@ const localazyMetadata: LocalazyMetadata = { file: "frontend.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", - "da": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", - "de": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", - "en": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", - "et": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", - "fi": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", - "fr": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", - "hu": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", - "nb_NO": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", - "nl": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", - "pt": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", - "ru": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", - "sv": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", - "uk": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", - "zh#Hans": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" + "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/cs/frontend.json", + "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/da/frontend.json", + "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/de/frontend.json", + "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/en/frontend.json", + "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/et/frontend.json", + "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fi/frontend.json", + "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/fr/frontend.json", + "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/hu/frontend.json", + "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nb-NO/frontend.json", + "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/nl/frontend.json", + "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/pt/frontend.json", + "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/ru/frontend.json", + "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/sv/frontend.json", + "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/uk/frontend.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/7c203a8ac8bd48c3c4609a8effcd0fbac430f9b2/zh-Hans/frontend.json" } }, { @@ -194,21 +194,21 @@ const localazyMetadata: LocalazyMetadata = { file: "file.json", path: "", cdnFiles: { - "cs": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", - "da": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", - "de": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", - "en": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", - "et": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", - "fi": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", - "fr": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", - "hu": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", - "nb_NO": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", - "nl": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", - "pt": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", - "ru": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", - "sv": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", - "uk": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", - "zh#Hans": "https://delivery.localazy.com/_a6804865183625420345536edd7e/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" + "cs": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/cs/file.json", + "da": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/da/file.json", + "de": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/de/file.json", + "en": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/en/file.json", + "et": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/et/file.json", + "fi": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fi/file.json", + "fr": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/fr/file.json", + "hu": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/hu/file.json", + "nb_NO": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nb-NO/file.json", + "nl": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/nl/file.json", + "pt": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/pt/file.json", + "ru": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/ru/file.json", + "sv": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/sv/file.json", + "uk": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/uk/file.json", + "zh#Hans": "https://delivery.localazy.com/_a7686032324574572744739e0707/_e0/5b69b0350dccfd47c245a5d41c1b9fdf6912cc6e/zh-Hans/file.json" } } ] diff --git a/frontend/locales/de.json b/frontend/locales/de.json index b5bcfe437..e1e6b7dc8 100644 --- a/frontend/locales/de.json +++ b/frontend/locales/de.json @@ -5,7 +5,7 @@ "clear": "Löschen", "close": "Schließen", "collapse": "Zusammenbruch", - "confirm": " Bestätigen Sie", + "confirm": "Bestätigen", "continue": "Weiter", "edit": "Bearbeiten", "expand": "Erweitern", @@ -40,16 +40,16 @@ "account_password": "Kontokennwort", "contact_info": "Kontaktinformation", "delete_account": { - "alert_description": "Dieses Konto wird dauerhaft gelöscht und Sie haben keinen Zugriff mehr auf Ihre Nachrichten.", - "alert_title": "Sie sind dabei, alle Ihre Daten zu verlieren", + "alert_description": "Dieses Konto wird dauerhaft entfernt und du hast keinen Zugriff mehr auf deine Nachrichten.", + "alert_title": "Du bist kurz davor, alle deine Daten zu verlieren.", "button": "Account löschen", - "dialog_description": "Bestätigen Sie, dass Sie Ihr Konto löschen möchten:\n\nSie können Ihr Konto nicht reaktivieren\nSie können sich nicht mehr anmelden\nNiemand kann Ihren Benutzernamen (MXID) wieder verwenden, auch Sie nicht.\nSie verlassen alle Räume und Direktnachrichten, in denen Sie sich befinden\nSie werden vom Identitätsserver entfernt und niemand kann Sie mit Ihrer E-Mail-Adresse oder Telefonnummer finden\n\nIhre alten Nachrichten sind für Empfänger weiterhin sichtbar. Möchten Sie Ihre gesendeten Nachrichten vor zukünftigen Chatroom-Besuchern verbergen?", + "dialog_description": "Bestätige, dass du dein Konto löschen möchtest:\n\nDu kannst dein Konto nicht reaktivieren\nDu kannst dich nicht mehr anmelden\nNiemand kann deinen Benutzernamen (MXID) wieder verwenden, auch du nicht.\nDu verlässt alle Gruppen und Chats\nDu wirst vom Identitätsserver entfernt und niemand kann dich mit deiner E-Mail-Adresse oder Telefonnummer finden\n\nDeine alten Nachrichten sind für Empfänger weiterhin sichtbar. Möchtest du deine gesendeten Nachrichten vor zukünftigen Gruppen-Besuchern verbergen?", "dialog_title": "Dieses Konto löschen?", "erase_checkbox_label": "Ja, alle meine Nachrichten vor neuen Mitgliedern verbergen", - "incorrect_password": "Falsches Passwort, bitte versuchen Sie es erneut", - "mxid_label": "Bestätigen Sie Ihre Matrix-ID ({{ mxid }})", - "mxid_mismatch": "Dieser Wert stimmt nicht mit Ihrer Matrix-ID überein", - "password_label": "Geben Sie Ihr Passwort ein, um fortzufahren" + "incorrect_password": "Falsches Passwort, versuch's nochmal", + "mxid_label": "Bestätige deine Matrix-ID ({{ mxid }})", + "mxid_mismatch": "Dieser Wert passt nicht zu deiner Matrix-ID.", + "password_label": "Gib dein Passwort ein, um weiterzumachen" }, "edit_profile": { "display_name_help": "Dies ist der öffentliche Nutzername.", @@ -79,7 +79,7 @@ "title": "Diese E-Mailadresse existiert bereits" }, "email_exists_error": "Die eingegebene E-Mail-Adresse ist diesem Konto bereits zugeordnet", - "email_field_help": "Fügen Sie eine alternative E-Mail-Adresse hinzu, mit der Sie auf dieses Konto zugreifen können.", + "email_field_help": "Gib eine alternative E-Mail-Adresse an, mit der du auf dieses Konto zugreifen kannst.", "email_field_label": "E-Mail-Adresse hinzufügen", "email_in_use_error": "Die eingegebene E-Mail wird bereits verwendet", "email_invalid_alert": { @@ -87,8 +87,8 @@ "title": "Ungültige Email-Adresse" }, "email_invalid_error": "Die eingegebene E-Mail-Adresse ist ungültig", - "incorrect_password_error": "Falsches Passwort, bitte versuchen Sie es erneut", - "password_confirmation": "Bestätigen Sie Ihr Kontopasswort, um diese E-Mail-Adresse hinzuzufügen" + "incorrect_password_error": "Falsches Passwort, versuch's nochmal", + "password_confirmation": "Bestätige dein Passwort, um diese E-Mail-Adresse hinzuzufügen." }, "app_sessions_list": { "error": "App-Sitzungen konnten nicht geladen werden", @@ -103,8 +103,8 @@ "body:other": "{{count}} aktive Sitzungen", "heading": "Browser", "no_active_sessions": { - "default": "Sie sind bei keinem Webbrowser angemeldet.", - "inactive_90_days": "Alle Ihre Sitzungen waren in den letzten 90 Tagen aktiv." + "default": "Du bist in keinem Webbrowser angemeldet.", + "inactive_90_days": "Alle deine Sitzungen waren in den letzten 90 Tagen aktiv." }, "view_all_button": "Alle anzeigen" }, @@ -125,19 +125,19 @@ "heading": "Die E-Mail-Adresse {{email}} wird bereits verwendet." }, "end_session_button": { - "confirmation_modal_title": "Sind Sie sicher, dass Sie diese Sitzung abmelden möchten?", + "confirmation_modal_title": "Möchtest du diese Sitzung wirklich beenden?", "text": "Gerät entfernen" }, "error": { "hideDetails": "Details ausblenden", "showDetails": "Details anzeigen", - "subtitle": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut", + "subtitle": "Ein unerwarteter Fehler ist aufgetreten, bitte versuch's nochmal.", "title": "Etwas ist schief gelaufen" }, "error_boundary_title": "Etwas ist schief gelaufen", "errors": { "field_required": "Dieses Feld ist ein Pflichtfeld", - "rate_limit_exceeded": "Sie haben in kurzer Zeit zu viele Anfragen gestellt. Bitte warten Sie einige Minuten und versuchen Sie es erneut." + "rate_limit_exceeded": "Du hast in kurzer Zeit zu viele Anfragen gestellt. Warte bitte ein paar Minuten und versuch's nochmal." }, "last_active": { "active_date": "Aktiv {{relativeDate}}", @@ -152,7 +152,7 @@ "settings": "Einstellungen" }, "not_found_alert_title": "Nicht gefunden.", - "not_logged_in_alert": "Sie sind nicht angemeldet.", + "not_logged_in_alert": "Du bist nicht angemeldet.", "oauth2_client_detail": { "details_title": "Geräte Information", "id": "Client-ID", @@ -172,15 +172,15 @@ "current_password_label": "Aktuelles Passwort", "failure": { "description": { - "account_locked": "Ihr Konto ist gesperrt und kann derzeit nicht wiederhergestellt werden. Wenn dies unerwartet auftritt, wenden Sie sich bitte an Ihren Serveradministrator.", - "expired_recovery_ticket": "Der Wiederherstellungslink ist abgelaufen. Bitte starten Sie den Kontowiederherstellungsprozess erneut von Anfang an.", - "invalid_new_password": "Das neue Passwort, das Sie gewählt haben, ist ungültig; es entspricht möglicherweise nicht der konfigurierten Sicherheitsrichtlinie.", - "no_current_password": "Sie haben kein aktuelles Passwort.", - "no_such_recovery_ticket": "Der Wiederherstellungslink ist ungültig. Wenn Sie den Link aus der Wiederherstellungs-E-Mail kopiert haben, überprüfen Sie bitte, ob der vollständige Link kopiert wurde.", + "account_locked": "Dein Konto ist gesperrt und kann im Moment nicht wiederhergestellt werden. Wenn du das nicht erwartet hast, wende dich bitte an deinen Server-Admin.", + "expired_recovery_ticket": "Der Link zur Kontowiederherstellung ist abgelaufen. Bitte fang den Prozess noch mal von vorne an.", + "invalid_new_password": "Das neue Passwort, das du gewählt hast, ist ungültig; es entspricht möglicherweise nicht den Sicherheitsrichtlinien.", + "no_current_password": "Du hast kein aktuelles Passwort.", + "no_such_recovery_ticket": "Der Link zum Wiederherstellen ist nicht gültig. Wenn du den Link aus der E-Mail zum Wiederherstellen kopiert hast, schau bitte nach, ob du den vollständigen Link kopiert hast.", "password_changes_disabled": "Passwortänderungen sind deaktiviert.", "recovery_ticket_already_used": "Der Wiederherstellungslink wurde bereits verwendet. Er kann nicht erneut verwendet werden.", - "unspecified": "Dies könnte ein vorübergehendes Problem sein. Bitte versuchen Sie es später erneut. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an Ihren Serveradministrator.", - "wrong_password": "Das Passwort, das Sie als Ihr aktuelles Passwort eingegeben haben, ist falsch. Bitte versuchen Sie es erneut." + "unspecified": "Das könnte ein vorübergehendes Problem sein, also versuch's später nochmal. Wenn das Problem weiterhin besteht, wende dich bitte an deinen Server-Admin.", + "wrong_password": "Das Passwort, das du als dein aktuelles Passwort angegeben hast, ist falsch. Versuch's bitte nochmal." }, "title": "Aktualisierung des Passworts fehlgeschlagen" }, @@ -188,25 +188,25 @@ "new_password_label": "Neues Passwort", "passwords_match": "Passwörter stimmen überein!", "passwords_no_match": "Passwörter stimmen nicht überein", - "subtitle": "Wählen Sie ein neues Passwort für Ihren Account.", + "subtitle": "Such dir ein neues Passwort für dein Konto aus.", "success": { - "description": "Ihr Passwort wurde erfolgreich aktualisiert.", - "title": "Passwort aktualisiert" + "description": "Dein Passwort wurde geändert.", + "title": "Passwort geändert" }, - "title": "Ändern Sie Ihr Passwort" + "title": "Ändere dein Passwort" }, "password_reset": { "consumed": { - "subtitle": "Um ein neues Passwort zu erstellen, beginnen Sie von vorne und wählen Sie „Passwort vergessen“.", - "title": "Der Link zum Zurücksetzen Ihres Passworts wurde bereits verwendet" + "subtitle": "Um ein neues Passwort zu erstellen, fang einfach von vorne an und wähle „Passwort vergessen“.", + "title": "Der Link zum Zurücksetzen deines Passworts wurde bereits verwendet" }, "expired": { "resend_email": "E-Mail erneut senden", - "subtitle": "Fordern Sie eine neue E-Mail an, die an folgende Adresse gesendet wird: {{email}}", - "title": "Der Link zum Zurücksetzen Ihres Passworts ist abgelaufen" + "subtitle": "Eine neue E-Mail anfordern, die an folgende Adresse gesendet wird: {{email}}", + "title": "Der Link zum Zurücksetzen deines Passworts ist abgelaufen" }, - "subtitle": "Wählen Sie ein neues Passwort für Ihren Account.", - "title": "Ihr Passwort zurücksetzen" + "subtitle": "Such dir ein neues Passwort für dein Konto aus.", + "title": "Setze dein Passwort zurück" }, "password_strength": { "placeholder": "Passwortstärke", @@ -218,20 +218,20 @@ "4": "Sehr starkes Passwort" }, "suggestion": { - "all_uppercase": "Schreiben Sie einige, aber nicht alle Buchstaben groß.", - "another_word": "Fügen Sie weitere Wörter hinzu, die weniger gebräuchlich sind.", - "associated_years": "Vermeiden Sie Jahre, die mit Ihnen in Verbindung gebracht werden.", - "capitalization": "Schreiben Sie mehr als den ersten Buchstaben groß.", - "dates": "Vermeiden Sie Daten und Jahre, die mit Ihnen in Verbindung gebracht werden.", - "l33t": "Vermeiden Sie vorhersehbare Buchstabenersetzungen wie '@' für 'a'.", - "longer_keyboard_pattern": "Verwenden Sie längere Eingaben und ändern Sie die Tipprichtung mehrmals.", - "no_need": "Sie können sichere Passwörter erstellen, ohne Symbole, Zahlen oder Großbuchstaben zu verwenden.", - "pwned": "Wenn Sie dieses Passwort woanders verwenden, sollten Sie es ändern.", - "recent_years": "Vermeiden Sie die letzten Jahre.", - "repeated": "Vermeiden Sie Wort- und Zeichenwiederholungen.", - "reverse_words": "Vermeiden Sie umgekehrte Schreibweisen gängiger Wörter.", - "sequences": "Vermeiden Sie gängige Zeichenfolgen.", - "use_words": "Verwenden Sie mehrere Wörter, vermeiden Sie jedoch gebräuchliche Ausdrücke." + "all_uppercase": "Schreib ein paar Buchstaben groß, aber nicht alle.", + "another_word": "Füge mehr Wörter hinzu, die weniger gebräuchlich sind.", + "associated_years": "Vermeide Jahre, die mit dir in Verbindung stehen.", + "capitalization": "Schreib mehr als nur den ersten Buchstaben groß.", + "dates": "Vermeide Daten und Jahreszahlen, die mit dir in Verbindung stehen.", + "l33t": "Vermeide vorhersehbare Buchstabenersetzungen wie „@“ für „a“.", + "longer_keyboard_pattern": "Benutz längere Tastaturmuster und wechsel mehrmals die Schreibrichtung.", + "no_need": "Du kannst starke Passwörter erstellen, ohne Symbole, Zahlen oder Großbuchstaben zu benutzen.", + "pwned": "Wenn du dieses Passwort auch woanders benutzt, solltest du es ändern.", + "recent_years": "Vermeide die letzten Jahre.", + "repeated": "Vermeide es, Wörter und Zeichen zu wiederholen.", + "reverse_words": "Vermeide es, gängige Wörter rückwärts zu schreiben.", + "sequences": "Vermeide gängige Zeichenfolgen.", + "use_words": "Benutze mehrere Wörter, aber vermeide gängige Redewendungen." }, "too_weak": "Dieses Passwort ist zu schwach", "warning": { @@ -241,12 +241,12 @@ "extended_repeat": "Wiederholte Zeichenmuster wie „abcabcabc“ sind leicht zu erraten.", "key_pattern": "Kurze Eingaben sind leicht zu erraten.", "names_by_themselves": "Einzelne Vor- oder Nachnamen sind leicht zu erraten.", - "pwned": "Ihr Passwort wurde durch eine Datenpanne im Internet preisgegeben.", + "pwned": "Dein Passwort wurde durch eine Datenpanne im Internet preisgegeben.", "recent_years": "Die letzten Jahre sind leicht zu erraten.", "sequences": "Gängige Zeichenfolgen wie „abc“ sind leicht zu erraten.", "similar_to_common": "Dies ähnelt einem häufig verwendeten Passwort.", "simple_repeat": "Sich wiederholende Zeichen wie \"aaa\" sind leicht zu erraten.", - "straight_row": "Gerade Tastenreihen auf Ihrer Tastatur sind leicht zu erraten.", + "straight_row": "Gerade Reihen von Tasten auf deiner Tastatur sind leicht zu erraten.", "top_hundred": "Dies ist ein häufig verwendetes Passwort.", "top_ten": "Dies ist ein häufig verwendetes Passwort.", "user_inputs": "Es sollten keine persönlichen oder seitenbezogenen Daten vorhanden sein.", @@ -256,32 +256,32 @@ "reset_cross_signing": { "button": "Identität zurücksetzen", "cancelled": { - "description_1": "Sie können dieses Fenster schließen und zur App zurückkehren, um fortzufahren.", - "description_2": "Wenn Sie überall abgemeldet sind und Ihren Wiederherstellungscode vergessen haben, müssen Sie Ihre Identität trotzdem zurücksetzen.", + "description_1": "Du kannst dieses Fenster schließen und zur App zurückgehen, um weiterzumachen.", + "description_2": "Wenn du dich überall abgemeldet hast und deinen Wiederherstellungs-Schlüssel nicht mehr weißt, musst du deine Identität zurücksetzen.", "heading": "Identitätszurücksetzung abgebrochen." }, - "description": "Wenn Sie nirgendwo anders angemeldet sind und alle Wiederherstellungsschlüssel verloren haben, müssen Sie Ihre Krypto-Identität zurücksetzen, bevor Sie die App weiterverwenden können", + "description": "Wenn du auf keinem anderen Gerät angemeldet bist und deinen Wiederherstellungs-Schlüssel verloren hast, musst du deine Identität zurücksetzen, um die App weiter nutzen zu können.", "effect_list": { - "negative_1": "Sie werden Ihren bestehenden Nachrichtenverlauf verlieren", - "negative_2": "Sie müssen alle Ihre vorhandenen Geräte und Kontakte erneut überprüfen.", - "neutral_1": "Sie verlieren jeglichen Nachrichtenverlauf, der nur auf dem Server gespeichert ist", - "neutral_2": "Sie müssen alle Ihre vorhandenen Geräte und Kontakte erneut überprüfen.", - "positive_1": "Ihre Kontodaten, Kontakte, Einstellungen und Chat-Liste werden gespeichert" + "negative_1": "Du verlierst deine bestehenden Chats.", + "negative_2": "Du musst alle deine Geräte und Kontakte nochmal verifizieren.", + "neutral_1": "Du verlierst alle Nachrichten, die nur auf dem Server gespeichert sind.", + "neutral_2": "Du musst alle deine Geräte und Kontakte nochmal verifizieren.", + "positive_1": "Deine Kontodaten, Kontakte, Einstellungen und Chat-Liste bleiben erhalten." }, "failure": { - "description": "Dies könnte ein vorübergehendes Problem sein. Bitte versuchen Sie es später erneut. Wenn das Problem weiterhin besteht, wenden Sie sich bitte an Ihren Serveradministrator.", + "description": "Das könnte ein vorübergehendes Problem sein, also versuch's später nochmal. Wenn das Problem weiterhin besteht, wende dich bitte an deinen Server-Admin.", "heading": "Zurücksetzen der Krypto-Identität konnte nicht zugelassen werden", "title": "Krypto-Identität konnte nicht zugelassen werden" }, "finish_reset": "Reset beenden", - "heading": "Setzen Sie Ihre Identität zurück für den Fall, dass Sie sie nicht anders bestätigen können", + "heading": "Erstelle eine neue Identität, solltest du sie nicht auf andere Weise bestätigen können.", "start_reset": "Reset starten", "success": { - "description": "Das Zurücksetzen der Identität wurde für die nächsten {{minutes}} Minuten genehmigt. Sie können dieses Fenster schließen und zur App zurückkehren, um fortzufahren.", - "heading": "Die Identität wurde erfolgreich zurückgesetzt. Kehren Sie zur App zurück, um den Vorgang abzuschließen.", + "description": "Das Zurücksetzen der Identität wurde für die nächsten {{minutes}} Minuten genehmigt. Du kannst dieses Fenster schließen und zur App zurückkehren, um fortzufahren.", + "heading": "Identität erfolgreich zurückgesetzt. Geh zurück zur App, um den Vorgang abzuschließen.", "title": "Das Zurücksetzen der Krypto-Identität ist vorübergehend erlaubt" }, - "warning": "Setzen Sie Ihre Identität nur zurück, wenn Sie keinen Zugriff auf ein anderes angemeldetes Gerät haben und Ihren Wiederherstellungsschlüssel verloren haben." + "warning": "Setze deine Identität nur zurück, wenn du keinen Zugriff auf ein anderes angemeldetes Gerät hast und deinen Wiederherstellungsschlüssel verloren hast." }, "selectable_session": { "label": "Sitzung auswählen" @@ -301,7 +301,7 @@ "name_for_platform": "{{name}} für {{platform}}", "scopes_label": "Berechtigungsumfang", "set_device_name": { - "help": "Geben Sie einen Namen ein, der Ihnen hilft, dieses Gerät zu identifizieren.", + "help": "Gib einen Namen ein, mit dem du dieses Gerät leicht wiederfindest.", "label": "Gerätename", "title": "Gerätename bearbeiten" }, @@ -324,17 +324,17 @@ "unknown_route": "Unbekannte Route {{route}}", "unverified_email_alert": { "button": "Überprüfen und verifizieren", - "text:one": "Sie haben {{count}} nicht verifizierte E-Mail-Adresse.", - "text:other": "Sie haben {{count}} nicht verifizierte E-Mail-Adressen.", + "text:one": "Du hast {{count}} unverifizierte E-Mail-Adresse.", + "text:other": "Du hast {{count}} unverifizierte E-Mail-Adressen.", "title": "Nicht verifizierte E-Mail-Adresse" }, "user_email": { - "cant_delete_primary": "Wählen Sie eine andere primäre E-Mail-Adresse, um diese zu löschen.", + "cant_delete_primary": "Wähle eine andere primäre E-Mail-Adresse aus, um diese zu löschen.", "delete_button_confirmation_modal": { "action": "E-Mail löschen", "body": "Diese E-Mail löschen?", - "incorrect_password": "Falsches Passwort, bitte versuchen Sie es erneut", - "password_confirmation": "Bestätigen Sie Ihr Kontopasswort, um diese E-Mail-Adresse zu löschen" + "incorrect_password": "Falsches Passwort, versuch's nochmal", + "password_confirmation": "Bestätige dein Passwort, um diese E-Mail-Adresse zu löschen." }, "delete_button_title": "E-Mail-Adresse entfernen", "email": "E-Mail", @@ -357,29 +357,29 @@ "user_sessions_overview": { "active_sessions:one": "{{count}} aktive Sitzung", "active_sessions:other": "{{count}} aktive Sitzungen", - "heading": "Wo Sie angemeldet sind", + "heading": "Wo du angemeldet bist", "no_active_sessions": { - "default": "Sie sind bei keiner Anwendung angemeldet.", - "inactive_90_days": "Alle Ihre Sitzungen waren in den letzten 90 Tagen aktiv." + "default": "Du bist bei keiner Anwendung angemeldet.", + "inactive_90_days": "Alle deine Sitzungen waren in den letzten 90 Tagen aktiv." } }, "verify_email": { "code_expired_alert": { - "description": "Der Code ist abgelaufen. Bitte fordern Sie einen neuen Code an.", + "description": "Der Code ist abgelaufen. Bitte fordere einen neuen Code an.", "title": "Code abgelaufen" }, "code_field_error": "Code nicht erkannt", "code_field_label": "6-stelliger Code", "code_field_wrong_shape": "Der Code muss 6-stellig sein", "email_sent_alert": { - "description": "Geben Sie unten den neuen Code ein.", + "description": "Gib den neuen Code unten ein.", "title": "Neuer Code gesendet" }, - "enter_code_prompt": "Geben Sie den 6-stelligen Code ein, der an {{email}} gesendet wurde", - "heading": "Bestätigen Sie Ihre E-Mail-Adresse", + "enter_code_prompt": "Gib den 6-stelligen Code ein, der an {{email}} gesendet wurde", + "heading": "Bestätige deine E-Mail", "invalid_code_alert": { - "description": "Überprüfen Sie den Code, der an Ihre E-Mail-Adresse gesendet wurde, und aktualisieren Sie die folgenden Felder, um fortzufahren.", - "title": "Sie haben einen falschen Code eingegeben" + "description": "Überprüfe den Code, der an deine E-Mail-Adresse gesendet wurde, und aktualisiere die folgenden Felder, um fortzufahren.", + "title": "Du hast den falschen Code eingegeben." }, "resend_code": "Code erneut senden", "resend_email": "E-Mail erneut senden", @@ -389,13 +389,13 @@ }, "mas": { "scope": { - "edit_profile": "Ihr Profil und Ihre Kontaktdaten bearbeiten", - "manage_sessions": "Ihre Geräte und Sitzungen verwalten", + "edit_profile": "Bearbeite dein Profil und deine Kontaktdaten", + "manage_sessions": "Verwalte deine Geräte und Sitzungen", "mas_admin": "Beliebige Benutzer verwalten", - "send_messages": "Nachrichten in Ihrem Namen senden", + "send_messages": "Neue Nachrichten in deinem Namen senden", "synapse_admin": "Den Synapse-Homeserver verwalten", - "view_messages": "Ihre vorhandenen Nachrichten und Daten anzeigen", - "view_profile": "Ihre Profilinformationen und Kontaktdaten anzeigen" + "view_messages": "Zeig deine vorhandenen Nachrichten und Daten an", + "view_profile": "Deine Profilinfos und Kontaktdaten anzeigen" } } } \ No newline at end of file diff --git a/translations/de.json b/translations/de.json index 015322c56..2441f2cfb 100644 --- a/translations/de.json +++ b/translations/de.json @@ -40,44 +40,44 @@ "mas": { "account": { "deactivated": { - "description": "Dieses Konto (%(mxid)s) wurde gelöscht. Wenn dies nicht erwartet wird, wenden Sie sich an Ihren Serveradministrator.", + "description": "Dieses Konto (%(mxid)s) wurde entfernt. Wenn du dies nicht erwartet hast, wende dich an den Server Admin", "heading": "Konto gelöscht" }, "locked": { - "description": "Dieses Konto (%(mxid)s) wurde gesperrt. Wenn dies nicht erwartet wird, wenden Sie sich an Ihren Serveradministrator.", + "description": "Dieses Konto (%(mxid)s) wurde gesperrt. Wenn du dies nicht erwartet hast, wende dich an den Server Admin.", "heading": "Konto gesperrt" }, "logged_out": { - "description": "Diese Sitzung wurde beendet. Melden Sie sich ab, um sich wieder anmelden zu können.", + "description": "Diese Sitzung wurde beendet. Melde dich ab, um dich wieder anmelden zu können.", "heading": "Sitzung beendet" } }, "add_email": { - "description": "Geben Sie eine E-Mail-Adresse ein, um Ihr Konto wiederherzustellen, falls Sie den Zugriff darauf verlieren.", + "description": "Solltest du den Zugriff auf dein Konto verloren haben, gib bitte deine Email-Adresse ein, um das Konto wiederherzustellen.", "heading": "E-Mail-Adresse hinzufügen" }, "back_to_homepage": "Zurück", "captcha": { - "noscript": "Dieses Formular ist durch ein CAPTCHA geschützt und erfordert die Aktivierung von JavaScript, um es abschicken zu können. Bitte aktivieren Sie JavaScript in Ihrem Browser und laden Sie diese Seite neu." + "noscript": "Dieses Formular ist durch ein CAPTCHA geschützt und erfordert die Aktivierung von JavaScript, um es abschicken zu können. Bitte aktiviere JavaScript im Browser und lade diese Seite neu." }, "change_password": { "change": "Passwort ändern", "confirm": "Passwort wiederholen", "current": "Aktuelles Passwort", - "description": "Hiermit wird das Passwort für Ihr Konto geändert.", + "description": "Damit änderst du das Passwort für dein Konto.", "heading": "Mein Passwort ändern", "new": "Neues Passwort" }, "choose_display_name": { - "description": "Das ist der Name, den andere Leute sehen werden. Sie können dies jederzeit ändern.", - "headline": "Wählen Sie Ihren Anzeigenamen" + "description": "Das ist der Name, den andere Leute sehen werden. Du kannst ihn jederzeit ändern.", + "headline": "Wähle deinen Anzeigenamen" }, "consent": { - "client_wants_access": "%(client_name)s auf %(redirect_uri)s möchte auf Ihr Konto zugreifen.", - "heading": "Zugriff auf Ihr Konto zulassen?", - "make_sure_you_trust": "Stellen Sie sicher, dass Sie %(client_name)s vertrauen.", + "client_wants_access": "%(client_name)s auf %(redirect_uri)s möchte auf dein Konto zugreifen.", + "heading": "Zugriff auf dein Konto zulassen?", + "make_sure_you_trust": "Stelle sicher, dass du %(client_name)s vertraust.", "this_will_allow": "Dies wird %(client_name)s ermöglichen:", - "you_may_be_sharing": "Möglicherweise teilen Sie vertrauliche Informationen mit dieser Webseite oder App." + "you_may_be_sharing": "Du gibst vielleicht sensible Infos an diese Website oder App weiter." }, "device_card": { "access_requested": "Zugriff beantragt", @@ -87,16 +87,16 @@ }, "device_code_link": { "description": "Ein Gerät verknüpfen", - "headline": "Geben Sie den auf Ihrem Gerät angezeigten Code ein" + "headline": "Gib den Code ein, der auf deinem Gerät angezeigt wird." }, "device_consent": { - "another_device_access": "Ein anderes Gerät möchte auf Ihr Konto zugreifen.", + "another_device_access": "Ein anderes Gerät möchte auf dein Konto zugreifen.", "denied": { - "description": "Sie haben den Zugriff auf %(client_name)s verweigert. Sie können dieses Fenster schließen.", + "description": "Du hast den Zugriff auf %(client_name)s abgelehnt. Du kannst dieses Fenster jetzt schließen.", "heading": "Zugriff verweigert" }, "granted": { - "description": "Sie haben Zugriff auf %(client_name)s gewährt. Sie können dieses Fenster schließen.", + "description": "Du hast %(client_name)s Zugriff gegeben. Du kannst dieses Fenster jetzt schließen.", "heading": "Zugriff gewährt" } }, @@ -106,28 +106,28 @@ "unknown_device": "Unbekanntes Gerät" }, "email_in_use": { - "description": "Wenn Sie Ihre Kontoinformationen vergessen haben, können Sie Ihr Konto wiederherstellen. Sie können auch von vorne beginnen und eine andere E-Mail-Adresse verwenden.", + "description": "Wenn du deine Kontodaten vergessen hast, kannst du dein Konto wiederherstellen. Du kannst auch neu anfangen und eine andere E-Mail-Adresse verwenden.", "title": "Die E-Mail-Adresse %(email)s wird bereits verwendet" }, "emails": { "greeting": "Hallo %(username)s,", "recovery": { - "click_button": "Klicken Sie auf die Schaltfläche unten, um ein neues Passwort zu erstellen:", - "copy_link": "Kopieren Sie den folgenden Link und fügen Sie ihn in einen Browser ein, um ein neues Passwort zu erstellen:", + "click_button": "Klick unten, um ein neues Passwort zu erstellen:", + "copy_link": "Kopier den folgenden Link und füge ihn in deinen Browser ein, um ein neues Passwort zu erstellen:", "create_new_password": "Neues Passwort erstellen", "fallback": "Funktioniert der Button bei Ihnen nicht?", - "headline": "Sie haben ein Zurücksetzen des Passworts für Ihr %(server_name)s Konto angefordert.", - "subject": "Setzen Sie Ihr Kontokennwort zurück (%(mxid)s )", - "you_can_ignore": "Wenn Sie nicht nach einem neuen Passwort gefragt haben, können Sie diese E-Mail ignorieren. Ihr aktuelles Passwort wird weiterhin funktionieren." + "headline": "Du hast das Zurücksetzen des Passworts für dein Konto bei %(server_name)s angefordert.", + "subject": "Setze dein Konto Passwort zurück (%(mxid)s)", + "you_can_ignore": "Wenn du kein neues Passwort angefordert hast, kannst du diese E-Mail einfach ignorieren. Dein aktuelles Passwort funktioniert weiterhin." }, "verify": { - "body_html": "Ihr Code zur Bestätigung dieser E-Mail-Adresse lautet: %(code)s", - "body_text": "Ihr Code zur Bestätigung dieser E-Mail-Adresse lautet: %(code)s", - "subject": "Ihr E-Mail-Bestätigungscode lautet: %(code)s" + "body_html": "Dein Code zur Bestätigung dieser E-Mail-Adresse lautet: %(code)s", + "body_text": "Dein Code zur Bestätigung dieser E-Mail-Adresse lautet: %(code)s", + "subject": "Dein E-Mail-Bestätigungscode lautet: %(code)s" } }, "errors": { - "captcha": "Die CAPTCHA-Überprüfung ist fehlgeschlagen, bitte versuchen Sie es erneut", + "captcha": "Die CAPTCHA-Überprüfung hat nicht geklappt, versuch's nochmal.", "denied_policy": "Abgelehnt durch Richtlinie: %(policy)s", "email_banned": "E-Mail ist durch die Serverrichtlinie gesperrt", "email_domain_banned": "Die E-Mail-Domain ist durch die Serverrichtlinie gesperrt", @@ -136,24 +136,24 @@ "field_required": "Dieses Feld ist ein Pflichtfeld", "invalid_credentials": "Ungültige Anmeldeinformationen", "password_mismatch": "Die Passwortfelder stimmen nicht überein", - "rate_limit_exceeded": "Sie haben in kurzer Zeit zu viele Anfragen gestellt. Bitte warten Sie einige Minuten und versuchen Sie es erneut.", + "rate_limit_exceeded": "Du hast in kurzer Zeit zu viele Anfragen gestellt. Warte bitte ein paar Minuten und versuch's nochmal.", "username_all_numeric": "Der Benutzername darf nicht nur aus Zahlen bestehen", "username_banned": "Der Benutzername ist durch die Serverrichtlinie gesperrt", - "username_invalid_chars": "Der Benutzername enthält ungültige Zeichen. Verwenden Sie nur Kleinbuchstaben, Zahlen, Bindestriche und Unterstriche.", + "username_invalid_chars": "Der Nutzername enthält ungültige Zeichen. Verwende nur Kleinbuchstaben, Zahlen, Bindestriche und Unterstriche.", "username_not_allowed": "Der Benutzername ist gemäß der Serverrichtlinie nicht zulässig", "username_taken": "Dieser Benutzername ist bereits vergeben", "username_too_long": "Der Benutzername ist zu lang", "username_too_short": "Der Benutzername ist zu kurz" }, "login": { - "call_to_register": "Sie haben noch kein Konto?", + "call_to_register": "Du hast noch kein Konto?", "continue_with_provider": "Weiter mit %(provider)s", - "description": "Bitte melden Sie sich an, um fortzufahren:", + "description": "Bitte melde dich an, um fortzufahren:", "forgot_password": "Passwort vergessen?", "headline": "Anmelden", "link": { - "description": "Ihr %(provider)s Konto verknüpfen", - "headline": "Melden Sie sich zum Verbinden an" + "description": "Dein %(provider)s Konto verknüpfen", + "headline": "Melde dich zum Verbinden an" }, "no_login_methods": "Keine Anmeldemethoden verfügbar.", "separator": "Oder", @@ -165,7 +165,7 @@ "signed_in_as": "Angemeldet als %(username)s." }, "not_found": { - "description": "Die Seite, nach der Sie gesucht haben, existiert nicht oder wurde verschoben", + "description": "Die Seite, die du gesucht hast, gibt's nicht oder wurde verschoben.", "heading": "Seite nicht gefunden" }, "not_you": "Nicht %(username)s?", @@ -177,41 +177,41 @@ }, "recovery": { "consumed": { - "description": "Um ein neues Passwort zu erstellen, beginnen Sie von vorne und wählen Sie „Passwort vergessen“.", - "heading": "Der Link zum Zurücksetzen Ihres Passworts wurde bereits verwendet" + "description": "Um ein neues Passwort zu erstellen, fang einfach von vorne an und wähle „Passwort vergessen”.", + "heading": "Der Link zum Zurücksetzen deines Passworts wurde bereits verwendet" }, "disabled": { - "description": "Wenn Sie Ihre Zugangsdaten verloren haben, wenden Sie sich bitte an den Administrator, um Ihr Konto wiederherzustellen.", + "description": "Wenn du deine Konto Daten verloren hast, wende dich bitte an den Admin, um das Konto wiederherzustellen.", "heading": "Die Kontowiederherstellung ist deaktiviert" }, "expired": { - "description": "Fordern Sie eine neue E-Mail an, die an folgende Adresse gesendet wird: %(email)s.", - "heading": "Der Link zum Zurücksetzen Ihres Passworts ist abgelaufen", + "description": "Bitte schick eine neue E-Mail an: %(email)s.", + "heading": "Der Link zum Zurücksetzen deines Passworts ist abgelaufen", "resend_email": "E-Mail erneut senden" }, "finish": { "confirm": "Neues Passwort erneut eingeben", - "description": "Wählen Sie ein neues Passwort für Ihren Account.", - "heading": "Ihr Passwort zurücksetzen", + "description": "Such dir ein neues Passwort für dein Konto aus.", + "heading": "Setze dein Passwort zurück", "new": "Neues Passwort", "save_and_continue": "Speichern und fortfahren" }, "progress": { - "change_email": "Versuchen Sie es mit einer anderen E-Mail", - "description": "Wir haben eine E-Mail mit einem Link zum Zurücksetzen Ihres Passworts gesendet, wenn es ein Konto mit %(email)s gibt.", - "heading": "Überprüfen Sie Ihre E-Mails", + "change_email": "Probier's mal mit einer anderen E-Mail-Adresse", + "description": "Eine E-Mail mit einem Link zum Zurücksetzen deines Passworts wurde versendet, wenn es ein Konto mit %(email)s gibt.", + "heading": "Überprüfe deine E-Mails!", "resend_email": "E-Mail erneut senden" }, "start": { - "description": "Es wird eine E-Mail mit einem Link zum Zurücksetzen Ihres Passworts gesendet.", - "heading": "Geben Sie Ihre E-Mail-Adresse ein, um fortzufahren" + "description": "Es wird eine E-Mail mit einem Link zum Zurücksetzen deines Passworts gesendet.", + "heading": "Gib deine E-Mail-Adresse ein, um fortzufahren" } }, "register": { - "call_to_login": "Sie haben bereits ein Konto?", + "call_to_login": "Du hast bereits ein Konto?", "continue_with_email": "Mit E-Mail-Adresse fortfahren", "create_account": { - "description": "Wählen Sie einen Benutzernamen, um fortzufahren.", + "description": "Wähle einen Nutzernamen, um fortzufahren.", "heading": "Konto erstellen" }, "sign_in_instead": "Stattdessen anmelden", @@ -223,13 +223,13 @@ "headline": "Registrierungstoken" }, "scope": { - "edit_profile": "Ihr Profil und Ihre Kontaktdaten bearbeiten", - "manage_sessions": "Ihre Geräte und Sitzungen verwalten", + "edit_profile": "Bearbeite dein Profil und deine Kontaktdaten", + "manage_sessions": "Verwalte deine Geräte und Sitzungen", "mas_admin": "Beliebige Benutzer verwalten", - "send_messages": "Nachrichten in Ihrem Namen senden", + "send_messages": "Neue Nachrichten in deinem Namen senden", "synapse_admin": "Den Synapse-Homeserver verwalten", - "view_messages": "Ihre vorhandenen Nachrichten und Daten anzeigen", - "view_profile": "Ihre Profilinformationen und Kontaktdaten anzeigen" + "view_messages": "Zeig deine vorhandenen Nachrichten und Daten an", + "view_profile": "Deine Profilinfos und Kontaktdaten anzeigen" }, "upstream_oauth2": { "link_mismatch": { @@ -238,12 +238,12 @@ "login_link": { "action": "Weiter", "description": "Für diesen Nutzernamen (%(username)s) gibt es schon ein Konto. Es wird mit diesem Upstream-Konto verknüpft.", - "heading": "Mit Ihrem bestehenden Konto verknüpfen" + "heading": "Verknüpfe mit deinem bestehenden Konto" }, "register": { "choose_username": { "description": "Dies kann später nicht mehr geändert werden.", - "heading": "Wählen Sie Ihren Benutzernamen" + "heading": "Wähle einen Nutzernamen" }, "create_account": "Neues Konto erstellen", "enforced_by_policy": "Erzwungen durch Server-Richtlinie", @@ -251,15 +251,15 @@ "forced_email": "Verwendet die folgende E-Mail-Adresse", "forced_localpart": "Verwendet den folgenden Benutzernamen", "import_data": { - "description": "Bestätigen Sie die Informationen, die mit Ihrem neuen %(server_name)s Konto verknüpft werden.", - "heading": "Ihre Daten importieren" + "description": "Bestätige die Informationen, die mit dem neuen %(server_name)s Konto verknüpft werden.", + "heading": "Deine Daten importieren" }, - "imported_from_upstream": "Von Ihrem Konto importiert", - "imported_from_upstream_with_name": "Importiert von Ihrem%(human_name)s Konto", + "imported_from_upstream": "Aus deinem Upstream-Konto importiert", + "imported_from_upstream_with_name": "Importiert von deinem %(human_name)s -Konto", "link_existing": "Mit einem bestehenden Konto verknüpfen", "provider_name": "%(human_name)s Konto", "signup_with_upstream": { - "heading": "Setzen Sie die Anmeldung mit Ihrem %(human_name)s Konto fort." + "heading": "Setze die Anmeldung mit %(human_name)s Konto fort." }, "suggested_display_name": "Anzeigenamen importieren", "suggested_email": "E-Mail-Adresse importieren", @@ -267,14 +267,14 @@ }, "suggest_link": { "action": "Link", - "heading": "Mit Ihrem bestehenden Konto verknüpfen" + "heading": "Verknüpfe mit deinem bestehenden Konto" } }, "verify_email": { "6_digit_code": "6-stelliger Code", "code": "Code", - "description": "Geben Sie den 6-stelligen Code ein, der an %(email)s gesendet wurde", - "headline": "Bestätigen Sie Ihre E-Mail-Adresse" + "description": "Gib den 6-stelligen Code ein, der an %(email)s gesendet wurde", + "headline": "Bestätige deine E-Mail" } } } \ No newline at end of file diff --git a/translations/zh-Hans.json b/translations/zh-Hans.json index 25e800dd3..9fddcb911 100644 --- a/translations/zh-Hans.json +++ b/translations/zh-Hans.json @@ -237,6 +237,7 @@ }, "login_link": { "action": "继续", + "description": "此用户名(%(username)s)已存在于一个账户,它将与该上游账户关联。", "heading": "链接到现有账户" }, "register": { From 8eb2389a95b819a6d20784550c64145efe351621 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:13:47 +0000 Subject: [PATCH 125/296] build(deps): bump softprops/action-gh-release from 2.3.3 to 2.4.0 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.3 to 2.4.0. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2.3.3...v2.4.0) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 7dad4d1d4..787ae7680 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -327,7 +327,7 @@ jobs: merge-multiple: true - name: Prepare a release - uses: softprops/action-gh-release@v2.3.3 + uses: softprops/action-gh-release@v2.4.0 with: generate_release_notes: true body: | @@ -396,7 +396,7 @@ jobs: await script({ core, github, context }); - name: Update unstable release - uses: softprops/action-gh-release@v2.3.3 + uses: softprops/action-gh-release@v2.4.0 with: name: "Unstable build" tag_name: unstable From 43f7140989b96d1ebbf4bc0c84a50da9f1c64c89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:14:10 +0000 Subject: [PATCH 126/296] build(deps): bump i18next in /frontend in the i18next group Bumps the i18next group in /frontend with 1 update: [i18next](https://github.com/i18next/i18next). Updates `i18next` from 25.5.2 to 25.5.3 - [Release notes](https://github.com/i18next/i18next/releases) - [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md) - [Commits](https://github.com/i18next/i18next/compare/v25.5.2...v25.5.3) --- updated-dependencies: - dependency-name: i18next dependency-version: 25.5.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: i18next ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0cdfed463..6d7d659ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -20,7 +20,7 @@ "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", "date-fns": "^4.1.0", - "i18next": "^25.5.2", + "i18next": "^25.5.3", "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^16.0.0", @@ -8773,9 +8773,9 @@ } }, "node_modules/i18next": { - "version": "25.5.2", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.2.tgz", - "integrity": "sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw==", + "version": "25.5.3", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.3.tgz", + "integrity": "sha512-joFqorDeQ6YpIXni944upwnuHBf5IoPMuqAchGVeQLdWC2JOjxgM9V8UGLhNIIH/Q8QleRxIi0BSRQehSrDLcg==", "funding": [ { "type": "individual", diff --git a/frontend/package.json b/frontend/package.json index 41f6ae5ce..384d5f2ec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,7 +30,7 @@ "@zxcvbn-ts/language-common": "^3.0.4", "classnames": "^2.5.1", "date-fns": "^4.1.0", - "i18next": "^25.5.2", + "i18next": "^25.5.3", "react": "^19.1.1", "react-dom": "^19.1.1", "react-i18next": "^16.0.0", From ca2f9b96a6266292cb1655c6b956c821900de80d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:14:19 +0000 Subject: [PATCH 127/296] build(deps-dev): bump @types/node in /frontend in the types group Bumps the types group in /frontend with 1 update: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node). Updates `@types/node` from 24.6.0 to 24.6.1 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 24.6.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: types ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 16 ++++++++-------- frontend/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0cdfed463..369b3a5f3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -44,7 +44,7 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.6.0", + "@types/node": "^24.7.0", "@types/react": "19.1.16", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", @@ -5867,13 +5867,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.0.tgz", - "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", + "version": "24.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", + "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~7.13.0" + "undici-types": "~7.14.0" } }, "node_modules/@types/react": { @@ -12928,9 +12928,9 @@ } }, "node_modules/undici-types": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz", - "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", "dev": true, "license": "MIT" }, diff --git a/frontend/package.json b/frontend/package.json index 41f6ae5ce..1352ab371 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,7 +54,7 @@ "@testing-library/jest-dom": "^6.8.0", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.6.0", + "@types/node": "^24.7.0", "@types/react": "19.1.16", "@types/react-dom": "19.1.9", "@types/swagger-ui-dist": "^3.30.6", From 4f1251fba0bae1645bb3e7e26c9540ed8fc24da3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:14:35 +0000 Subject: [PATCH 128/296] build(deps-dev): bump the storybook group in /frontend with 3 updates Bumps the storybook group in /frontend with 3 updates: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite) and [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/core). Updates `@storybook/addon-docs` from 9.1.9 to 9.1.10 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.10/code/addons/docs) Updates `@storybook/react-vite` from 9.1.9 to 9.1.10 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.10/code/frameworks/react-vite) Updates `storybook` from 9.1.9 to 9.1.10 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v9.1.10/code/core) --- updated-dependencies: - dependency-name: "@storybook/addon-docs" dependency-version: 9.1.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/react-vite" dependency-version: 9.1.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-version: 9.1.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 70 +++++++++++++++++++------------------- frontend/package.json | 4 +-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0cdfed463..d7d69544b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,8 +36,8 @@ "@graphql-codegen/cli": "^6.0.0", "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.9", - "@storybook/react-vite": "^9.1.9", + "@storybook/addon-docs": "^9.1.10", + "@storybook/react-vite": "^9.1.10", "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", @@ -5161,16 +5161,16 @@ "license": "Apache-2.0" }, "node_modules/@storybook/addon-docs": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.9.tgz", - "integrity": "sha512-76OHwsYCC6u8Nu5IUQ3E580BVnto6u4UgQC66inf+ot0+LI9fFPieg7fmcnQtYoFwiAyya3/JEwhY2GuFk7eMg==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.10.tgz", + "integrity": "sha512-LYK3oXy/0PgY39FhkYVd9D0bzatLGTsMhaPPwSjBOmZgK0f0yBLqaePy7urUFeHYm/rjwAaRmDJNBqUnGTVoig==", "dev": true, "license": "MIT", "dependencies": { "@mdx-js/react": "^3.0.0", - "@storybook/csf-plugin": "9.1.9", + "@storybook/csf-plugin": "9.1.10", "@storybook/icons": "^1.4.0", - "@storybook/react-dom-shim": "9.1.9", + "@storybook/react-dom-shim": "9.1.10", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" @@ -5180,17 +5180,17 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.9" + "storybook": "^9.1.10" } }, "node_modules/@storybook/builder-vite": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.9.tgz", - "integrity": "sha512-tCQ2Bv07D0roTg6+c1dCrX6PmAwEpKkwX4eqq32vGYiQ0CTzWP1ivBUAzBvIIHD2FY/zLXzXSrDo/qtrQppCGw==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.10.tgz", + "integrity": "sha512-0ogI+toZJYaFptcFpRcRPOZ9/NrFUYhiaI09ggeEB1FF9ygHMVsobp4eaj4HjZI6V3x7cQwkd2ZmxAMQDBQuMA==", "dev": true, "license": "MIT", "dependencies": { - "@storybook/csf-plugin": "9.1.9", + "@storybook/csf-plugin": "9.1.10", "ts-dedent": "^2.0.0" }, "funding": { @@ -5198,14 +5198,14 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.9", + "storybook": "^9.1.10", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@storybook/csf-plugin": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.9.tgz", - "integrity": "sha512-8tMZaGqer9PkPl7xRD/d97pgzl6Aw5/rWH+q8fAA09bvjLllKOlytj3vTckGJ4DlkKKXGvxoECG/n35AbJOYIA==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.10.tgz", + "integrity": "sha512-247F/JU0Naxm/RIUnQYpqXeCL0wG8UNJkZe+/GkLjdqzsyML0lb+8OwBsWFfG8zfj6fkjmRU2mF44TnNkzoQcg==", "dev": true, "license": "MIT", "dependencies": { @@ -5216,7 +5216,7 @@ "url": "https://opencollective.com/storybook" }, "peerDependencies": { - "storybook": "^9.1.9" + "storybook": "^9.1.10" } }, "node_modules/@storybook/global": { @@ -5241,14 +5241,14 @@ } }, "node_modules/@storybook/react": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.9.tgz", - "integrity": "sha512-S06dZv8ebUmCrIP2GfIqD3g1F5LKBf0Lc1daSd2++2MI6i8zw8kZ8IAGg5bYrWb0nk56JHALCwXAzsGyRepEww==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.10.tgz", + "integrity": "sha512-flG3Gn3EHZnxn92C7vrA2U4aGqpOKdf85fL43+J/2k9HF5AIyOFGlcv4LGVyKZ3LOAow/nGBVSXL9961h+ICRA==", "dev": true, "license": "MIT", "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/react-dom-shim": "9.1.9" + "@storybook/react-dom-shim": "9.1.10" }, "engines": { "node": ">=20.0.0" @@ -5260,7 +5260,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.9", + "storybook": "^9.1.10", "typescript": ">= 4.9.x" }, "peerDependenciesMeta": { @@ -5270,9 +5270,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.9.tgz", - "integrity": "sha512-RFaB+N63XXEEo8l5INlvWnqxDUH7UGZ++MOsFsVUqfn7lAzxfR9HcJTGN3WOyIDBoS0vD3+LfnplqFyQU/anuw==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.10.tgz", + "integrity": "sha512-cxy8GTj73RMJIFPrgqdnMXePGX5iFohM5pDCZ63Te5m5GtzKqsILRXtBBLO6Ouexm/ZYRVznkKiwNKX/Fu24fQ==", "dev": true, "license": "MIT", "funding": { @@ -5282,20 +5282,20 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.9" + "storybook": "^9.1.10" } }, "node_modules/@storybook/react-vite": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.9.tgz", - "integrity": "sha512-k+wbLdM8963YkQmVSFEuigUfGZKEgUdA7tTazXGzkL65j0il93JbtFCso8spKePlgeQ2uD6RxbXUp+E3qLeRSw==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.10.tgz", + "integrity": "sha512-k0wWlfoWakoHL3NZ1+38oxRH3WYyprFFX+WUb/4W8axrvpKogvdnxKCul/YB1HH5FcTagIfguamsPjKwB1ZkJg==", "dev": true, "license": "MIT", "dependencies": { "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", "@rollup/pluginutils": "^5.0.2", - "@storybook/builder-vite": "9.1.9", - "@storybook/react": "9.1.9", + "@storybook/builder-vite": "9.1.10", + "@storybook/react": "9.1.10", "find-up": "^7.0.0", "magic-string": "^0.30.0", "react-docgen": "^8.0.0", @@ -5312,7 +5312,7 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", - "storybook": "^9.1.9", + "storybook": "^9.1.10", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" } }, @@ -12098,9 +12098,9 @@ "license": "MIT" }, "node_modules/storybook": { - "version": "9.1.9", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.9.tgz", - "integrity": "sha512-KEazHA1iD2L8Fll+Kw9c/z0Pjv3Z+1GHYejmk+JlrIt+/mXDG2HVF7eelvk3tYCbuxqyuCL57pYhJUfkHwA6Fw==", + "version": "9.1.10", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.10.tgz", + "integrity": "sha512-4+U7gF9hMpGilQmdVJwQaVZZEkD7XwC4ZDmBa51mobaPYelELEMoMfNM2hLyvB2x12gk1IJui1DnwOE4t+MXhw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 41f6ae5ce..a8d6e878a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -46,8 +46,8 @@ "@graphql-codegen/cli": "^6.0.0", "@graphql-codegen/client-preset": "^5.0.2", "@graphql-codegen/typescript-msw": "^3.0.1", - "@storybook/addon-docs": "^9.1.9", - "@storybook/react-vite": "^9.1.9", + "@storybook/addon-docs": "^9.1.10", + "@storybook/react-vite": "^9.1.10", "@tanstack/react-query-devtools": "^5.90.2", "@tanstack/react-router-devtools": "^1.131.44", "@tanstack/router-plugin": "^1.131.44", From fba01ebcbb6a7b2a75ee0e24a58c5dad8040dee5 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Thu, 2 Oct 2025 13:51:28 +0100 Subject: [PATCH 129/296] activity tracker: Add SessionKind::Personal --- crates/handlers/src/activity_tracker/mod.rs | 25 +++++++++++++++++++ .../handlers/src/activity_tracker/worker.rs | 5 ++++ 2 files changed, 30 insertions(+) diff --git a/crates/handlers/src/activity_tracker/mod.rs b/crates/handlers/src/activity_tracker/mod.rs index 738da3856..71d6a8fc2 100644 --- a/crates/handlers/src/activity_tracker/mod.rs +++ b/crates/handlers/src/activity_tracker/mod.rs @@ -24,6 +24,8 @@ static MESSAGE_QUEUE_SIZE: usize = 1000; enum SessionKind { OAuth2, Compat, + /// Session associated with personal access tokens + Personal, Browser, } @@ -32,6 +34,7 @@ impl SessionKind { match self { SessionKind::OAuth2 => "oauth2", SessionKind::Compat => "compat", + SessionKind::Personal => "personal", SessionKind::Browser => "browser", } } @@ -108,6 +111,28 @@ impl ActivityTracker { } } + /// Record activity in a personal access token session. + pub async fn record_personal_access_token_session( + &self, + clock: &dyn Clock, + session: &Session, + ip: Option, + ) { + let res = self + .channel + .send(Message::Record { + kind: SessionKind::Personal, + id: session.id, + date_time: clock.now(), + ip, + }) + .await; + + if let Err(e) = res { + tracing::error!("Failed to record Personal session: {}", e); + } + } + /// Record activity in a compat session. pub async fn record_compat_session( &self, diff --git a/crates/handlers/src/activity_tracker/worker.rs b/crates/handlers/src/activity_tracker/worker.rs index 46cc84ccd..6fa51fce3 100644 --- a/crates/handlers/src/activity_tracker/worker.rs +++ b/crates/handlers/src/activity_tracker/worker.rs @@ -224,6 +224,7 @@ impl Worker { let mut browser_sessions = Vec::new(); let mut oauth2_sessions = Vec::new(); let mut compat_sessions = Vec::new(); + let mut personal_sessions = Vec::new(); for ((kind, id), record) in pending_records { match kind { @@ -236,6 +237,9 @@ impl Worker { SessionKind::Compat => { compat_sessions.push((*id, record.end_time, record.ip)); } + SessionKind::Personal => { + personal_sessions.push((*id, record.end_time, record.ip)); + } } } @@ -253,6 +257,7 @@ impl Worker { repo.compat_session() .record_batch_activity(compat_sessions) .await?; + // TODO: personal sessions: record repo.save().await?; self.pending_records.clear(); From 293271912d47cc96225a1a5e50790f64285a81f8 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Thu, 2 Oct 2025 13:53:43 +0100 Subject: [PATCH 130/296] data model: Add personal sessions with `mpt_` prefix --- crates/data-model/src/lib.rs | 1 + crates/data-model/src/personal/mod.rs | 32 ++++++ crates/data-model/src/personal/session.rs | 111 ++++++++++++++++++++ crates/data-model/src/tokens.rs | 10 +- crates/handlers/src/oauth2/introspection.rs | 5 + 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 crates/data-model/src/personal/mod.rs create mode 100644 crates/data-model/src/personal/session.rs diff --git a/crates/data-model/src/lib.rs b/crates/data-model/src/lib.rs index 337c05d89..962c8be00 100644 --- a/crates/data-model/src/lib.rs +++ b/crates/data-model/src/lib.rs @@ -11,6 +11,7 @@ use thiserror::Error; pub mod clock; pub(crate) mod compat; pub mod oauth2; +pub mod personal; pub(crate) mod policy_data; mod site_config; pub(crate) mod tokens; diff --git a/crates/data-model/src/personal/mod.rs b/crates/data-model/src/personal/mod.rs new file mode 100644 index 000000000..1142fea76 --- /dev/null +++ b/crates/data-model/src/personal/mod.rs @@ -0,0 +1,32 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +pub mod session; + +use chrono::{DateTime, Utc}; +use ulid::Ulid; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PersonalAccessToken { + pub id: Ulid, + pub session_id: Ulid, + pub created_at: DateTime, + pub expires_at: Option>, + pub revoked_at: Option>, +} + +impl PersonalAccessToken { + #[must_use] + pub fn is_valid(&self, now: DateTime) -> bool { + if self.revoked_at.is_some() { + return false; + } + if let Some(expires_at) = self.expires_at { + expires_at > now + } else { + true + } + } +} diff --git a/crates/data-model/src/personal/session.rs b/crates/data-model/src/personal/session.rs new file mode 100644 index 000000000..f8904f810 --- /dev/null +++ b/crates/data-model/src/personal/session.rs @@ -0,0 +1,111 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use std::net::IpAddr; + +use chrono::{DateTime, Utc}; +use oauth2_types::scope::Scope; +use serde::Serialize; +use ulid::Ulid; + +use crate::InvalidTransitionError; + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)] +pub enum SessionState { + #[default] + Valid, + Revoked { + revoked_at: DateTime, + }, +} + +impl SessionState { + /// Returns `true` if the session state is [`Valid`]. + /// + /// [`Valid`]: SessionState::Valid + #[must_use] + pub fn is_valid(&self) -> bool { + matches!(self, Self::Valid) + } + + /// Returns `true` if the session state is [`Revoked`]. + /// + /// [`Revoked`]: SessionState::Revoked + #[must_use] + pub fn is_revoked(&self) -> bool { + matches!(self, Self::Revoked { .. }) + } + + /// Transitions the session state to [`Revoked`]. + /// + /// # Parameters + /// + /// * `revoked_at` - The time at which the session was revoked. + /// + /// # Errors + /// + /// Returns an error if the session state is already [`Revoked`]. + /// + /// [`Revoked`]: SessionState::Revoked + pub fn revoke(self, revoked_at: DateTime) -> Result { + match self { + Self::Valid => Ok(Self::Revoked { revoked_at }), + Self::Revoked { .. } => Err(InvalidTransitionError), + } + } + + /// Returns the time the session was revoked, if any + /// + /// Returns `None` if the session is still [`Valid`]. + /// + /// [`Valid`]: SessionState::Valid + #[must_use] + pub fn revoked_at(&self) -> Option> { + match self { + Self::Valid => None, + Self::Revoked { revoked_at } => Some(*revoked_at), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +pub struct PersonalSession { + pub id: Ulid, + pub state: SessionState, + pub owner_user_id: Ulid, + pub actor_user_id: Ulid, + pub human_name: String, + /// The scope for the session, identical to OAuth2 sessions. + /// May or may not include a device scope + /// (personal sessions can be deviceless). + pub scope: Scope, + pub created_at: DateTime, + pub last_active_at: Option>, + pub last_active_ip: Option, +} + +impl std::ops::Deref for PersonalSession { + type Target = SessionState; + + fn deref(&self) -> &Self::Target { + &self.state + } +} + +impl PersonalSession { + /// Marks the session as revoked. + /// + /// # Parameters + /// + /// * `revoked_at` - The time at which the session was finished. + /// + /// # Errors + /// + /// Returns an error if the session is already finished. + pub fn finish(mut self, revoked_at: DateTime) -> Result { + self.state = self.state.revoke(revoked_at)?; + Ok(self) + } +} diff --git a/crates/data-model/src/tokens.rs b/crates/data-model/src/tokens.rs index 1ea5be6be..bd34c5000 100644 --- a/crates/data-model/src/tokens.rs +++ b/crates/data-model/src/tokens.rs @@ -240,6 +240,9 @@ pub enum TokenType { /// A legacy refresh token CompatRefreshToken, + + /// A personal access token. + PersonalAccessToken, } impl std::fmt::Display for TokenType { @@ -249,6 +252,7 @@ impl std::fmt::Display for TokenType { TokenType::RefreshToken => write!(f, "refresh token"), TokenType::CompatAccessToken => write!(f, "compat access token"), TokenType::CompatRefreshToken => write!(f, "compat refresh token"), + TokenType::PersonalAccessToken => write!(f, "personal access token"), } } } @@ -260,6 +264,7 @@ impl TokenType { TokenType::RefreshToken => "mar", TokenType::CompatAccessToken => "mct", TokenType::CompatRefreshToken => "mcr", + TokenType::PersonalAccessToken => "mpt", } } @@ -269,6 +274,7 @@ impl TokenType { "mar" => Some(TokenType::RefreshToken), "mct" | "syt" => Some(TokenType::CompatAccessToken), "mcr" | "syr" => Some(TokenType::CompatRefreshToken), + "mpt" => Some(TokenType::PersonalAccessToken), _ => None, } } @@ -335,7 +341,9 @@ impl PartialEq for TokenType { matches!( (self, other), ( - TokenType::AccessToken | TokenType::CompatAccessToken, + TokenType::AccessToken + | TokenType::CompatAccessToken + | TokenType::PersonalAccessToken, OAuthTokenTypeHint::AccessToken ) | ( TokenType::RefreshToken | TokenType::CompatRefreshToken, diff --git a/crates/handlers/src/oauth2/introspection.rs b/crates/handlers/src/oauth2/introspection.rs index 6bb61bf72..27ee3fdbc 100644 --- a/crates/handlers/src/oauth2/introspection.rs +++ b/crates/handlers/src/oauth2/introspection.rs @@ -625,6 +625,11 @@ pub(crate) async fn post( device_id: session.device.map(Device::into), } } + + TokenType::PersonalAccessToken => { + // TODO + return Err(RouteError::UnknownToken(TokenType::PersonalAccessToken)); + } }; repo.save().await?; From 28e573b4009ccd50c2c88866ed07ae8535fddb59 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Tue, 7 Oct 2025 17:13:05 +0200 Subject: [PATCH 131/296] Add a configuration option to make email optional for password registration --- crates/cli/src/util.rs | 1 + crates/config/src/sections/account.rs | 8 + crates/data-model/src/site_config.rs | 3 + crates/handlers/src/admin/v1/site_config.rs | 5 + crates/handlers/src/test_utils.rs | 1 + .../handlers/src/views/register/password.rs | 384 ++++++++++++++++-- .../src/views/register/steps/finish.rs | 104 ++--- crates/templates/src/context/ext.rs | 1 + crates/templates/src/context/features.rs | 7 + crates/templates/src/lib.rs | 1 + docs/api/spec.json | 6 + docs/config.schema.json | 4 + docs/reference/configuration.md | 8 +- policies/register/register.rego | 7 - policies/register/register_test.rego | 5 +- templates/pages/register/index.html | 6 +- templates/pages/register/password.html | 8 +- translations/en.json | 20 +- 18 files changed, 482 insertions(+), 97 deletions(-) diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index 959c8ba0f..976a08c32 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -211,6 +211,7 @@ pub fn site_config_from_config( password_login_enabled: password_config.enabled(), password_registration_enabled: password_config.enabled() && account_config.password_registration_enabled, + password_registration_email_required: account_config.password_registration_email_required, registration_token_required: account_config.registration_token_required, email_change_allowed: account_config.email_change_allowed, displayname_change_allowed: account_config.displayname_change_allowed, diff --git a/crates/config/src/sections/account.rs b/crates/config/src/sections/account.rs index 47efa0162..2b6538a2b 100644 --- a/crates/config/src/sections/account.rs +++ b/crates/config/src/sections/account.rs @@ -50,6 +50,13 @@ pub struct AccountConfig { #[serde(default = "default_false", skip_serializing_if = "is_default_false")] pub password_registration_enabled: bool, + /// Whether self-service password registrations require a valid email. + /// Defaults to `true`. + /// + /// This has no effect if password registration is disabled. + #[serde(default = "default_true", skip_serializing_if = "is_default_true")] + pub password_registration_email_required: bool, + /// Whether users are allowed to change their passwords. Defaults to `true`. /// /// This has no effect if password login is disabled. @@ -89,6 +96,7 @@ impl Default for AccountConfig { email_change_allowed: default_true(), displayname_change_allowed: default_true(), password_registration_enabled: default_false(), + password_registration_email_required: default_true(), password_change_allowed: default_true(), password_recovery_enabled: default_false(), account_deactivation_allowed: default_true(), diff --git a/crates/data-model/src/site_config.rs b/crates/data-model/src/site_config.rs index ac0d7e6b8..9622203ad 100644 --- a/crates/data-model/src/site_config.rs +++ b/crates/data-model/src/site_config.rs @@ -64,6 +64,9 @@ pub struct SiteConfig { /// Whether password registration is enabled. pub password_registration_enabled: bool, + /// Whether a valid email address is required for password registrations. + pub password_registration_email_required: bool, + /// Whether registration tokens are required for password registrations. pub registration_token_required: bool, diff --git a/crates/handlers/src/admin/v1/site_config.rs b/crates/handlers/src/admin/v1/site_config.rs index b9b05dac7..40a5db51a 100644 --- a/crates/handlers/src/admin/v1/site_config.rs +++ b/crates/handlers/src/admin/v1/site_config.rs @@ -22,6 +22,9 @@ pub struct SiteConfig { /// Whether password registration is enabled. pub password_registration_enabled: bool, + /// Whether a valid email address is required for password registrations. + pub password_registration_email_required: bool, + /// Whether registration tokens are required for password registrations. pub registration_token_required: bool, @@ -59,6 +62,7 @@ pub fn doc(operation: TransformOperation) -> TransformOperation { server_name: "example.com".to_owned(), password_login_enabled: true, password_registration_enabled: true, + password_registration_email_required: true, registration_token_required: true, email_change_allowed: true, displayname_change_allowed: true, @@ -80,6 +84,7 @@ pub async fn handler( server_name: site_config.server_name, password_login_enabled: site_config.password_login_enabled, password_registration_enabled: site_config.password_registration_enabled, + password_registration_email_required: site_config.password_registration_email_required, registration_token_required: site_config.registration_token_required, email_change_allowed: site_config.email_change_allowed, displayname_change_allowed: site_config.displayname_change_allowed, diff --git a/crates/handlers/src/test_utils.rs b/crates/handlers/src/test_utils.rs index a25fda9dc..fa8105763 100644 --- a/crates/handlers/src/test_utils.rs +++ b/crates/handlers/src/test_utils.rs @@ -140,6 +140,7 @@ pub fn test_site_config() -> SiteConfig { email_change_allowed: true, displayname_change_allowed: true, password_change_allowed: true, + password_registration_email_required: true, account_recovery_allowed: true, account_deactivation_allowed: true, captcha: None, diff --git a/crates/handlers/src/views/register/password.rs b/crates/handlers/src/views/register/password.rs index a9a882f68..0fc8b6a63 100644 --- a/crates/handlers/src/views/register/password.rs +++ b/crates/handlers/src/views/register/password.rs @@ -45,6 +45,7 @@ use crate::{ #[derive(Debug, Deserialize, Serialize)] pub(crate) struct RegisterForm { username: String, + #[serde(default)] email: String, password: String, password_confirm: String, @@ -165,9 +166,16 @@ pub(crate) async fn post( .await .is_ok(); + let state = form.to_form_state(); + + // The email form is only shown if the server requires it + let email = site_config + .password_registration_email_required + .then_some(form.email); + // Validate the form let state = { - let mut state = form.to_form_state(); + let mut state = state; if !passed_captcha { state.add_error_on_form(FormError::Captcha); @@ -195,13 +203,15 @@ pub(crate) async fn post( homeserver_denied_username = true; } - // Note that we don't check here if the email is already taken here, as - // we don't want to leak the information about other users. Instead, we will - // show an error message once the user confirmed their email address. - if form.email.is_empty() { - state.add_error_on_field(RegisterFormField::Email, FieldError::Required); - } else if Address::from_str(&form.email).is_err() { - state.add_error_on_field(RegisterFormField::Email, FieldError::Invalid); + if let Some(email) = &email { + // Note that we don't check here if the email is already taken here, as + // we don't want to leak the information about other users. Instead, we will + // show an error message once the user confirmed their email address. + if email.is_empty() { + state.add_error_on_field(RegisterFormField::Email, FieldError::Required); + } else if Address::from_str(email).is_err() { + state.add_error_on_field(RegisterFormField::Email, FieldError::Invalid); + } } if form.password.is_empty() { @@ -240,7 +250,7 @@ pub(crate) async fn post( .evaluate_register(mas_policy::RegisterInput { registration_method: mas_policy::RegistrationMethod::Password, username: &form.username, - email: Some(&form.email), + email: email.as_deref(), requester: mas_policy::Requester { ip_address: activity_tracker.ip(), user_agent: user_agent.clone(), @@ -295,7 +305,9 @@ pub(crate) async fn post( state.add_error_on_form(FormError::RateLimitExceeded); } - if let Err(e) = limiter.check_email_authentication_email(requester, &form.email) { + if let Some(email) = &email + && let Err(e) = limiter.check_email_authentication_email(requester, email) + { tracing::warn!(error = &e as &dyn std::error::Error); state.add_error_on_form(FormError::RateLimitExceeded); } @@ -343,25 +355,28 @@ pub(crate) async fn post( registration }; - // Create a new user email authentication session - let user_email_authentication = repo - .user_email() - .add_authentication_for_registration(&mut rng, &clock, form.email, ®istration) - .await?; + let registration = if let Some(email) = email { + // Create a new user email authentication session + let user_email_authentication = repo + .user_email() + .add_authentication_for_registration(&mut rng, &clock, email, ®istration) + .await?; - // Schedule a job to verify the email - repo.queue_job() - .schedule_job( - &mut rng, - &clock, - SendEmailAuthenticationCodeJob::new(&user_email_authentication, locale.to_string()), - ) - .await?; + // Schedule a job to verify the email + repo.queue_job() + .schedule_job( + &mut rng, + &clock, + SendEmailAuthenticationCodeJob::new(&user_email_authentication, locale.to_string()), + ) + .await?; - let registration = repo - .user_registration() - .set_email_authentication(registration, &user_email_authentication) - .await?; + repo.user_registration() + .set_email_authentication(registration, &user_email_authentication) + .await? + } else { + registration + }; // Hash the password let password = Zeroizing::new(form.password); @@ -713,4 +728,319 @@ mod tests { response.assert_status(StatusCode::OK); assert!(response.body().contains("This username is already taken")); } + + /// Test registration without email when email is not required + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_register_without_email_when_not_required(pool: PgPool) { + setup(); + let state = TestState::from_pool_with_site_config( + pool, + SiteConfig { + password_registration_email_required: false, + ..test_site_config() + }, + ) + .await + .unwrap(); + let cookies = CookieHelper::new(); + + // Render the registration page and get the CSRF token + let request = + Request::get(&*mas_router::PasswordRegister::default().path_and_query()).empty(); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + // Extract the CSRF token from the response body + let csrf_token = response + .body() + .split("name=\"csrf\" value=\"") + .nth(1) + .unwrap() + .split('\"') + .next() + .unwrap(); + + // Submit the registration form without email + let request = Request::post(&*mas_router::PasswordRegister::default().path_and_query()) + .form(serde_json::json!({ + "csrf": csrf_token, + "username": "alice", + "password": "correcthorsebatterystaple", + "password_confirm": "correcthorsebatterystaple", + "accept_terms": "on", + })); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::SEE_OTHER); + let location = response.headers().get(LOCATION).unwrap(); + + // The handler redirects with the ID as the second to last portion of the path + let id = location + .to_str() + .unwrap() + .rsplit('/') + .nth(1) + .unwrap() + .parse() + .unwrap(); + + // There should be a new registration in the database + let mut repo = state.repository().await.unwrap(); + let registration = repo.user_registration().lookup(id).await.unwrap().unwrap(); + assert_eq!(registration.username, "alice".to_owned()); + assert!(registration.password.is_some()); + // Email authentication should be None when email is not required and not + // provided + assert!(registration.email_authentication_id.is_none()); + } + + /// Test registration with valid email when email is not required + /// (email input is ignored completely when not required) + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_register_with_email_when_not_required(pool: PgPool) { + setup(); + let state = TestState::from_pool_with_site_config( + pool, + SiteConfig { + password_registration_email_required: false, + ..test_site_config() + }, + ) + .await + .unwrap(); + let cookies = CookieHelper::new(); + + // Render the registration page and get the CSRF token + let request = + Request::get(&*mas_router::PasswordRegister::default().path_and_query()).empty(); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + // Extract the CSRF token from the response body + let csrf_token = response + .body() + .split("name=\"csrf\" value=\"") + .nth(1) + .unwrap() + .split('\"') + .next() + .unwrap(); + + // Submit the registration form with valid email + let request = Request::post(&*mas_router::PasswordRegister::default().path_and_query()) + .form(serde_json::json!({ + "csrf": csrf_token, + "username": "charlie", + "email": "charlie@example.com", + "password": "correcthorsebatterystaple", + "password_confirm": "correcthorsebatterystaple", + "accept_terms": "on", + })); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::SEE_OTHER); + let location = response.headers().get(LOCATION).unwrap(); + + // The handler redirects with the ID as the second to last portion of the path + let id = location + .to_str() + .unwrap() + .rsplit('/') + .nth(1) + .unwrap() + .parse() + .unwrap(); + + // There should be a new registration in the database + let mut repo = state.repository().await.unwrap(); + let registration = repo.user_registration().lookup(id).await.unwrap().unwrap(); + assert_eq!(registration.username, "charlie".to_owned()); + assert!(registration.password.is_some()); + + // Email authentication should be None when email is not required + // (email input is completely ignored in this case) + assert!(registration.email_authentication_id.is_none()); + } + + /// Test registration fails when email is required but not provided + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_register_fails_without_email_when_required(pool: PgPool) { + setup(); + let state = TestState::from_pool_with_site_config( + pool, + SiteConfig { + password_registration_email_required: true, + ..test_site_config() + }, + ) + .await + .unwrap(); + let cookies = CookieHelper::new(); + + // Render the registration page and get the CSRF token + let request = + Request::get(&*mas_router::PasswordRegister::default().path_and_query()).empty(); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + // Extract the CSRF token from the response body + let csrf_token = response + .body() + .split("name=\"csrf\" value=\"") + .nth(1) + .unwrap() + .split('\"') + .next() + .unwrap(); + + // Submit the registration form without email + let request = Request::post(&*mas_router::PasswordRegister::default().path_and_query()) + .form(serde_json::json!({ + "csrf": csrf_token, + "username": "david", + "password": "correcthorsebatterystaple", + "password_confirm": "correcthorsebatterystaple", + "accept_terms": "on", + })); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + + // Check that the response contains an error about the email field + let body = response.body(); + assert!(body.contains("email") || body.contains("Email")); + + // Ensure no registration was created + let mut repo = state.repository().await.unwrap(); + let user_exists = repo.user().exists("david").await.unwrap(); + assert!(!user_exists); + } + + /// Test registration fails when email is required but empty + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_register_fails_with_empty_email_when_required(pool: PgPool) { + setup(); + let state = TestState::from_pool_with_site_config( + pool, + SiteConfig { + password_registration_email_required: true, + ..test_site_config() + }, + ) + .await + .unwrap(); + let cookies = CookieHelper::new(); + + // Render the registration page and get the CSRF token + let request = + Request::get(&*mas_router::PasswordRegister::default().path_and_query()).empty(); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + // Extract the CSRF token from the response body + let csrf_token = response + .body() + .split("name=\"csrf\" value=\"") + .nth(1) + .unwrap() + .split('\"') + .next() + .unwrap(); + + // Submit the registration form with empty email + let request = Request::post(&*mas_router::PasswordRegister::default().path_and_query()) + .form(serde_json::json!({ + "csrf": csrf_token, + "username": "eve", + "email": "", + "password": "correcthorsebatterystaple", + "password_confirm": "correcthorsebatterystaple", + "accept_terms": "on", + })); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + + // Check that the response contains an error about the email field + let body = response.body(); + assert!(body.contains("email") || body.contains("Email")); + + // Ensure no registration was created + let mut repo = state.repository().await.unwrap(); + let user_exists = repo.user().exists("eve").await.unwrap(); + assert!(!user_exists); + } + + /// Test registration fails with invalid email when email is required + #[sqlx::test(migrator = "mas_storage_pg::MIGRATOR")] + async fn test_register_fails_with_invalid_email_when_required(pool: PgPool) { + setup(); + let state = TestState::from_pool_with_site_config( + pool, + SiteConfig { + password_registration_email_required: true, + ..test_site_config() + }, + ) + .await + .unwrap(); + let cookies = CookieHelper::new(); + + // Render the registration page and get the CSRF token + let request = + Request::get(&*mas_router::PasswordRegister::default().path_and_query()).empty(); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + // Extract the CSRF token from the response body + let csrf_token = response + .body() + .split("name=\"csrf\" value=\"") + .nth(1) + .unwrap() + .split('\"') + .next() + .unwrap(); + + // Submit the registration form with invalid email + let request = Request::post(&*mas_router::PasswordRegister::default().path_and_query()) + .form(serde_json::json!({ + "csrf": csrf_token, + "username": "grace", + "email": "not-an-email", + "password": "correcthorsebatterystaple", + "password_confirm": "correcthorsebatterystaple", + "accept_terms": "on", + })); + let request = cookies.with_cookies(request); + let response = state.request(request).await; + cookies.save_cookies(&response); + response.assert_status(StatusCode::OK); + response.assert_header_value(CONTENT_TYPE, "text/html; charset=utf-8"); + + // Check that the response contains an error about the email field + let body = response.body(); + assert!(body.contains("email") || body.contains("Email")); + + // Ensure no registration was created + let mut repo = state.repository().await.unwrap(); + let user_exists = repo.user().exists("grace").await.unwrap(); + assert!(!user_exists); + } } diff --git a/crates/handlers/src/views/register/steps/finish.rs b/crates/handlers/src/views/register/steps/finish.rs index de7a537b5..e1ed8a3f0 100644 --- a/crates/handlers/src/views/register/steps/finish.rs +++ b/crates/handlers/src/views/register/steps/finish.rs @@ -151,52 +151,62 @@ pub(crate) async fn get( None }; - // For now, we require an email address on the registration, but this might - // change in the future - let email_authentication_id = registration - .email_authentication_id - .context("No email authentication started for this registration") - .map_err(InternalError::from_anyhow)?; - let email_authentication = repo - .user_email() - .lookup_authentication(email_authentication_id) - .await? - .context("Could not load the email authentication") - .map_err(InternalError::from_anyhow)?; - - // Check that the email authentication has been completed - if email_authentication.completed_at.is_none() { - return Ok(( - cookie_jar, - url_builder.redirect(&mas_router::RegisterVerifyEmail::new(id)), - ) - .into_response()); - } - - // Check that the email address isn't already used - // It is important to do that here, as we we're not checking during the - // registration, because we don't want to disclose whether an email is - // already being used or not before we verified it - if repo - .user_email() - .count(UserEmailFilter::new().for_email(&email_authentication.email)) - .await? - > 0 + // If there is an email authentication, we need to check that the email + // address was verified. If there is no email authentication attached, we + // need to make sure the server doesn't require it + let email_authentication = if let Some(email_authentication_id) = + registration.email_authentication_id { - let action = registration - .post_auth_action - .map(serde_json::from_value) - .transpose()?; + let email_authentication = repo + .user_email() + .lookup_authentication(email_authentication_id) + .await? + .context("Could not load the email authentication") + .map_err(InternalError::from_anyhow)?; - let ctx = RegisterStepsEmailInUseContext::new(email_authentication.email, action) - .with_language(lang); + // Check that the email authentication has been completed + if email_authentication.completed_at.is_none() { + return Ok(( + cookie_jar, + url_builder.redirect(&mas_router::RegisterVerifyEmail::new(id)), + ) + .into_response()); + } - return Ok(( - cookie_jar, - Html(templates.render_register_steps_email_in_use(&ctx)?), - ) - .into_response()); - } + // Check that the email address isn't already used + // It is important to do that here, as we we're not checking during the + // registration, because we don't want to disclose whether an email is + // already being used or not before we verified it + if repo + .user_email() + .count(UserEmailFilter::new().for_email(&email_authentication.email)) + .await? + > 0 + { + let action = registration + .post_auth_action + .map(serde_json::from_value) + .transpose()?; + + let ctx = RegisterStepsEmailInUseContext::new(email_authentication.email, action) + .with_language(lang); + + return Ok(( + cookie_jar, + Html(templates.render_register_steps_email_in_use(&ctx)?), + ) + .into_response()); + } + + Some(email_authentication) + } else if site_config.password_registration_email_required { + // This could only happen in theory during a configuration change + return Err(InternalError::from_anyhow(anyhow::anyhow!( + "Server requires an email address to complete the registration, but no email authentication was attached to the user registration" + ))); + } else { + None + }; // Check that the display name is set if registration.display_name.is_none() { @@ -236,9 +246,11 @@ pub(crate) async fn get( .add(&mut rng, &clock, &user, user_agent) .await?; - repo.user_email() - .add(&mut rng, &clock, &user, email_authentication.email) - .await?; + if let Some(email_authentication) = email_authentication { + repo.user_email() + .add(&mut rng, &clock, &user, email_authentication.email) + .await?; + } if let Some(password) = registration.password { let user_password = repo diff --git a/crates/templates/src/context/ext.rs b/crates/templates/src/context/ext.rs index e4ae3886c..679ad91a7 100644 --- a/crates/templates/src/context/ext.rs +++ b/crates/templates/src/context/ext.rs @@ -45,6 +45,7 @@ impl SiteConfigExt for SiteConfig { fn templates_features(&self) -> SiteFeatures { SiteFeatures { password_registration: self.password_registration_enabled, + password_registration_email_required: self.password_registration_email_required, password_login: self.password_login_enabled, account_recovery: self.account_recovery_allowed, login_with_email_allowed: self.login_with_email_allowed, diff --git a/crates/templates/src/context/features.rs b/crates/templates/src/context/features.rs index d514b5c63..07e80f702 100644 --- a/crates/templates/src/context/features.rs +++ b/crates/templates/src/context/features.rs @@ -18,6 +18,9 @@ pub struct SiteFeatures { /// Whether local password-based registration is enabled. pub password_registration: bool, + /// Whether local password-based registration requires an email address. + pub password_registration_email_required: bool, + /// Whether local password-based login is enabled. pub password_login: bool, @@ -32,6 +35,9 @@ impl Object for SiteFeatures { fn get_value(self: &Arc, field: &Value) -> Option { match field.as_str()? { "password_registration" => Some(Value::from(self.password_registration)), + "password_registration_email_required" => { + Some(Value::from(self.password_registration_email_required)) + } "password_login" => Some(Value::from(self.password_login)), "account_recovery" => Some(Value::from(self.account_recovery)), "login_with_email_allowed" => Some(Value::from(self.login_with_email_allowed)), @@ -42,6 +48,7 @@ impl Object for SiteFeatures { fn enumerate(self: &Arc) -> Enumerator { Enumerator::Str(&[ "password_registration", + "password_registration_email_required", "password_login", "account_recovery", "login_with_email_allowed", diff --git a/crates/templates/src/lib.rs b/crates/templates/src/lib.rs index 1c0bef423..bb208eb44 100644 --- a/crates/templates/src/lib.rs +++ b/crates/templates/src/lib.rs @@ -509,6 +509,7 @@ mod tests { let features = SiteFeatures { password_login: true, password_registration: true, + password_registration_email_required: true, account_recovery: true, login_with_email_allowed: true, }; diff --git a/docs/api/spec.json b/docs/api/spec.json index 74e42f734..d0e4c7e54 100644 --- a/docs/api/spec.json +++ b/docs/api/spec.json @@ -35,6 +35,7 @@ "server_name": "example.com", "password_login_enabled": true, "password_registration_enabled": true, + "password_registration_email_required": true, "registration_token_required": true, "email_change_allowed": true, "displayname_change_allowed": true, @@ -3680,6 +3681,7 @@ "minimum_password_complexity", "password_change_allowed", "password_login_enabled", + "password_registration_email_required", "password_registration_enabled", "registration_token_required", "server_name" @@ -3697,6 +3699,10 @@ "description": "Whether password registration is enabled.", "type": "boolean" }, + "password_registration_email_required": { + "description": "Whether a valid email address is required for password registrations.", + "type": "boolean" + }, "registration_token_required": { "description": "Whether registration tokens are required for password registrations.", "type": "boolean" diff --git a/docs/config.schema.json b/docs/config.schema.json index ada9005c7..524f02c93 100644 --- a/docs/config.schema.json +++ b/docs/config.schema.json @@ -2604,6 +2604,10 @@ "description": "Whether to enable self-service password registration. Defaults to `false` if password authentication is enabled.\n\nThis has no effect if password login is disabled.", "type": "boolean" }, + "password_registration_email_required": { + "description": "Whether self-service password registrations require a valid email. Defaults to `true`.\n\nThis has no effect if password registration is disabled.", + "type": "boolean" + }, "password_change_allowed": { "description": "Whether users are allowed to change their passwords. Defaults to `true`.\n\nThis has no effect if password login is disabled.", "type": "boolean" diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index b292aa332..c5b69e38f 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -296,6 +296,12 @@ account: # This has no effect if password login is disabled. password_registration_enabled: false + # Whether self-service registrations require a valid email + # + # Defaults to `true` + # This has no effect if password registration is disabled. + password_registration_email_required: true + # Whether users are allowed to change their passwords # # Defaults to `true`. @@ -759,7 +765,7 @@ upstream_oauth2: localpart: #action: force #template: "{{ user.preferred_username }}" - + # How to handle when localpart already exists. # Possible values are (default: fail): # - `add` : Adds the upstream account link to the existing user, regardless of whether there is an existing link or not. diff --git a/policies/register/register.rego b/policies/register/register.rego index 34428741a..89002a075 100644 --- a/policies/register/register.rego +++ b/policies/register/register.rego @@ -81,13 +81,6 @@ violation contains {"msg": sprintf( common.requester_banned(input.requester, data.requester) } -# Check that we supplied an email for password registration -violation contains {"field": "email", "msg": "email required for password-based registration"} if { - input.registration_method == "password" - - not input.email -} - # Check if the email is valid using the email policy # and add the email field to the violation object violation contains object.union({"field": "email"}, v) if { diff --git a/policies/register/register_test.rego b/policies/register/register_test.rego index 6cb324b77..a01946bbb 100644 --- a/policies/register/register_test.rego +++ b/policies/register/register_test.rego @@ -39,11 +39,8 @@ test_banned_subdomain if { with data.banned_domains as ["staging.element.io"] } -test_email_required if { - not register.allow with input as {"username": "hello", "registration_method": "password"} -} - test_no_email if { + register.allow with input as {"username": "hello", "registration_method": "password"} register.allow with input as {"username": "hello", "registration_method": "upstream-oauth2"} } diff --git a/templates/pages/register/index.html b/templates/pages/register/index.html index 21c14cdc7..5115b7bbb 100644 --- a/templates/pages/register/index.html +++ b/templates/pages/register/index.html @@ -41,7 +41,11 @@ Please see LICENSE files in the repository root for full details. {% endfor %} {% if features.password_registration %} - {{ button.button(text=_("mas.register.continue_with_email")) }} + {% if features.password_registration_email_required %} + {{ button.button(text=_("mas.register.continue_with_email")) }} + {% else %} + {{ button.button(text=_("mas.register.continue_with_password")) }} + {% endif %} {% endif %} {% if providers %} diff --git a/templates/pages/register/password.html b/templates/pages/register/password.html index 5178445de..f6f7a924f 100644 --- a/templates/pages/register/password.html +++ b/templates/pages/register/password.html @@ -35,9 +35,11 @@ Please see LICENSE files in the repository root for full details. {% endcall %} - {% call(f) field.field(label=_("common.email_address"), name="email", form_state=form) %} - - {% endcall %} + {% if features.password_registration_email_required %} + {% call(f) field.field(label=_("common.email_address"), name="email", form_state=form) %} + + {% endcall %} + {% endif %} {% call(f) field.field(label=_("common.password"), name="password", form_state=form) %} diff --git a/translations/en.json b/translations/en.json index 0d263fb55..8e800b0e1 100644 --- a/translations/en.json +++ b/translations/en.json @@ -10,7 +10,7 @@ }, "continue": "Continue", "@continue": { - "context": "form_post.html:25:28-48, pages/consent.html:57:28-48, pages/device_consent.html:124:13-33, pages/device_link.html:40:26-46, pages/login.html:68:30-50, pages/reauth.html:32:28-48, pages/recovery/start.html:38:26-46, pages/register/password.html:74:26-46, pages/register/steps/display_name.html:43:28-48, pages/register/steps/registration_token.html:41:28-48, pages/register/steps/verify_email.html:51:26-46, pages/sso.html:37:28-48" + "context": "form_post.html:25:28-48, pages/consent.html:57:28-48, pages/device_consent.html:124:13-33, pages/device_link.html:40:26-46, pages/login.html:68:30-50, pages/reauth.html:32:28-48, pages/recovery/start.html:38:26-46, pages/register/password.html:76:26-46, pages/register/steps/display_name.html:43:28-48, pages/register/steps/registration_token.html:41:28-48, pages/register/steps/verify_email.html:51:26-46, pages/sso.html:37:28-48" }, "create_account": "Create Account", "@create_account": { @@ -79,7 +79,7 @@ }, "email_address": "Email address", "@email_address": { - "context": "pages/recovery/start.html:34:33-58, pages/register/password.html:38:33-58, pages/upstream_oauth2/do_register.html:114:37-62" + "context": "pages/recovery/start.html:34:33-58, pages/register/password.html:39:35-60, pages/upstream_oauth2/do_register.html:114:37-62" }, "loading": "Loading…", "@loading": { @@ -91,11 +91,11 @@ }, "password": "Password", "@password": { - "context": "pages/login.html:56:37-57, pages/reauth.html:28:35-55, pages/register/password.html:42:33-53" + "context": "pages/login.html:56:37-57, pages/reauth.html:28:35-55, pages/register/password.html:44:33-53" }, "password_confirm": "Confirm password", "@password_confirm": { - "context": "pages/register/password.html:46:33-61" + "context": "pages/register/password.html:48:33-61" }, "username": "Username", "@username": { @@ -423,7 +423,7 @@ }, "continue_with_provider": "Continue with %(provider)s", "@continue_with_provider": { - "context": "pages/login.html:81:15-67, pages/register/index.html:53:15-67", + "context": "pages/login.html:81:15-67, pages/register/index.html:57:15-67", "description": "Button to log in with an upstream provider" }, "description": "Please sign in to continue:", @@ -613,12 +613,16 @@ "register": { "call_to_login": "Already have an account?", "@call_to_login": { - "context": "pages/register/index.html:59:35-66, pages/register/password.html:77:33-64", + "context": "pages/register/index.html:63:35-66, pages/register/password.html:79:33-64", "description": "Displayed on the registration page to suggest to log in instead" }, "continue_with_email": "Continue with email address", "@continue_with_email": { - "context": "pages/register/index.html:44:30-67" + "context": "pages/register/index.html:45:32-69" + }, + "continue_with_password": "Continue with password", + "@continue_with_password": { + "context": "pages/register/index.html:47:32-72" }, "create_account": { "description": "Choose a username to continue.", @@ -632,7 +636,7 @@ }, "terms_of_service": "I agree to the Terms and Conditions", "@terms_of_service": { - "context": "pages/register/password.html:51:35-95, pages/upstream_oauth2/do_register.html:179:35-95" + "context": "pages/register/password.html:53:35-95, pages/upstream_oauth2/do_register.html:179:35-95" } }, "registration_token": { From 8ca8d878e77cdfa7a49c209fcecc47dac5ecde06 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Thu, 2 Oct 2025 14:34:34 +0100 Subject: [PATCH 132/296] Add personal access token and session storage --- Cargo.lock | 1 + ...56577d98074e244a35c0d3be24bc18d9d0daa.json | 15 ++ ...63aa46225245a04d1c7bc24b5275c44a6d58d.json | 15 ++ ...7a18ff07e0b5cd08cc525ac9d5dcceece7311.json | 70 ++++++ ...6f5c701411387c939f6b8a3478b41b3de4f20.json | 46 ++++ ...7e260ba8911123744980e24a52bc9b95bd056.json | 18 ++ ...f063537d5a7f13c48d031367c1d8dba2f8af5.json | 19 ++ ...e1ef2f192ca66f8000d1385626154e5ce4f7e.json | 46 ++++ crates/storage-pg/Cargo.toml | 1 + crates/storage-pg/src/lib.rs | 1 + .../storage-pg/src/personal/access_token.rs | 216 +++++++++++++++++ crates/storage-pg/src/personal/mod.rs | 13 ++ crates/storage-pg/src/personal/session.rs | 218 ++++++++++++++++++ crates/storage-pg/src/repository.rs | 15 ++ crates/storage/src/lib.rs | 1 + crates/storage/src/personal/access_token.rs | 119 ++++++++++ crates/storage/src/personal/mod.rs | 13 ++ crates/storage/src/personal/session.rs | 101 ++++++++ crates/storage/src/repository.rs | 39 ++++ 19 files changed, 967 insertions(+) create mode 100644 crates/storage-pg/.sqlx/query-06d67595eeef23d5f2773632e0956577d98074e244a35c0d3be24bc18d9d0daa.json create mode 100644 crates/storage-pg/.sqlx/query-0e45995714e60b71e0f0158500a63aa46225245a04d1c7bc24b5275c44a6d58d.json create mode 100644 crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json create mode 100644 crates/storage-pg/.sqlx/query-90875bdd2f75cdf0dc3f48dc2516f5c701411387c939f6b8a3478b41b3de4f20.json create mode 100644 crates/storage-pg/.sqlx/query-a0be6c56e470382b9470df414497e260ba8911123744980e24a52bc9b95bd056.json create mode 100644 crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json create mode 100644 crates/storage-pg/.sqlx/query-e1746b33c2f0d10f26332195f78e1ef2f192ca66f8000d1385626154e5ce4f7e.json create mode 100644 crates/storage-pg/src/personal/access_token.rs create mode 100644 crates/storage-pg/src/personal/mod.rs create mode 100644 crates/storage-pg/src/personal/session.rs create mode 100644 crates/storage/src/personal/access_token.rs create mode 100644 crates/storage/src/personal/mod.rs create mode 100644 crates/storage/src/personal/session.rs diff --git a/Cargo.lock b/Cargo.lock index 253308775..67e00137b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3676,6 +3676,7 @@ dependencies = [ "sea-query", "sea-query-binder", "serde_json", + "sha2", "sqlx", "thiserror 2.0.17", "tracing", diff --git a/crates/storage-pg/.sqlx/query-06d67595eeef23d5f2773632e0956577d98074e244a35c0d3be24bc18d9d0daa.json b/crates/storage-pg/.sqlx/query-06d67595eeef23d5f2773632e0956577d98074e244a35c0d3be24bc18d9d0daa.json new file mode 100644 index 000000000..55509569c --- /dev/null +++ b/crates/storage-pg/.sqlx/query-06d67595eeef23d5f2773632e0956577d98074e244a35c0d3be24bc18d9d0daa.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE personal_sessions\n SET revoked_at = $2\n WHERE personal_session_id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "06d67595eeef23d5f2773632e0956577d98074e244a35c0d3be24bc18d9d0daa" +} diff --git a/crates/storage-pg/.sqlx/query-0e45995714e60b71e0f0158500a63aa46225245a04d1c7bc24b5275c44a6d58d.json b/crates/storage-pg/.sqlx/query-0e45995714e60b71e0f0158500a63aa46225245a04d1c7bc24b5275c44a6d58d.json new file mode 100644 index 000000000..5bba6548d --- /dev/null +++ b/crates/storage-pg/.sqlx/query-0e45995714e60b71e0f0158500a63aa46225245a04d1c7bc24b5275c44a6d58d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE personal_access_tokens\n SET revoked_at = $2\n WHERE personal_access_token_id = $1\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "0e45995714e60b71e0f0158500a63aa46225245a04d1c7bc24b5275c44a6d58d" +} diff --git a/crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json b/crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json new file mode 100644 index 000000000..d7eb2c798 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json @@ -0,0 +1,70 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT personal_session_id\n , owner_user_id\n , actor_user_id\n , scope_list\n , created_at\n , revoked_at\n , human_name\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM personal_sessions\n\n WHERE personal_session_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "personal_session_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "owner_user_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "actor_user_id", + "type_info": "Uuid" + }, + { + "ordinal": 3, + "name": "scope_list", + "type_info": "TextArray" + }, + { + "ordinal": 4, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 5, + "name": "revoked_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 6, + "name": "human_name", + "type_info": "Text" + }, + { + "ordinal": 7, + "name": "last_active_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 8, + "name": "last_active_ip: IpAddr", + "type_info": "Inet" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + false, + true, + true + ] + }, + "hash": "8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311" +} diff --git a/crates/storage-pg/.sqlx/query-90875bdd2f75cdf0dc3f48dc2516f5c701411387c939f6b8a3478b41b3de4f20.json b/crates/storage-pg/.sqlx/query-90875bdd2f75cdf0dc3f48dc2516f5c701411387c939f6b8a3478b41b3de4f20.json new file mode 100644 index 000000000..66aab4ee6 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-90875bdd2f75cdf0dc3f48dc2516f5c701411387c939f6b8a3478b41b3de4f20.json @@ -0,0 +1,46 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT personal_access_token_id\n , personal_session_id\n , created_at\n , expires_at\n , revoked_at\n\n FROM personal_access_tokens\n\n WHERE access_token_sha256 = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "personal_access_token_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "personal_session_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "expires_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "revoked_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false, + false, + false, + true, + true + ] + }, + "hash": "90875bdd2f75cdf0dc3f48dc2516f5c701411387c939f6b8a3478b41b3de4f20" +} diff --git a/crates/storage-pg/.sqlx/query-a0be6c56e470382b9470df414497e260ba8911123744980e24a52bc9b95bd056.json b/crates/storage-pg/.sqlx/query-a0be6c56e470382b9470df414497e260ba8911123744980e24a52bc9b95bd056.json new file mode 100644 index 000000000..3542f8481 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-a0be6c56e470382b9470df414497e260ba8911123744980e24a52bc9b95bd056.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO personal_access_tokens\n (personal_access_token_id, personal_session_id, access_token_sha256, created_at, expires_at)\n VALUES ($1, $2, $3, $4, $5)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid", + "Bytea", + "Timestamptz", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "a0be6c56e470382b9470df414497e260ba8911123744980e24a52bc9b95bd056" +} diff --git a/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json b/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json new file mode 100644 index 000000000..9dec975ca --- /dev/null +++ b/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json @@ -0,0 +1,19 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO personal_sessions\n ( personal_session_id\n , owner_user_id\n , actor_user_id\n , human_name\n , scope_list\n , created_at\n )\n VALUES ($1, $2, $3, $4, $5, $6)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid", + "Uuid", + "Text", + "TextArray", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5" +} diff --git a/crates/storage-pg/.sqlx/query-e1746b33c2f0d10f26332195f78e1ef2f192ca66f8000d1385626154e5ce4f7e.json b/crates/storage-pg/.sqlx/query-e1746b33c2f0d10f26332195f78e1ef2f192ca66f8000d1385626154e5ce4f7e.json new file mode 100644 index 000000000..2112e7603 --- /dev/null +++ b/crates/storage-pg/.sqlx/query-e1746b33c2f0d10f26332195f78e1ef2f192ca66f8000d1385626154e5ce4f7e.json @@ -0,0 +1,46 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT personal_access_token_id\n , personal_session_id\n , created_at\n , expires_at\n , revoked_at\n\n FROM personal_access_tokens\n\n WHERE personal_access_token_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "personal_access_token_id", + "type_info": "Uuid" + }, + { + "ordinal": 1, + "name": "personal_session_id", + "type_info": "Uuid" + }, + { + "ordinal": 2, + "name": "created_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 3, + "name": "expires_at", + "type_info": "Timestamptz" + }, + { + "ordinal": 4, + "name": "revoked_at", + "type_info": "Timestamptz" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false, + false, + false, + true, + true + ] + }, + "hash": "e1746b33c2f0d10f26332195f78e1ef2f192ca66f8000d1385626154e5ce4f7e" +} diff --git a/crates/storage-pg/Cargo.toml b/crates/storage-pg/Cargo.toml index 149e92fc6..8710ead70 100644 --- a/crates/storage-pg/Cargo.toml +++ b/crates/storage-pg/Cargo.toml @@ -27,6 +27,7 @@ rand.workspace = true sea-query-binder.workspace = true sea-query.workspace = true serde_json.workspace = true +sha2.workspace = true sqlx.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/storage-pg/src/lib.rs b/crates/storage-pg/src/lib.rs index 908058df6..207235667 100644 --- a/crates/storage-pg/src/lib.rs +++ b/crates/storage-pg/src/lib.rs @@ -165,6 +165,7 @@ use sqlx::migrate::Migrator; pub mod app_session; pub mod compat; pub mod oauth2; +pub mod personal; pub mod queue; pub mod upstream_oauth2; pub mod user; diff --git a/crates/storage-pg/src/personal/access_token.rs b/crates/storage-pg/src/personal/access_token.rs new file mode 100644 index 000000000..832e867f5 --- /dev/null +++ b/crates/storage-pg/src/personal/access_token.rs @@ -0,0 +1,216 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use mas_data_model::{ + Clock, + personal::{PersonalAccessToken, session::PersonalSession}, +}; +use mas_storage::personal::PersonalAccessTokenRepository; +use rand::RngCore; +use sha2::{Digest, Sha256}; +use sqlx::PgConnection; +use ulid::Ulid; +use uuid::Uuid; + +use crate::{DatabaseError, tracing::ExecuteExt as _}; + +/// An implementation of [`PersonalAccessTokenRepository`] for a PostgreSQL +/// connection +pub struct PgPersonalAccessTokenRepository<'c> { + conn: &'c mut PgConnection, +} + +impl<'c> PgPersonalAccessTokenRepository<'c> { + /// Create a new [`PgPersonalAccessTokenRepository`] from an active + /// PostgreSQL connection + pub fn new(conn: &'c mut PgConnection) -> Self { + Self { conn } + } +} + +struct PersonalAccessTokenLookup { + personal_access_token_id: Uuid, + personal_session_id: Uuid, + created_at: DateTime, + expires_at: Option>, + revoked_at: Option>, +} + +impl From for PersonalAccessToken { + fn from(value: PersonalAccessTokenLookup) -> Self { + Self { + id: Ulid::from(value.personal_access_token_id), + session_id: Ulid::from(value.personal_session_id), + created_at: value.created_at, + expires_at: value.expires_at, + revoked_at: value.revoked_at, + } + } +} + +#[async_trait] +impl PersonalAccessTokenRepository for PgPersonalAccessTokenRepository<'_> { + type Error = DatabaseError; + + #[tracing::instrument( + name = "db.personal_access_token.lookup", + skip_all, + fields( + db.query.text, + personal_access_token.id = %id, + ), + err, + )] + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error> { + let res = sqlx::query_as!( + PersonalAccessTokenLookup, + r#" + SELECT personal_access_token_id + , personal_session_id + , created_at + , expires_at + , revoked_at + + FROM personal_access_tokens + + WHERE personal_access_token_id = $1 + "#, + Uuid::from(id), + ) + .traced() + .fetch_optional(&mut *self.conn) + .await?; + + let Some(res) = res else { return Ok(None) }; + + Ok(Some(res.into())) + } + + #[tracing::instrument( + name = "db.personal_access_token.find_by_token", + skip_all, + fields( + db.query.text, + ), + err, + )] + async fn find_by_token( + &mut self, + access_token: &str, + ) -> Result, Self::Error> { + let token_sha256 = Sha256::digest(access_token.as_bytes()).to_vec(); + + let res = sqlx::query_as!( + PersonalAccessTokenLookup, + r#" + SELECT personal_access_token_id + , personal_session_id + , created_at + , expires_at + , revoked_at + + FROM personal_access_tokens + + WHERE access_token_sha256 = $1 + "#, + &token_sha256, + ) + .traced() + .fetch_optional(&mut *self.conn) + .await?; + + let Some(res) = res else { return Ok(None) }; + + Ok(Some(res.into())) + } + + #[tracing::instrument( + name = "db.personal_access_token.add", + skip_all, + fields( + db.query.text, + personal_access_token.id, + %session.id, + ), + err, + )] + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + session: &PersonalSession, + access_token: String, + expires_after: Option, + ) -> Result { + let created_at = clock.now(); + let id = Ulid::from_datetime_with_source(created_at.into(), rng); + tracing::Span::current().record("personal_access_token.id", tracing::field::display(id)); + + let token_sha256 = Sha256::digest(access_token.as_bytes()).to_vec(); + + let expires_at = expires_after.map(|expires_after| created_at + expires_after); + + sqlx::query!( + r#" + INSERT INTO personal_access_tokens + (personal_access_token_id, personal_session_id, access_token_sha256, created_at, expires_at) + VALUES ($1, $2, $3, $4, $5) + "#, + Uuid::from(id), + Uuid::from(session.id), + &token_sha256, + created_at, + expires_at, + ) + .traced() + .execute(&mut *self.conn) + .await?; + + Ok(PersonalAccessToken { + id, + session_id: session.id, + created_at, + expires_at, + revoked_at: None, + }) + } + + #[tracing::instrument( + name = "db.personal_access_token.revoke", + skip_all, + fields( + db.query.text, + %access_token.id, + personal_session.id = %access_token.session_id, + ), + err, + )] + async fn revoke( + &mut self, + clock: &dyn Clock, + mut access_token: PersonalAccessToken, + ) -> Result { + let revoked_at = clock.now(); + let res = sqlx::query!( + r#" + UPDATE personal_access_tokens + SET revoked_at = $2 + WHERE personal_access_token_id = $1 + "#, + Uuid::from(access_token.id), + revoked_at, + ) + .traced() + .execute(&mut *self.conn) + .await?; + + DatabaseError::ensure_affected_rows(&res, 1)?; + + access_token.revoked_at = Some(revoked_at); + Ok(access_token) + } +} diff --git a/crates/storage-pg/src/personal/mod.rs b/crates/storage-pg/src/personal/mod.rs new file mode 100644 index 000000000..e60daccc4 --- /dev/null +++ b/crates/storage-pg/src/personal/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +//! A module containing the PostgreSQL implementations of the +//! Personal Access Token / Personal Session repositories + +mod access_token; +mod session; + +pub use access_token::PgPersonalAccessTokenRepository; +pub use session::PgPersonalSessionRepository; diff --git a/crates/storage-pg/src/personal/session.rs b/crates/storage-pg/src/personal/session.rs new file mode 100644 index 000000000..514293ba9 --- /dev/null +++ b/crates/storage-pg/src/personal/session.rs @@ -0,0 +1,218 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use std::net::IpAddr; + +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use mas_data_model::{ + Clock, User, + personal::session::{PersonalSession, SessionState}, +}; +use mas_storage::personal::PersonalSessionRepository; +use oauth2_types::scope::Scope; +use rand::RngCore; +use sqlx::PgConnection; +use ulid::Ulid; +use uuid::Uuid; + +use crate::{DatabaseError, errors::DatabaseInconsistencyError, tracing::ExecuteExt as _}; + +/// An implementation of [`PersonalSessionRepository`] for a PostgreSQL +/// connection +pub struct PgPersonalSessionRepository<'c> { + conn: &'c mut PgConnection, +} + +impl<'c> PgPersonalSessionRepository<'c> { + /// Create a new [`PgOAuth2SessionRepository`] from an active PostgreSQL + /// connection + pub fn new(conn: &'c mut PgConnection) -> Self { + Self { conn } + } +} + +struct PersonalSessionLookup { + personal_session_id: Uuid, + owner_user_id: Uuid, + actor_user_id: Uuid, + human_name: String, + scope_list: Vec, + created_at: DateTime, + revoked_at: Option>, + last_active_at: Option>, + last_active_ip: Option, +} + +impl TryFrom for PersonalSession { + type Error = DatabaseInconsistencyError; + + fn try_from(value: PersonalSessionLookup) -> Result { + let id = Ulid::from(value.personal_session_id); + let scope: Result = value.scope_list.iter().map(|s| s.parse()).collect(); + let scope = scope.map_err(|e| { + DatabaseInconsistencyError::on("personal_sessions") + .column("scope") + .row(id) + .source(e) + })?; + + let state = match value.revoked_at { + None => SessionState::Valid, + Some(revoked_at) => SessionState::Revoked { revoked_at }, + }; + + Ok(PersonalSession { + id, + state, + owner_user_id: Ulid::from(value.owner_user_id), + actor_user_id: Ulid::from(value.actor_user_id), + human_name: value.human_name, + scope, + created_at: value.created_at, + last_active_at: value.last_active_at, + last_active_ip: value.last_active_ip, + }) + } +} + +#[async_trait] +impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { + type Error = DatabaseError; + + #[tracing::instrument( + name = "db.personal_session.lookup", + skip_all, + fields( + db.query.text, + session.id = %id, + ), + err, + )] + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error> { + let res = sqlx::query_as!( + PersonalSessionLookup, + r#" + SELECT personal_session_id + , owner_user_id + , actor_user_id + , scope_list + , created_at + , revoked_at + , human_name + , last_active_at + , last_active_ip as "last_active_ip: IpAddr" + FROM personal_sessions + + WHERE personal_session_id = $1 + "#, + Uuid::from(id), + ) + .traced() + .fetch_optional(&mut *self.conn) + .await?; + + let Some(session) = res else { return Ok(None) }; + + Ok(Some(session.try_into()?)) + } + + #[tracing::instrument( + name = "db.personal_session.add", + skip_all, + fields( + db.query.text, + session.id, + session.scope = %scope, + ), + err, + )] + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + owner_user: &User, + actor_user: &User, + human_name: String, + scope: Scope, + ) -> Result { + let created_at = clock.now(); + let id = Ulid::from_datetime_with_source(created_at.into(), rng); + tracing::Span::current().record("session.id", tracing::field::display(id)); + + let scope_list: Vec = scope.iter().map(|s| s.as_str().to_owned()).collect(); + + sqlx::query!( + r#" + INSERT INTO personal_sessions + ( personal_session_id + , owner_user_id + , actor_user_id + , human_name + , scope_list + , created_at + ) + VALUES ($1, $2, $3, $4, $5, $6) + "#, + Uuid::from(id), + Uuid::from(owner_user.id), + Uuid::from(actor_user.id), + &human_name, + &scope_list, + created_at, + ) + .traced() + .execute(&mut *self.conn) + .await?; + + Ok(PersonalSession { + id, + state: SessionState::Valid, + owner_user_id: owner_user.id, + actor_user_id: actor_user.id, + human_name, + scope, + created_at, + last_active_at: None, + last_active_ip: None, + }) + } + + #[tracing::instrument( + name = "db.personal_session.revoke", + skip_all, + fields( + db.query.text, + %session.id, + %session.scope, + ), + err, + )] + async fn revoke( + &mut self, + clock: &dyn Clock, + session: PersonalSession, + ) -> Result { + let finished_at = clock.now(); + let res = sqlx::query!( + r#" + UPDATE personal_sessions + SET revoked_at = $2 + WHERE personal_session_id = $1 + "#, + Uuid::from(session.id), + finished_at, + ) + .traced() + .execute(&mut *self.conn) + .await?; + + DatabaseError::ensure_affected_rows(&res, 1)?; + + session + .finish(finished_at) + .map_err(DatabaseError::to_invalid_operation) + } +} diff --git a/crates/storage-pg/src/repository.rs b/crates/storage-pg/src/repository.rs index 7911cd2b6..210d66a02 100644 --- a/crates/storage-pg/src/repository.rs +++ b/crates/storage-pg/src/repository.rs @@ -20,6 +20,7 @@ use mas_storage::{ OAuth2AccessTokenRepository, OAuth2AuthorizationGrantRepository, OAuth2ClientRepository, OAuth2DeviceCodeGrantRepository, OAuth2RefreshTokenRepository, OAuth2SessionRepository, }, + personal::PersonalSessionRepository, policy_data::PolicyDataRepository, queue::{QueueJobRepository, QueueScheduleRepository, QueueWorkerRepository}, upstream_oauth2::{ @@ -47,6 +48,7 @@ use crate::{ PgOAuth2ClientRepository, PgOAuth2DeviceCodeGrantRepository, PgOAuth2RefreshTokenRepository, PgOAuth2SessionRepository, }, + personal::{PgPersonalAccessTokenRepository, PgPersonalSessionRepository}, policy_data::PgPolicyDataRepository, queue::{ job::PgQueueJobRepository, schedule::PgQueueScheduleRepository, @@ -328,6 +330,19 @@ where Box::new(PgCompatRefreshTokenRepository::new(self.conn.as_mut())) } + fn personal_access_token<'c>( + &'c mut self, + ) -> Box + 'c> + { + Box::new(PgPersonalAccessTokenRepository::new(self.conn.as_mut())) + } + + fn personal_session<'c>( + &'c mut self, + ) -> Box + 'c> { + Box::new(PgPersonalSessionRepository::new(self.conn.as_mut())) + } + fn queue_worker<'c>(&'c mut self) -> Box + 'c> { Box::new(PgQueueWorkerRepository::new(self.conn.as_mut())) } diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index 605dea279..7a19f05ac 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -111,6 +111,7 @@ mod utils; pub mod app_session; pub mod compat; pub mod oauth2; +pub mod personal; pub mod policy_data; pub mod queue; pub mod upstream_oauth2; diff --git a/crates/storage/src/personal/access_token.rs b/crates/storage/src/personal/access_token.rs new file mode 100644 index 000000000..4f06bbf34 --- /dev/null +++ b/crates/storage/src/personal/access_token.rs @@ -0,0 +1,119 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use async_trait::async_trait; +use chrono::Duration; +use mas_data_model::{ + Clock, + personal::{PersonalAccessToken, session::PersonalSession}, +}; +use rand_core::RngCore; +use ulid::Ulid; + +use crate::repository_impl; + +/// An [`PersonalAccessTokenRepository`] helps interacting with +/// [`PersonalAccessToken`] saved in the storage backend +#[async_trait] +pub trait PersonalAccessTokenRepository: Send + Sync { + /// The error type returned by the repository + type Error; + + /// Lookup an access token by its ID + /// + /// Returns the access token if it exists, `None` otherwise + /// + /// # Parameters + /// + /// * `id`: The ID of the access token to lookup + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error>; + + /// Find an access token by its token + /// + /// Returns the access token if it exists, `None` otherwise + /// + /// # Parameters + /// + /// * `access_token`: The token of the access token to lookup + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn find_by_token( + &mut self, + access_token: &str, + ) -> Result, Self::Error>; + + /// Add a new access token to the database + /// + /// Returns the newly created access token + /// + /// # Parameters + /// + /// * `rng`: A random number generator + /// * `clock`: The clock used to generate timestamps + /// * `session`: The session the access token is associated with + /// * `access_token`: The access token to add + /// * `expires_after`: The duration after which the access token expires. If + /// [`None`] the access token never expires + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + session: &PersonalSession, + access_token: String, + expires_after: Option, + ) -> Result; + + /// Revoke an access token + /// + /// Returns the revoked access token + /// + /// # Parameters + /// + /// * `clock`: The clock used to generate timestamps + /// * `access_token`: The access token to revoke + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn revoke( + &mut self, + clock: &dyn Clock, + access_token: PersonalAccessToken, + ) -> Result; +} + +repository_impl!(PersonalAccessTokenRepository: + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error>; + + async fn find_by_token( + &mut self, + access_token: &str, + ) -> Result, Self::Error>; + + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + session: &PersonalSession, + access_token: String, + expires_after: Option, + ) -> Result; + + async fn revoke( + &mut self, + clock: &dyn Clock, + access_token: PersonalAccessToken, + ) -> Result; +); diff --git a/crates/storage/src/personal/mod.rs b/crates/storage/src/personal/mod.rs new file mode 100644 index 000000000..28a33e1a0 --- /dev/null +++ b/crates/storage/src/personal/mod.rs @@ -0,0 +1,13 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +//! Repositories to deal with Personal Sessions and Personal Access Tokens +//! (PATs), which are sessions/access tokens created manually by users for use +//! in scripts, bots and similar applications. + +mod access_token; +mod session; + +pub use self::{access_token::PersonalAccessTokenRepository, session::PersonalSessionRepository}; diff --git a/crates/storage/src/personal/session.rs b/crates/storage/src/personal/session.rs new file mode 100644 index 000000000..7d0a76a37 --- /dev/null +++ b/crates/storage/src/personal/session.rs @@ -0,0 +1,101 @@ +// Copyright 2025 New Vector Ltd. +// +// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +// Please see LICENSE files in the repository root for full details. + +use async_trait::async_trait; +use chrono::{DateTime, Utc}; +use mas_data_model::{Clock, Device, User, personal::session::PersonalSession}; +use oauth2_types::scope::Scope; +use rand_core::RngCore; +use ulid::Ulid; + +use crate::repository_impl; + +/// A [`PersonalSessionRepository`] helps interacting with +/// [`PersonalSession`] saved in the storage backend +#[async_trait] +pub trait PersonalSessionRepository: Send + Sync { + /// The error type returned by the repository + type Error; + + /// Lookup a Personal session by its ID + /// + /// Returns the Personal session if it exists, `None` otherwise + /// + /// # Parameters + /// + /// * `id`: The ID of the Personal session to lookup + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error>; + + /// Start a new Personal session + /// + /// Returns the newly created Personal session + /// + /// # Parameters + /// + /// * `rng`: The random number generator to use + /// * `clock`: The clock used to generate timestamps + /// * `owner_user`: The user that will own the personal session + /// * `actor_user`: The user that will be represented by the personal + /// session + /// * `device`: The device ID of this session + /// * `human_name`: The human-readable name of the session provided by the + /// client or the user + /// * `scope`: The [`Scope`] of the [`PersonalSession`] + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + owner_user: &User, + actor_user: &User, + human_name: String, + scope: Scope, + ) -> Result; + + /// End a Personal session + /// + /// Returns the ended Personal session + /// + /// # Parameters + /// + /// * `clock`: The clock used to generate timestamps + /// * `Personal_session`: The Personal session to end + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn revoke( + &mut self, + clock: &dyn Clock, + personal_session: PersonalSession, + ) -> Result; +} + +repository_impl!(PersonalSessionRepository: + async fn lookup(&mut self, id: Ulid) -> Result, Self::Error>; + + async fn add( + &mut self, + rng: &mut (dyn RngCore + Send), + clock: &dyn Clock, + owner_user: &User, + actor_user: &User, + human_name: String, + scope: Scope, + ) -> Result; + + async fn revoke( + &mut self, + clock: &dyn Clock, + personal_session: PersonalSession, + ) -> Result; +); diff --git a/crates/storage/src/repository.rs b/crates/storage/src/repository.rs index 518769eb1..f6eb191e6 100644 --- a/crates/storage/src/repository.rs +++ b/crates/storage/src/repository.rs @@ -18,6 +18,7 @@ use crate::{ OAuth2AccessTokenRepository, OAuth2AuthorizationGrantRepository, OAuth2ClientRepository, OAuth2DeviceCodeGrantRepository, OAuth2RefreshTokenRepository, OAuth2SessionRepository, }, + personal::{PersonalAccessTokenRepository, PersonalSessionRepository}, policy_data::PolicyDataRepository, queue::{QueueJobRepository, QueueScheduleRepository, QueueWorkerRepository}, upstream_oauth2::{ @@ -214,6 +215,16 @@ pub trait RepositoryAccess: Send { &'c mut self, ) -> Box + 'c>; + /// Get a [`PersonalAccessTokenRepository`] + fn personal_access_token<'c>( + &'c mut self, + ) -> Box + 'c>; + + /// Get a [`PersonalSessionRepository`] + fn personal_session<'c>( + &'c mut self, + ) -> Box + 'c>; + /// Get a [`QueueWorkerRepository`] fn queue_worker<'c>(&'c mut self) -> Box + 'c>; @@ -247,6 +258,7 @@ mod impls { OAuth2ClientRepository, OAuth2DeviceCodeGrantRepository, OAuth2RefreshTokenRepository, OAuth2SessionRepository, }, + personal::{PersonalAccessTokenRepository, PersonalSessionRepository}, policy_data::PolicyDataRepository, queue::{QueueJobRepository, QueueScheduleRepository, QueueWorkerRepository}, upstream_oauth2::{ @@ -458,6 +470,21 @@ mod impls { )) } + fn personal_access_token<'c>( + &'c mut self, + ) -> Box + 'c> { + Box::new(MapErr::new( + self.inner.personal_access_token(), + &mut self.mapper, + )) + } + + fn personal_session<'c>( + &'c mut self, + ) -> Box + 'c> { + Box::new(MapErr::new(self.inner.personal_session(), &mut self.mapper)) + } + fn queue_worker<'c>( &'c mut self, ) -> Box + 'c> { @@ -610,6 +637,18 @@ mod impls { (**self).compat_refresh_token() } + fn personal_access_token<'c>( + &'c mut self, + ) -> Box + 'c> { + (**self).personal_access_token() + } + + fn personal_session<'c>( + &'c mut self, + ) -> Box + 'c> { + (**self).personal_session() + } + fn queue_worker<'c>( &'c mut self, ) -> Box + 'c> { From e1b228c48b41974a030074c9349ccf797d85c94d Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Fri, 3 Oct 2025 13:39:54 +0100 Subject: [PATCH 133/296] Add storage tests (with TODOs for unsupported functionality) --- crates/storage-pg/src/personal/mod.rs | 309 ++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) diff --git a/crates/storage-pg/src/personal/mod.rs b/crates/storage-pg/src/personal/mod.rs index e60daccc4..10956de3d 100644 --- a/crates/storage-pg/src/personal/mod.rs +++ b/crates/storage-pg/src/personal/mod.rs @@ -11,3 +11,312 @@ mod session; pub use access_token::PgPersonalAccessTokenRepository; pub use session::PgPersonalSessionRepository; + +#[cfg(test)] +mod tests { + use chrono::Duration; + use mas_data_model::{Clock, Device, clock::MockClock}; + use mas_storage::{ + RepositoryAccess, + personal::{PersonalAccessTokenRepository, PersonalSessionRepository}, + user::UserRepository, + }; + use oauth2_types::scope::{OPENID, PROFILE, Scope}; + use rand::SeedableRng; + use rand_chacha::ChaChaRng; + use sqlx::PgPool; + + use crate::PgRepository; + + #[sqlx::test(migrator = "crate::MIGRATOR")] + async fn test_session_repository(pool: PgPool) { + let mut rng = ChaChaRng::seed_from_u64(42); + let clock = MockClock::default(); + let mut repo = PgRepository::from_pool(&pool).await.unwrap(); + + // Create a user + let admin_user = repo + .user() + .add(&mut rng, &clock, "john".to_owned()) + .await + .unwrap(); + let bot_user = repo + .user() + .add(&mut rng, &clock, "marvin".to_owned()) + .await + .unwrap(); + + // TODO: Session filters are not implemented for personal sessions yet + // let all = PersonalSessionFilter::new().for_user(&user); + // let active = all.active_only(); + // let finished = all.finished_only(); + // let pagination = Pagination::first(10); + + // assert_eq!(repo.personal_session().count(all).await.unwrap(), 0); + // assert_eq!(repo.personal_session().count(active).await.unwrap(), 0); + // assert_eq!(repo.personal_session().count(finished).await.unwrap(), 0); + + // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); + // assert!(full_list.edges.is_empty()); + // let active_list = repo + // .compat_session() + // .list(active, pagination) + // .await + // .unwrap(); + // assert!(active_list.edges.is_empty()); + // let finished_list = repo + // .compat_session() + // .list(finished, pagination) + // .await + // .unwrap(); + // assert!(finished_list.edges.is_empty()); + + // Start a personal session for that user + let device = Device::generate(&mut rng); + let scope: Scope = [OPENID, PROFILE] + .into_iter() + .chain(device.to_scope_token().unwrap()) + .collect(); + let session = repo + .personal_session() + .add( + &mut rng, + &clock, + &admin_user, + &bot_user, + "Test Personal Session".to_owned(), + scope.clone(), + ) + .await + .unwrap(); + assert_eq!(session.owner_user_id, admin_user.id); + assert_eq!(session.actor_user_id, bot_user.id); + assert!(session.is_valid()); + assert!(!session.is_revoked()); + assert_eq!(session.scope, scope); + + // TODO + // assert_eq!(repo.compat_session().count(all).await.unwrap(), 1); + // assert_eq!(repo.compat_session().count(active).await.unwrap(), 1); + // assert_eq!(repo.compat_session().count(finished).await.unwrap(), 0); + + // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); + // assert_eq!(full_list.edges.len(), 1); + // assert_eq!(full_list.edges[0].0.id, session.id); + // let active_list = repo + // .compat_session() + // .list(active, pagination) + // .await + // .unwrap(); + // assert_eq!(active_list.edges.len(), 1); + // assert_eq!(active_list.edges[0].0.id, session.id); + // let finished_list = repo + // .compat_session() + // .list(finished, pagination) + // .await + // .unwrap(); + // assert!(finished_list.edges.is_empty()); + + // Lookup the session and check it didn't change + let session_lookup = repo + .personal_session() + .lookup(session.id) + .await + .unwrap() + .expect("personal session not found"); + assert_eq!(session_lookup.id, session.id); + assert_eq!(session_lookup.owner_user_id, admin_user.id); + assert_eq!(session_lookup.actor_user_id, bot_user.id); + assert!(session_lookup.is_valid()); + assert!(!session_lookup.is_revoked()); + assert_eq!(session_lookup.scope, scope); + + // TODO + // assert_eq!(list.edges.len(), 1); + // let session_lookup = &list.edges[0].0; + // assert_eq!(session_lookup.id, session.id); + // assert_eq!(session_lookup.user_id, user.id); + // assert_eq!(session.device.as_ref().unwrap().as_str(), device_str); + // assert!(session_lookup.is_valid()); + // assert!(!session_lookup.is_finished()); + + // Revoke the session + let session = repo + .personal_session() + .revoke(&clock, session) + .await + .unwrap(); + assert!(!session.is_valid()); + assert!(session.is_revoked()); + + // TODO + // assert_eq!(repo.compat_session().count(all).await.unwrap(), 1); + // assert_eq!(repo.compat_session().count(active).await.unwrap(), 0); + // assert_eq!(repo.compat_session().count(finished).await.unwrap(), 1); + + // TODO + // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); + // assert_eq!(full_list.edges.len(), 1); + // assert_eq!(full_list.edges[0].0.id, session.id); + // let active_list = repo + // .compat_session() + // .list(active, pagination) + // .await + // .unwrap(); + // assert!(active_list.edges.is_empty()); + // let finished_list = repo + // .compat_session() + // .list(finished, pagination) + // .await + // .unwrap(); + // assert_eq!(finished_list.edges.len(), 1); + // assert_eq!(finished_list.edges[0].0.id, session.id); + // assert!(session.is_revoked()); + + // Reload the session and check again + let session_lookup = repo + .personal_session() + .lookup(session.id) + .await + .unwrap() + .expect("personal session not found"); + assert!(!session_lookup.is_valid()); + assert!(session_lookup.is_revoked()); + } + + #[sqlx::test(migrator = "crate::MIGRATOR")] + async fn test_access_token_repository(pool: PgPool) { + const FIRST_TOKEN: &str = "first_access_token"; + const SECOND_TOKEN: &str = "second_access_token"; + let mut rng = ChaChaRng::seed_from_u64(42); + let clock = MockClock::default(); + let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); + + // Create a user + let admin_user = repo + .user() + .add(&mut rng, &clock, "john".to_owned()) + .await + .unwrap(); + let bot_user = repo + .user() + .add(&mut rng, &clock, "marvin".to_owned()) + .await + .unwrap(); + + // Start a personal session for that user + let device = Device::generate(&mut rng); + let scope: Scope = [OPENID, PROFILE] + .into_iter() + .chain(device.to_scope_token().unwrap()) + .collect(); + let session = repo + .personal_session() + .add( + &mut rng, + &clock, + &admin_user, + &bot_user, + "Test Personal Session".to_owned(), + scope, + ) + .await + .unwrap(); + + // Add an access token to that session + let token = repo + .personal_access_token() + .add( + &mut rng, + &clock, + &session, + FIRST_TOKEN.to_owned(), + Some(Duration::try_minutes(1).unwrap()), + ) + .await + .unwrap(); + assert_eq!(token.session_id, session.id); + + // Commit the txn and grab a new transaction, to test a conflict + repo.save().await.unwrap(); + + { + let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); + // Adding the same token a second time should conflict + assert!( + repo.personal_access_token() + .add( + &mut rng, + &clock, + &session, + FIRST_TOKEN.to_owned(), + Some(Duration::try_minutes(1).unwrap()), + ) + .await + .is_err() + ); + repo.cancel().await.unwrap(); + } + + // Grab a new repo + let mut repo = PgRepository::from_pool(&pool).await.unwrap().boxed(); + + // Looking up via ID works + let token_lookup = repo + .personal_access_token() + .lookup(token.id) + .await + .unwrap() + .expect("personal access token not found"); + assert_eq!(token.id, token_lookup.id); + assert_eq!(token_lookup.session_id, session.id); + + // Looking up via the token value works + let token_lookup = repo + .personal_access_token() + .find_by_token(FIRST_TOKEN) + .await + .unwrap() + .expect("personal access token not found"); + assert_eq!(token.id, token_lookup.id); + assert_eq!(token_lookup.session_id, session.id); + + // Token is currently valid + assert!(token.is_valid(clock.now())); + + clock.advance(Duration::try_minutes(1).unwrap()); + // Token should have expired + assert!(!token.is_valid(clock.now())); + + // Add a second access token, this time without expiration + let token = repo + .personal_access_token() + .add(&mut rng, &clock, &session, SECOND_TOKEN.to_owned(), None) + .await + .unwrap(); + assert_eq!(token.session_id, session.id); + + // Token is currently valid + assert!(token.is_valid(clock.now())); + + // Revoke it + let _token = repo + .personal_access_token() + .revoke(&clock, token) + .await + .unwrap(); + + // Reload it + let token = repo + .personal_access_token() + .find_by_token(SECOND_TOKEN) + .await + .unwrap() + .expect("personal access token not found"); + + // Token is not valid anymore + assert!(!token.is_valid(clock.now())); + + repo.save().await.unwrap(); + } +} From 2a86a446b2eb195fbe56b37a41b612a8c498bd86 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Mon, 6 Oct 2025 13:31:43 +0100 Subject: [PATCH 134/296] Add filters for personal sessions --- crates/storage-pg/src/iden.rs | 15 ++ crates/storage-pg/src/personal/session.rs | 170 +++++++++++++++++++- crates/storage/src/personal/mod.rs | 5 +- crates/storage/src/personal/session.rs | 181 +++++++++++++++++++++- 4 files changed, 366 insertions(+), 5 deletions(-) diff --git a/crates/storage-pg/src/iden.rs b/crates/storage-pg/src/iden.rs index a861f59c7..c2198434e 100644 --- a/crates/storage-pg/src/iden.rs +++ b/crates/storage-pg/src/iden.rs @@ -108,6 +108,21 @@ pub enum OAuth2Clients { IsStatic, } +#[derive(sea_query::Iden)] +#[iden = "personal_sessions"] +pub enum PersonalSessions { + Table, + PersonalSessionId, + OwnerUserId, + ActorUserId, + HumanName, + ScopeList, + CreatedAt, + RevokedAt, + LastActiveAt, + LastActiveIp, +} + #[derive(sea_query::Iden)] #[iden = "upstream_oauth_providers"] pub enum UpstreamOAuthProviders { diff --git a/crates/storage-pg/src/personal/session.rs b/crates/storage-pg/src/personal/session.rs index 514293ba9..40ed4f312 100644 --- a/crates/storage-pg/src/personal/session.rs +++ b/crates/storage-pg/src/personal/session.rs @@ -11,14 +11,29 @@ use mas_data_model::{ Clock, User, personal::session::{PersonalSession, SessionState}, }; -use mas_storage::personal::PersonalSessionRepository; +use mas_storage::{ + Page, Pagination, + personal::{PersonalSessionFilter, PersonalSessionRepository, PersonalSessionState}, +}; use oauth2_types::scope::Scope; use rand::RngCore; +use sea_query::{ + Condition, Expr, PgFunc, PostgresQueryBuilder, Query, SimpleExpr, enum_def, + extension::postgres::PgExpr as _, +}; +use sea_query_binder::SqlxBinder as _; use sqlx::PgConnection; use ulid::Ulid; use uuid::Uuid; -use crate::{DatabaseError, errors::DatabaseInconsistencyError, tracing::ExecuteExt as _}; +use crate::{ + DatabaseError, + errors::DatabaseInconsistencyError, + filter::{Filter, StatementExt as _}, + iden::PersonalSessions, + pagination::QueryBuilderExt as _, + tracing::ExecuteExt as _, +}; /// An implementation of [`PersonalSessionRepository`] for a PostgreSQL /// connection @@ -27,13 +42,15 @@ pub struct PgPersonalSessionRepository<'c> { } impl<'c> PgPersonalSessionRepository<'c> { - /// Create a new [`PgOAuth2SessionRepository`] from an active PostgreSQL + /// Create a new [`PgPersonalSessionRepository`] from an active PostgreSQL /// connection pub fn new(conn: &'c mut PgConnection) -> Self { Self { conn } } } +#[derive(sqlx::FromRow)] +#[enum_def] struct PersonalSessionLookup { personal_session_id: Uuid, owner_user_id: Uuid, @@ -215,4 +232,151 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { .finish(finished_at) .map_err(DatabaseError::to_invalid_operation) } + + #[tracing::instrument( + name = "db.personal_session.list", + skip_all, + fields( + db.query.text, + ), + err, + )] + async fn list( + &mut self, + filter: PersonalSessionFilter<'_>, + pagination: Pagination, + ) -> Result, Self::Error> { + let (sql, arguments) = Query::select() + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::PersonalSessionId)), + PersonalSessionLookupIden::PersonalSessionId, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::OwnerUserId)), + PersonalSessionLookupIden::OwnerUserId, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::ActorUserId)), + PersonalSessionLookupIden::ActorUserId, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::HumanName)), + PersonalSessionLookupIden::HumanName, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::ScopeList)), + PersonalSessionLookupIden::ScopeList, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::CreatedAt)), + PersonalSessionLookupIden::CreatedAt, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::RevokedAt)), + PersonalSessionLookupIden::RevokedAt, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::LastActiveAt)), + PersonalSessionLookupIden::LastActiveAt, + ) + .expr_as( + Expr::col((PersonalSessions::Table, PersonalSessions::LastActiveIp)), + PersonalSessionLookupIden::LastActiveIp, + ) + .from(PersonalSessions::Table) + .apply_filter(filter) + .generate_pagination( + (PersonalSessions::Table, PersonalSessions::PersonalSessionId), + pagination, + ) + .build_sqlx(PostgresQueryBuilder); + + let edges: Vec = sqlx::query_as_with(&sql, arguments) + .traced() + .fetch_all(&mut *self.conn) + .await?; + + let page = pagination + .process(edges) + .try_map(PersonalSession::try_from)?; + + Ok(page) + } + + #[tracing::instrument( + name = "db.personal_session.count", + skip_all, + fields( + db.query.text, + ), + err, + )] + async fn count(&mut self, filter: PersonalSessionFilter<'_>) -> Result { + let (sql, arguments) = Query::select() + .expr(Expr::col((PersonalSessions::Table, PersonalSessions::PersonalSessionId)).count()) + .from(PersonalSessions::Table) + .apply_filter(filter) + .build_sqlx(PostgresQueryBuilder); + + let count: i64 = sqlx::query_scalar_with(&sql, arguments) + .traced() + .fetch_one(&mut *self.conn) + .await?; + + count + .try_into() + .map_err(DatabaseError::to_invalid_operation) + } +} + +impl Filter for PersonalSessionFilter<'_> { + fn generate_condition(&self, _has_joins: bool) -> impl sea_query::IntoCondition { + sea_query::Condition::all() + .add_option(self.owner_user().map(|user| { + Expr::col((PersonalSessions::Table, PersonalSessions::OwnerUserId)) + .eq(Uuid::from(user.id)) + })) + .add_option(self.actor_user().map(|user| { + Expr::col((PersonalSessions::Table, PersonalSessions::ActorUserId)) + .eq(Uuid::from(user.id)) + })) + .add_option(self.device().map(|device| -> SimpleExpr { + if let Ok([stable_scope_token, unstable_scope_token]) = device.to_scope_token() { + Condition::any() + .add( + Expr::val(stable_scope_token.to_string()).eq(PgFunc::any(Expr::col(( + PersonalSessions::Table, + PersonalSessions::ScopeList, + )))), + ) + .add(Expr::val(unstable_scope_token.to_string()).eq(PgFunc::any( + Expr::col((PersonalSessions::Table, PersonalSessions::ScopeList)), + ))) + .into() + } else { + // If the device ID can't be encoded as a scope token, match no rows + Expr::val(false).into() + } + })) + .add_option(self.state().map(|state| match state { + PersonalSessionState::Active => { + Expr::col((PersonalSessions::Table, PersonalSessions::RevokedAt)).is_null() + } + PersonalSessionState::Revoked => { + Expr::col((PersonalSessions::Table, PersonalSessions::RevokedAt)).is_not_null() + } + })) + .add_option(self.scope().map(|scope| { + let scope: Vec = scope.iter().map(|s| s.as_str().to_owned()).collect(); + Expr::col((PersonalSessions::Table, PersonalSessions::ScopeList)).contains(scope) + })) + .add_option(self.last_active_before().map(|last_active_before| { + Expr::col((PersonalSessions::Table, PersonalSessions::LastActiveAt)) + .lt(last_active_before) + })) + .add_option(self.last_active_after().map(|last_active_after| { + Expr::col((PersonalSessions::Table, PersonalSessions::LastActiveAt)) + .gt(last_active_after) + })) + } } diff --git a/crates/storage/src/personal/mod.rs b/crates/storage/src/personal/mod.rs index 28a33e1a0..3a9dfcd65 100644 --- a/crates/storage/src/personal/mod.rs +++ b/crates/storage/src/personal/mod.rs @@ -10,4 +10,7 @@ mod access_token; mod session; -pub use self::{access_token::PersonalAccessTokenRepository, session::PersonalSessionRepository}; +pub use self::{ + access_token::PersonalAccessTokenRepository, + session::{PersonalSessionFilter, PersonalSessionRepository, PersonalSessionState}, +}; diff --git a/crates/storage/src/personal/session.rs b/crates/storage/src/personal/session.rs index 7d0a76a37..aedb939e0 100644 --- a/crates/storage/src/personal/session.rs +++ b/crates/storage/src/personal/session.rs @@ -10,7 +10,7 @@ use oauth2_types::scope::Scope; use rand_core::RngCore; use ulid::Ulid; -use crate::repository_impl; +use crate::{Page, Pagination, repository_impl}; /// A [`PersonalSessionRepository`] helps interacting with /// [`PersonalSession`] saved in the storage backend @@ -78,6 +78,34 @@ pub trait PersonalSessionRepository: Send + Sync { clock: &dyn Clock, personal_session: PersonalSession, ) -> Result; + + /// List [`PersonalSession`]s matching the given filter and pagination + /// parameters + /// + /// # Parameters + /// + /// * `filter`: The filter parameters + /// * `pagination`: The pagination parameters + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn list( + &mut self, + filter: PersonalSessionFilter<'_>, + pagination: Pagination, + ) -> Result, Self::Error>; + + /// Count [`PersonalSession`]s matching the given filter + /// + /// # Parameters + /// + /// * `filter`: The filter parameters + /// + /// # Errors + /// + /// Returns [`Self::Error`] if the underlying repository fails + async fn count(&mut self, filter: PersonalSessionFilter<'_>) -> Result; } repository_impl!(PersonalSessionRepository: @@ -98,4 +126,155 @@ repository_impl!(PersonalSessionRepository: clock: &dyn Clock, personal_session: PersonalSession, ) -> Result; + + async fn list( + &mut self, + filter: PersonalSessionFilter<'_>, + pagination: Pagination, + ) -> Result, Self::Error>; + + async fn count(&mut self, filter: PersonalSessionFilter<'_>) -> Result; ); + +/// Filter parameters for listing personal sessions +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub struct PersonalSessionFilter<'a> { + owner_user: Option<&'a User>, + actor_user: Option<&'a User>, + device: Option<&'a Device>, + state: Option, + scope: Option<&'a Scope>, + last_active_before: Option>, + last_active_after: Option>, +} + +/// Filter for what state a personal session is in. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PersonalSessionState { + /// The personal session is active, which means it either + /// has active access tokens or can have new access tokens generated. + Active, + /// The personal session is revoked, which means no more access tokens + /// can be generated and none are active. + Revoked, +} + +impl<'a> PersonalSessionFilter<'a> { + /// Create a new [`PersonalSessionFilter`] with default values + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// List sessions owned by a specific user + #[must_use] + pub fn for_owner_user(mut self, user: &'a User) -> Self { + self.owner_user = Some(user); + self + } + + /// Get the owner user filter + /// + /// Returns [`None`] if no user filter was set + #[must_use] + pub fn owner_user(&self) -> Option<&'a User> { + self.owner_user + } + + /// List sessions acting as a specific user + #[must_use] + pub fn for_actor_user(mut self, user: &'a User) -> Self { + self.actor_user = Some(user); + self + } + + /// Get the actor user filter + /// + /// Returns [`None`] if no user filter was set + #[must_use] + pub fn actor_user(&self) -> Option<&'a User> { + self.actor_user + } + + /// Only return sessions with a last active time before the given time + #[must_use] + pub fn with_last_active_before(mut self, last_active_before: DateTime) -> Self { + self.last_active_before = Some(last_active_before); + self + } + + /// Only return sessions with a last active time after the given time + #[must_use] + pub fn with_last_active_after(mut self, last_active_after: DateTime) -> Self { + self.last_active_after = Some(last_active_after); + self + } + + /// Get the last active before filter + /// + /// Returns [`None`] if no client filter was set + #[must_use] + pub fn last_active_before(&self) -> Option> { + self.last_active_before + } + + /// Get the last active after filter + /// + /// Returns [`None`] if no client filter was set + #[must_use] + pub fn last_active_after(&self) -> Option> { + self.last_active_after + } + + /// Only return active sessions + #[must_use] + pub fn active_only(mut self) -> Self { + self.state = Some(PersonalSessionState::Active); + self + } + + /// Only return finished sessions + #[must_use] + pub fn finished_only(mut self) -> Self { + self.state = Some(PersonalSessionState::Revoked); + self + } + + /// Get the state filter + /// + /// Returns [`None`] if no state filter was set + #[must_use] + pub fn state(&self) -> Option { + self.state + } + + /// Only return sessions with the given scope + #[must_use] + pub fn with_scope(mut self, scope: &'a Scope) -> Self { + self.scope = Some(scope); + self + } + + /// Get the scope filter + /// + /// Returns [`None`] if no scope filter was set + #[must_use] + pub fn scope(&self) -> Option<&'a Scope> { + self.scope + } + + /// Only return sessions that have the given device in their scope + #[must_use] + pub fn for_device(mut self, device: &'a Device) -> Self { + self.device = Some(device); + self + } + + /// Get the device filter + /// + /// Returns [`None`] if no device filter was set + #[must_use] + pub fn device(&self) -> Option<&'a Device> { + self.device + } +} From c48285d7f7692e766945c0c88b7d83c9563675f9 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Mon, 6 Oct 2025 13:31:49 +0100 Subject: [PATCH 135/296] Sync devices from personal sessions --- crates/tasks/src/matrix.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/crates/tasks/src/matrix.rs b/crates/tasks/src/matrix.rs index 2acd9372e..8a8b90c4e 100644 --- a/crates/tasks/src/matrix.rs +++ b/crates/tasks/src/matrix.rs @@ -14,6 +14,7 @@ use mas_storage::{ Pagination, RepositoryAccess, compat::CompatSessionFilter, oauth2::OAuth2SessionFilter, + personal::PersonalSessionFilter, queue::{ DeleteDeviceJob, ProvisionDeviceJob, ProvisionUserJob, QueueJobRepositoryExt as _, SyncDevicesJob, @@ -243,6 +244,35 @@ impl RunnableJob for SyncDevicesJob { } } + // Cycle through all the personal sessions of the user and get the devices + let mut cursor = Pagination::first(5000); + loop { + let page = repo + .personal_session() + .list( + PersonalSessionFilter::new() + .for_actor_user(&user) + .active_only(), + cursor, + ) + .await + .map_err(JobError::retry)?; + + for edge in page.edges { + for scope in &*edge.node.scope { + if let Some(device) = Device::from_scope_token(scope) { + devices.insert(device.as_str().to_owned()); + } + } + + cursor = cursor.after(edge.cursor); + } + + if !page.has_next_page { + break; + } + } + matrix .sync_devices(&user.username, devices) .await From e4dee42cb38eb18804760c2202de24b2e82e4c9e Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Mon, 6 Oct 2025 17:19:57 +0100 Subject: [PATCH 136/296] Enable session filter tests --- crates/storage-pg/src/personal/mod.rs | 144 ++++++++++------------ crates/storage-pg/src/personal/session.rs | 11 +- 2 files changed, 76 insertions(+), 79 deletions(-) diff --git a/crates/storage-pg/src/personal/mod.rs b/crates/storage-pg/src/personal/mod.rs index 10956de3d..3b19bcfe2 100644 --- a/crates/storage-pg/src/personal/mod.rs +++ b/crates/storage-pg/src/personal/mod.rs @@ -17,8 +17,10 @@ mod tests { use chrono::Duration; use mas_data_model::{Clock, Device, clock::MockClock}; use mas_storage::{ - RepositoryAccess, - personal::{PersonalAccessTokenRepository, PersonalSessionRepository}, + Pagination, RepositoryAccess, + personal::{ + PersonalAccessTokenRepository, PersonalSessionFilter, PersonalSessionRepository, + }, user::UserRepository, }; use oauth2_types::scope::{OPENID, PROFILE, Scope}; @@ -46,30 +48,30 @@ mod tests { .await .unwrap(); - // TODO: Session filters are not implemented for personal sessions yet - // let all = PersonalSessionFilter::new().for_user(&user); - // let active = all.active_only(); - // let finished = all.finished_only(); - // let pagination = Pagination::first(10); + let all = PersonalSessionFilter::new().for_actor_user(&bot_user); + let active = all.active_only(); + let finished = all.finished_only(); + let pagination = Pagination::first(10); - // assert_eq!(repo.personal_session().count(all).await.unwrap(), 0); - // assert_eq!(repo.personal_session().count(active).await.unwrap(), 0); - // assert_eq!(repo.personal_session().count(finished).await.unwrap(), 0); + assert_eq!(repo.personal_session().count(all).await.unwrap(), 0); + assert_eq!(repo.personal_session().count(active).await.unwrap(), 0); + assert_eq!(repo.personal_session().count(finished).await.unwrap(), 0); - // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); - // assert!(full_list.edges.is_empty()); - // let active_list = repo - // .compat_session() - // .list(active, pagination) - // .await - // .unwrap(); - // assert!(active_list.edges.is_empty()); - // let finished_list = repo - // .compat_session() - // .list(finished, pagination) - // .await - // .unwrap(); - // assert!(finished_list.edges.is_empty()); + // We start off with no sessions + let full_list = repo.personal_session().list(all, pagination).await.unwrap(); + assert!(full_list.edges.is_empty()); + let active_list = repo + .personal_session() + .list(active, pagination) + .await + .unwrap(); + assert!(active_list.edges.is_empty()); + let finished_list = repo + .personal_session() + .list(finished, pagination) + .await + .unwrap(); + assert!(finished_list.edges.is_empty()); // Start a personal session for that user let device = Device::generate(&mut rng); @@ -95,27 +97,28 @@ mod tests { assert!(!session.is_revoked()); assert_eq!(session.scope, scope); - // TODO - // assert_eq!(repo.compat_session().count(all).await.unwrap(), 1); - // assert_eq!(repo.compat_session().count(active).await.unwrap(), 1); - // assert_eq!(repo.compat_session().count(finished).await.unwrap(), 0); + assert_eq!(repo.personal_session().count(all).await.unwrap(), 1); + assert_eq!(repo.personal_session().count(active).await.unwrap(), 1); + assert_eq!(repo.personal_session().count(finished).await.unwrap(), 0); - // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); - // assert_eq!(full_list.edges.len(), 1); - // assert_eq!(full_list.edges[0].0.id, session.id); - // let active_list = repo - // .compat_session() - // .list(active, pagination) - // .await - // .unwrap(); - // assert_eq!(active_list.edges.len(), 1); - // assert_eq!(active_list.edges[0].0.id, session.id); - // let finished_list = repo - // .compat_session() - // .list(finished, pagination) - // .await - // .unwrap(); - // assert!(finished_list.edges.is_empty()); + let full_list = repo.personal_session().list(all, pagination).await.unwrap(); + assert_eq!(full_list.edges.len(), 1); + assert_eq!(full_list.edges[0].node.id, session.id); + assert!(full_list.edges[0].node.is_valid()); + let active_list = repo + .personal_session() + .list(active, pagination) + .await + .unwrap(); + assert_eq!(active_list.edges.len(), 1); + assert_eq!(active_list.edges[0].node.id, session.id); + assert!(active_list.edges[0].node.is_valid()); + let finished_list = repo + .personal_session() + .list(finished, pagination) + .await + .unwrap(); + assert!(finished_list.edges.is_empty()); // Lookup the session and check it didn't change let session_lookup = repo @@ -127,18 +130,9 @@ mod tests { assert_eq!(session_lookup.id, session.id); assert_eq!(session_lookup.owner_user_id, admin_user.id); assert_eq!(session_lookup.actor_user_id, bot_user.id); + assert_eq!(session_lookup.scope, scope); assert!(session_lookup.is_valid()); assert!(!session_lookup.is_revoked()); - assert_eq!(session_lookup.scope, scope); - - // TODO - // assert_eq!(list.edges.len(), 1); - // let session_lookup = &list.edges[0].0; - // assert_eq!(session_lookup.id, session.id); - // assert_eq!(session_lookup.user_id, user.id); - // assert_eq!(session.device.as_ref().unwrap().as_str(), device_str); - // assert!(session_lookup.is_valid()); - // assert!(!session_lookup.is_finished()); // Revoke the session let session = repo @@ -149,29 +143,27 @@ mod tests { assert!(!session.is_valid()); assert!(session.is_revoked()); - // TODO - // assert_eq!(repo.compat_session().count(all).await.unwrap(), 1); - // assert_eq!(repo.compat_session().count(active).await.unwrap(), 0); - // assert_eq!(repo.compat_session().count(finished).await.unwrap(), 1); + assert_eq!(repo.personal_session().count(all).await.unwrap(), 1); + assert_eq!(repo.personal_session().count(active).await.unwrap(), 0); + assert_eq!(repo.personal_session().count(finished).await.unwrap(), 1); - // TODO - // let full_list = repo.compat_session().list(all, pagination).await.unwrap(); - // assert_eq!(full_list.edges.len(), 1); - // assert_eq!(full_list.edges[0].0.id, session.id); - // let active_list = repo - // .compat_session() - // .list(active, pagination) - // .await - // .unwrap(); - // assert!(active_list.edges.is_empty()); - // let finished_list = repo - // .compat_session() - // .list(finished, pagination) - // .await - // .unwrap(); - // assert_eq!(finished_list.edges.len(), 1); - // assert_eq!(finished_list.edges[0].0.id, session.id); - // assert!(session.is_revoked()); + let full_list = repo.personal_session().list(all, pagination).await.unwrap(); + assert_eq!(full_list.edges.len(), 1); + assert_eq!(full_list.edges[0].node.id, session.id); + let active_list = repo + .personal_session() + .list(active, pagination) + .await + .unwrap(); + assert!(active_list.edges.is_empty()); + let finished_list = repo + .personal_session() + .list(finished, pagination) + .await + .unwrap(); + assert_eq!(finished_list.edges.len(), 1); + assert_eq!(finished_list.edges[0].node.id, session.id); + assert!(finished_list.edges[0].node.is_revoked()); // Reload the session and check again let session_lookup = repo diff --git a/crates/storage-pg/src/personal/session.rs b/crates/storage-pg/src/personal/session.rs index 40ed4f312..3b5b0a601 100644 --- a/crates/storage-pg/src/personal/session.rs +++ b/crates/storage-pg/src/personal/session.rs @@ -13,6 +13,7 @@ use mas_data_model::{ }; use mas_storage::{ Page, Pagination, + pagination::Node, personal::{PersonalSessionFilter, PersonalSessionRepository, PersonalSessionState}, }; use oauth2_types::scope::Scope; @@ -63,6 +64,12 @@ struct PersonalSessionLookup { last_active_ip: Option, } +impl Node for PersonalSessionLookup { + fn cursor(&self) -> Ulid { + self.personal_session_id.into() + } +} + impl TryFrom for PersonalSession { type Error = DatabaseInconsistencyError; @@ -296,9 +303,7 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { .fetch_all(&mut *self.conn) .await?; - let page = pagination - .process(edges) - .try_map(PersonalSession::try_from)?; + let page = pagination.process(edges).try_map(TryFrom::try_from)?; Ok(page) } From b9e1cdb554357d7e3cb1dd88cab59672138a4eb0 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Tue, 7 Oct 2025 16:02:55 +0100 Subject: [PATCH 137/296] Support OAuth2 clients as owners of personal sessions --- crates/data-model/src/personal/session.rs | 27 ++++++++-- ...550e4e12d1778474aba72762d9aa093d21ee2.json | 20 ++++++++ ...f063537d5a7f13c48d031367c1d8dba2f8af5.json | 19 ------- ...29681d450669563dd1178c492ffce51e5ff2.json} | 24 +++++---- .../20250924132713_personal_access_tokens.sql | 21 ++++++-- crates/storage-pg/src/iden.rs | 2 + crates/storage-pg/src/personal/mod.rs | 15 ++++-- crates/storage-pg/src/personal/session.rs | 50 ++++++++++++++++--- crates/storage/src/personal/session.rs | 25 ++++++++-- 9 files changed, 153 insertions(+), 50 deletions(-) create mode 100644 crates/storage-pg/.sqlx/query-109f0c859e123966462f1001aef550e4e12d1778474aba72762d9aa093d21ee2.json delete mode 100644 crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json rename crates/storage-pg/.sqlx/{query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json => query-fd32368fa6cd16a9704cdea54f7729681d450669563dd1178c492ffce51e5ff2.json} (64%) diff --git a/crates/data-model/src/personal/session.rs b/crates/data-model/src/personal/session.rs index f8904f810..ddca07590 100644 --- a/crates/data-model/src/personal/session.rs +++ b/crates/data-model/src/personal/session.rs @@ -10,7 +10,7 @@ use oauth2_types::scope::Scope; use serde::Serialize; use ulid::Ulid; -use crate::InvalidTransitionError; +use crate::{Client, InvalidTransitionError, User}; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)] pub enum SessionState { @@ -74,10 +74,10 @@ impl SessionState { pub struct PersonalSession { pub id: Ulid, pub state: SessionState, - pub owner_user_id: Ulid, + pub owner: PersonalSessionOwner, pub actor_user_id: Ulid, pub human_name: String, - /// The scope for the session, identical to OAuth2 sessions. + /// The scope for the session, identical to OAuth 2 sessions. /// May or may not include a device scope /// (personal sessions can be deviceless). pub scope: Scope, @@ -86,6 +86,27 @@ pub struct PersonalSession { pub last_active_ip: Option, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)] +pub enum PersonalSessionOwner { + /// The personal session is owned by the user with the given `user_id`. + User(Ulid), + /// The personal session is owned by the OAuth 2 Client with the given + /// `oauth2_client_id`. + OAuth2Client(Ulid), +} + +impl<'a> From<&'a User> for PersonalSessionOwner { + fn from(value: &'a User) -> Self { + PersonalSessionOwner::User(value.id) + } +} + +impl<'a> From<&'a Client> for PersonalSessionOwner { + fn from(value: &'a Client) -> Self { + PersonalSessionOwner::OAuth2Client(value.id) + } +} + impl std::ops::Deref for PersonalSession { type Target = SessionState; diff --git a/crates/storage-pg/.sqlx/query-109f0c859e123966462f1001aef550e4e12d1778474aba72762d9aa093d21ee2.json b/crates/storage-pg/.sqlx/query-109f0c859e123966462f1001aef550e4e12d1778474aba72762d9aa093d21ee2.json new file mode 100644 index 000000000..83400921a --- /dev/null +++ b/crates/storage-pg/.sqlx/query-109f0c859e123966462f1001aef550e4e12d1778474aba72762d9aa093d21ee2.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO personal_sessions\n ( personal_session_id\n , owner_user_id\n , owner_oauth2_client_id\n , actor_user_id\n , human_name\n , scope_list\n , created_at\n )\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Uuid", + "Uuid", + "Uuid", + "Uuid", + "Text", + "TextArray", + "Timestamptz" + ] + }, + "nullable": [] + }, + "hash": "109f0c859e123966462f1001aef550e4e12d1778474aba72762d9aa093d21ee2" +} diff --git a/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json b/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json deleted file mode 100644 index 9dec975ca..000000000 --- a/crates/storage-pg/.sqlx/query-c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO personal_sessions\n ( personal_session_id\n , owner_user_id\n , actor_user_id\n , human_name\n , scope_list\n , created_at\n )\n VALUES ($1, $2, $3, $4, $5, $6)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Uuid", - "Uuid", - "Uuid", - "Text", - "TextArray", - "Timestamptz" - ] - }, - "nullable": [] - }, - "hash": "c55d8dc9c1d1120ebc2c82e3779f063537d5a7f13c48d031367c1d8dba2f8af5" -} diff --git a/crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json b/crates/storage-pg/.sqlx/query-fd32368fa6cd16a9704cdea54f7729681d450669563dd1178c492ffce51e5ff2.json similarity index 64% rename from crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json rename to crates/storage-pg/.sqlx/query-fd32368fa6cd16a9704cdea54f7729681d450669563dd1178c492ffce51e5ff2.json index d7eb2c798..b46904ccb 100644 --- a/crates/storage-pg/.sqlx/query-8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311.json +++ b/crates/storage-pg/.sqlx/query-fd32368fa6cd16a9704cdea54f7729681d450669563dd1178c492ffce51e5ff2.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT personal_session_id\n , owner_user_id\n , actor_user_id\n , scope_list\n , created_at\n , revoked_at\n , human_name\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM personal_sessions\n\n WHERE personal_session_id = $1\n ", + "query": "\n SELECT personal_session_id\n , owner_user_id\n , owner_oauth2_client_id\n , actor_user_id\n , scope_list\n , created_at\n , revoked_at\n , human_name\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM personal_sessions\n\n WHERE personal_session_id = $1\n ", "describe": { "columns": [ { @@ -15,36 +15,41 @@ }, { "ordinal": 2, - "name": "actor_user_id", + "name": "owner_oauth2_client_id", "type_info": "Uuid" }, { "ordinal": 3, + "name": "actor_user_id", + "type_info": "Uuid" + }, + { + "ordinal": 4, "name": "scope_list", "type_info": "TextArray" }, { - "ordinal": 4, + "ordinal": 5, "name": "created_at", "type_info": "Timestamptz" }, { - "ordinal": 5, + "ordinal": 6, "name": "revoked_at", "type_info": "Timestamptz" }, { - "ordinal": 6, + "ordinal": 7, "name": "human_name", "type_info": "Text" }, { - "ordinal": 7, + "ordinal": 8, "name": "last_active_at", "type_info": "Timestamptz" }, { - "ordinal": 8, + "ordinal": 9, "name": "last_active_ip: IpAddr", "type_info": "Inet" } @@ -56,7 +61,8 @@ }, "nullable": [ false, - false, + true, + true, false, false, false, @@ -66,5 +72,5 @@ true ] }, - "hash": "8816802493ba098c0705b8a8fa87a18ff07e0b5cd08cc525ac9d5dcceece7311" + "hash": "fd32368fa6cd16a9704cdea54f7729681d450669563dd1178c492ffce51e5ff2" } diff --git a/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql b/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql index 62df7bc3e..0e113b156 100644 --- a/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql +++ b/crates/storage-pg/migrations/20250924132713_personal_access_tokens.sql @@ -7,7 +7,16 @@ -- themselves, allowing tokens to be regenerated whilst still retaining a persistent identifier for them. CREATE TABLE personal_sessions ( personal_session_id UUID NOT NULL PRIMARY KEY, - owner_user_id UUID NOT NULL REFERENCES users(user_id), + + -- If this session is owned by a user, the ID of the user. + -- Null otherwise. + owner_user_id UUID REFERENCES users(user_id), + + -- If this session is owned by an OAuth 2 Client (via Client Credentials grant), + -- the ID of the owning client. + -- Null otherwise. + owner_oauth2_client_id UUID REFERENCES oauth2_clients(oauth2_client_id), + actor_user_id UUID NOT NULL REFERENCES users(user_id), -- A human-readable label, intended to describe what the session is for. human_name TEXT NOT NULL, @@ -18,13 +27,16 @@ CREATE TABLE personal_sessions ( -- If set, none of the tokens will be valid anymore. revoked_at TIMESTAMP WITH TIME ZONE, last_active_at TIMESTAMP WITH TIME ZONE, - last_active_ip INET + last_active_ip INET, + + -- There must be exactly one owner. + CONSTRAINT personal_sessions_exactly_one_owner CHECK ((owner_user_id IS NULL) <> (owner_oauth2_client_id IS NULL)) ); -- Individual tokens. CREATE TABLE personal_access_tokens ( - -- The family this access token belongs to. personal_access_token_id UUID NOT NULL PRIMARY KEY, + -- The session this access token belongs to. personal_session_id UUID NOT NULL REFERENCES personal_sessions(personal_session_id), -- SHA256 of the access token. -- This is a lightweight measure to stop a database backup (or other @@ -51,5 +63,6 @@ CREATE UNIQUE INDEX ON personal_access_tokens (personal_session_id) WHERE revoke -- Add indices to satisfy foreign key backward checks -- (and likely filter queries) -CREATE INDEX ON personal_sessions (owner_user_id); +CREATE INDEX ON personal_sessions (owner_user_id) WHERE owner_user_id IS NOT NULL; +CREATE INDEX ON personal_sessions (owner_oauth2_client_id) WHERE owner_oauth2_client_id IS NOT NULL; CREATE INDEX ON personal_sessions (actor_user_id); diff --git a/crates/storage-pg/src/iden.rs b/crates/storage-pg/src/iden.rs index c2198434e..947d1a86f 100644 --- a/crates/storage-pg/src/iden.rs +++ b/crates/storage-pg/src/iden.rs @@ -114,6 +114,8 @@ pub enum PersonalSessions { Table, PersonalSessionId, OwnerUserId, + #[iden = "owner_oauth2_client_id"] + OwnerOAuth2ClientId, ActorUserId, HumanName, ScopeList, diff --git a/crates/storage-pg/src/personal/mod.rs b/crates/storage-pg/src/personal/mod.rs index 3b19bcfe2..cc2e2413f 100644 --- a/crates/storage-pg/src/personal/mod.rs +++ b/crates/storage-pg/src/personal/mod.rs @@ -15,7 +15,9 @@ pub use session::PgPersonalSessionRepository; #[cfg(test)] mod tests { use chrono::Duration; - use mas_data_model::{Clock, Device, clock::MockClock}; + use mas_data_model::{ + Clock, Device, clock::MockClock, personal::session::PersonalSessionOwner, + }; use mas_storage::{ Pagination, RepositoryAccess, personal::{ @@ -84,14 +86,14 @@ mod tests { .add( &mut rng, &clock, - &admin_user, + (&admin_user).into(), &bot_user, "Test Personal Session".to_owned(), scope.clone(), ) .await .unwrap(); - assert_eq!(session.owner_user_id, admin_user.id); + assert_eq!(session.owner, PersonalSessionOwner::User(admin_user.id)); assert_eq!(session.actor_user_id, bot_user.id); assert!(session.is_valid()); assert!(!session.is_revoked()); @@ -128,7 +130,10 @@ mod tests { .unwrap() .expect("personal session not found"); assert_eq!(session_lookup.id, session.id); - assert_eq!(session_lookup.owner_user_id, admin_user.id); + assert_eq!( + session_lookup.owner, + PersonalSessionOwner::User(admin_user.id) + ); assert_eq!(session_lookup.actor_user_id, bot_user.id); assert_eq!(session_lookup.scope, scope); assert!(session_lookup.is_valid()); @@ -207,7 +212,7 @@ mod tests { .add( &mut rng, &clock, - &admin_user, + (&admin_user).into(), &bot_user, "Test Personal Session".to_owned(), scope, diff --git a/crates/storage-pg/src/personal/session.rs b/crates/storage-pg/src/personal/session.rs index 3b5b0a601..28c725a24 100644 --- a/crates/storage-pg/src/personal/session.rs +++ b/crates/storage-pg/src/personal/session.rs @@ -9,7 +9,7 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; use mas_data_model::{ Clock, User, - personal::session::{PersonalSession, SessionState}, + personal::session::{PersonalSession, PersonalSessionOwner, SessionState}, }; use mas_storage::{ Page, Pagination, @@ -54,7 +54,8 @@ impl<'c> PgPersonalSessionRepository<'c> { #[enum_def] struct PersonalSessionLookup { personal_session_id: Uuid, - owner_user_id: Uuid, + owner_user_id: Option, + owner_oauth2_client_id: Option, actor_user_id: Uuid, human_name: String, scope_list: Vec, @@ -88,10 +89,23 @@ impl TryFrom for PersonalSession { Some(revoked_at) => SessionState::Revoked { revoked_at }, }; + let owner = match (value.owner_user_id, value.owner_oauth2_client_id) { + (Some(owner_user_id), None) => PersonalSessionOwner::User(Ulid::from(owner_user_id)), + (None, Some(owner_oauth2_client_id)) => { + PersonalSessionOwner::OAuth2Client(Ulid::from(owner_oauth2_client_id)) + } + _ => { + // should be impossible (CHECK constraint in Postgres prevents it) + return Err(DatabaseInconsistencyError::on("personal_sessions") + .column("owner_user_id, owner_oauth2_client_id") + .row(id)); + } + }; + Ok(PersonalSession { id, state, - owner_user_id: Ulid::from(value.owner_user_id), + owner, actor_user_id: Ulid::from(value.actor_user_id), human_name: value.human_name, scope, @@ -121,6 +135,7 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { r#" SELECT personal_session_id , owner_user_id + , owner_oauth2_client_id , actor_user_id , scope_list , created_at @@ -157,7 +172,7 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { &mut self, rng: &mut (dyn RngCore + Send), clock: &dyn Clock, - owner_user: &User, + owner: PersonalSessionOwner, actor_user: &User, human_name: String, scope: Scope, @@ -168,20 +183,27 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { let scope_list: Vec = scope.iter().map(|s| s.as_str().to_owned()).collect(); + let (owner_user_id, owner_oauth2_client_id) = match owner { + PersonalSessionOwner::User(ulid) => (Some(Uuid::from(ulid)), None), + PersonalSessionOwner::OAuth2Client(ulid) => (None, Some(Uuid::from(ulid))), + }; + sqlx::query!( r#" INSERT INTO personal_sessions ( personal_session_id , owner_user_id + , owner_oauth2_client_id , actor_user_id , human_name , scope_list , created_at ) - VALUES ($1, $2, $3, $4, $5, $6) + VALUES ($1, $2, $3, $4, $5, $6, $7) "#, Uuid::from(id), - Uuid::from(owner_user.id), + owner_user_id, + owner_oauth2_client_id, Uuid::from(actor_user.id), &human_name, &scope_list, @@ -194,7 +216,7 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { Ok(PersonalSession { id, state: SessionState::Valid, - owner_user_id: owner_user.id, + owner, actor_user_id: actor_user.id, human_name, scope, @@ -262,6 +284,13 @@ impl PersonalSessionRepository for PgPersonalSessionRepository<'_> { Expr::col((PersonalSessions::Table, PersonalSessions::OwnerUserId)), PersonalSessionLookupIden::OwnerUserId, ) + .expr_as( + Expr::col(( + PersonalSessions::Table, + PersonalSessions::OwnerOAuth2ClientId, + )), + PersonalSessionLookupIden::OwnerOauth2ClientId, + ) .expr_as( Expr::col((PersonalSessions::Table, PersonalSessions::ActorUserId)), PersonalSessionLookupIden::ActorUserId, @@ -341,6 +370,13 @@ impl Filter for PersonalSessionFilter<'_> { Expr::col((PersonalSessions::Table, PersonalSessions::OwnerUserId)) .eq(Uuid::from(user.id)) })) + .add_option(self.owner_oauth2_client().map(|client| { + Expr::col(( + PersonalSessions::Table, + PersonalSessions::OwnerOAuth2ClientId, + )) + .eq(Uuid::from(client.id)) + })) .add_option(self.actor_user().map(|user| { Expr::col((PersonalSessions::Table, PersonalSessions::ActorUserId)) .eq(Uuid::from(user.id)) diff --git a/crates/storage/src/personal/session.rs b/crates/storage/src/personal/session.rs index aedb939e0..c090efa30 100644 --- a/crates/storage/src/personal/session.rs +++ b/crates/storage/src/personal/session.rs @@ -5,7 +5,10 @@ use async_trait::async_trait; use chrono::{DateTime, Utc}; -use mas_data_model::{Clock, Device, User, personal::session::PersonalSession}; +use mas_data_model::{ + Client, Clock, Device, User, + personal::session::{PersonalSession, PersonalSessionOwner}, +}; use oauth2_types::scope::Scope; use rand_core::RngCore; use ulid::Ulid; @@ -55,7 +58,7 @@ pub trait PersonalSessionRepository: Send + Sync { &mut self, rng: &mut (dyn RngCore + Send), clock: &dyn Clock, - owner_user: &User, + owner: PersonalSessionOwner, actor_user: &User, human_name: String, scope: Scope, @@ -115,7 +118,7 @@ repository_impl!(PersonalSessionRepository: &mut self, rng: &mut (dyn RngCore + Send), clock: &dyn Clock, - owner_user: &User, + owner: PersonalSessionOwner, actor_user: &User, human_name: String, scope: Scope, @@ -140,6 +143,7 @@ repository_impl!(PersonalSessionRepository: #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] pub struct PersonalSessionFilter<'a> { owner_user: Option<&'a User>, + owner_oauth2_client: Option<&'a Client>, actor_user: Option<&'a User>, device: Option<&'a Device>, state: Option, @@ -173,6 +177,21 @@ impl<'a> PersonalSessionFilter<'a> { self } + /// Get the owner user filter + /// + /// Returns [`None`] if no user filter was set + #[must_use] + pub fn owner_oauth2_client(&self) -> Option<&'a Client> { + self.owner_oauth2_client + } + + /// List sessions owned by a specific user + #[must_use] + pub fn for_owner_oauth2_client(mut self, client: &'a Client) -> Self { + self.owner_oauth2_client = Some(client); + self + } + /// Get the owner user filter /// /// Returns [`None`] if no user filter was set From 2be83dc3afb95e0b3bea941298209493af4e2b62 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 8 Oct 2025 10:23:14 +0200 Subject: [PATCH 138/296] Skip loading the user when finishing a compat session --- .../src/admin/v1/compat_sessions/finish.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/handlers/src/admin/v1/compat_sessions/finish.rs b/crates/handlers/src/admin/v1/compat_sessions/finish.rs index c0299d960..df42c2ff9 100644 --- a/crates/handlers/src/admin/v1/compat_sessions/finish.rs +++ b/crates/handlers/src/admin/v1/compat_sessions/finish.rs @@ -99,17 +99,14 @@ pub async fn handler( return Err(RouteError::AlreadyFinished(id)); } - // Load the user to schedule a device sync job - let user = repo - .user() - .lookup(session.user_id) - .await? - .ok_or_else(|| RouteError::Internal("User not found for session".into()))?; - // Schedule a job to sync the devices of the user with the homeserver - tracing::info!(user.id = %user.id, "Scheduling device sync job for user"); + tracing::info!(user.id = %session.user_id, "Scheduling device sync job for user"); repo.queue_job() - .schedule_job(&mut rng, &clock, SyncDevicesJob::new(&user)) + .schedule_job( + &mut rng, + &clock, + SyncDevicesJob::new_for_id(session.user_id), + ) .await?; // Finish the session From 55634baab9178ce3027f148cbb59b6303646ef93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:16:32 +0000 Subject: [PATCH 139/296] build(deps): bump the opentelemetry group with 2 updates Bumps the opentelemetry group with 2 updates: [opentelemetry-prometheus-text-exporter](https://github.com/sandhose/opentelemetry-prometheus-text-exporter) and [opentelemetry_sdk](https://github.com/open-telemetry/opentelemetry-rust). Updates `opentelemetry-prometheus-text-exporter` from 0.2.0 to 0.2.1 - [Release notes](https://github.com/sandhose/opentelemetry-prometheus-text-exporter/releases) - [Changelog](https://github.com/sandhose/opentelemetry-prometheus-text-exporter/blob/main/CHANGELOG.md) - [Commits](https://github.com/sandhose/opentelemetry-prometheus-text-exporter/compare/v0.2.0...v0.2.1) Updates `opentelemetry_sdk` from 0.30.0 to 0.31.0 - [Release notes](https://github.com/open-telemetry/opentelemetry-rust/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-rust/blob/main/docs/release_0.30.md) - [Commits](https://github.com/open-telemetry/opentelemetry-rust/compare/opentelemetry_sdk-0.30.0...v0.31.0) --- updated-dependencies: - dependency-name: opentelemetry-prometheus-text-exporter dependency-version: 0.2.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: opentelemetry - dependency-name: opentelemetry_sdk dependency-version: 0.31.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: opentelemetry ... Signed-off-by: dependabot[bot] --- Cargo.lock | 76 +++++++++++++++++++++++++++++++----------------------- Cargo.toml | 20 +++++++------- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 253308775..13ed17dac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4088,7 +4088,7 @@ dependencies = [ "sha1", "sha2", "sprintf", - "thiserror 1.0.69", + "thiserror 2.0.17", "tokio", "tracing", "urlencoding", @@ -4110,9 +4110,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "opentelemetry" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" dependencies = [ "futures-core", "futures-sink", @@ -4124,9 +4124,9 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", @@ -4137,18 +4137,18 @@ dependencies = [ [[package]] name = "opentelemetry-jaeger-propagator" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090b8ec07bb2e304b529581aa1fe530d7861298c9ef549ebbf44a4a56472c539" +checksum = "ba3bbd907f151104a112f749f3b8387ef669b7264e0bb80546ea0700a3b307b7" dependencies = [ "opentelemetry", ] [[package]] name = "opentelemetry-otlp" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ "http", "opentelemetry", @@ -4161,9 +4161,9 @@ dependencies = [ [[package]] name = "opentelemetry-prometheus-text-exporter" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddbb5743c13741bd9207de7c449f9797c0e513ac07551eac807da94056c530d9" +checksum = "897906366b17a89bec845f6051e0c3474049402a09a0711eea180941293bd013" dependencies = [ "opentelemetry", "opentelemetry_sdk", @@ -4172,21 +4172,22 @@ dependencies = [ [[package]] name = "opentelemetry-proto" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ "opentelemetry", "opentelemetry_sdk", "prost", "tonic", + "tonic-prost", ] [[package]] name = "opentelemetry-resource-detectors" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a44e076f07fa3d76e741991f4f7d3ecbac0eed8521ced491fbdf8db77d024cf" +checksum = "e82845106cf72d47c141cee7f0d95e0650d8f28c6222a1f1ae727a8883899c19" dependencies = [ "opentelemetry", "opentelemetry-semantic-conventions", @@ -4195,15 +4196,15 @@ dependencies = [ [[package]] name = "opentelemetry-semantic-conventions" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" [[package]] name = "opentelemetry-stdout" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447191061af41c3943e082ea359ab8b64ff27d6d34d30d327df309ddef1eef6f" +checksum = "bc8887887e169414f637b18751487cce4e095be787d23fad13c454e2fb1b3811" dependencies = [ "chrono", "opentelemetry", @@ -4212,9 +4213,9 @@ dependencies = [ [[package]] name = "opentelemetry_sdk" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" dependencies = [ "futures-channel", "futures-executor", @@ -4222,7 +4223,6 @@ dependencies = [ "opentelemetry", "percent-encoding", "rand 0.9.2", - "serde_json", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -4654,9 +4654,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", "prost-derive", @@ -4664,9 +4664,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" dependencies = [ "anyhow", "itertools 0.14.0", @@ -6427,9 +6427,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" dependencies = [ "async-trait", "base64", @@ -6439,13 +6439,24 @@ dependencies = [ "http-body-util", "percent-encoding", "pin-project", - "prost", + "sync_wrapper", "tokio-stream", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.2" @@ -6572,14 +6583,15 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e" dependencies = [ "js-sys", - "once_cell", "opentelemetry", "opentelemetry_sdk", + "rustversion", + "thiserror 2.0.17", "tracing", "tracing-core", "tracing-subscriber", diff --git a/Cargo.toml b/Cargo.toml index 8d525c706..80c949184 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -396,36 +396,36 @@ version = "0.1.7" # OpenTelemetry [workspace.dependencies.opentelemetry] -version = "0.30.0" +version = "0.31.0" features = ["trace", "metrics"] [workspace.dependencies.opentelemetry-http] -version = "0.30.0" +version = "0.31.0" features = ["reqwest"] [workspace.dependencies.opentelemetry-jaeger-propagator] -version = "0.30.0" +version = "0.31.0" [workspace.dependencies.opentelemetry-otlp] -version = "0.30.0" +version = "0.31.0" default-features = false features = ["trace", "metrics", "http-proto"] [workspace.dependencies.opentelemetry-prometheus-text-exporter] -version = "0.2.0" +version = "0.2.1" [workspace.dependencies.opentelemetry-resource-detectors] -version = "0.9.0" +version = "0.10.0" [workspace.dependencies.opentelemetry-semantic-conventions] -version = "0.30.0" +version = "0.31.0" features = ["semconv_experimental"] [workspace.dependencies.opentelemetry-stdout] -version = "0.30.0" +version = "0.31.0" features = ["trace", "metrics"] [workspace.dependencies.opentelemetry_sdk] -version = "0.30.0" +version = "0.31.0" features = [ "experimental_trace_batch_span_processor_with_async_runtime", "experimental_metrics_periodicreader_with_async_runtime", "rt-tokio", ] [workspace.dependencies.tracing-opentelemetry] -version = "0.31.0" +version = "0.32.0" default-features = false # P256 elliptic curve From df45543e2e4a8c912d6918be452852b4dfca2e7d Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 8 Oct 2025 11:12:30 +0200 Subject: [PATCH 140/296] Adapt to the new tracing-opentelemetry API --- crates/cli/src/server.rs | 7 ++++++- crates/context/src/fmt.rs | 36 ++++++++---------------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/crates/cli/src/server.rs b/crates/cli/src/server.rs index 9ce9b3a52..4279e7e4a 100644 --- a/crates/cli/src/server.rs +++ b/crates/cli/src/server.rs @@ -143,7 +143,12 @@ fn make_http_span(req: &Request) -> Span { propagator.extract_with_context(&context, &extractor) }); - span.set_parent(parent_context); + if let Err(err) = span.set_parent(parent_context) { + tracing::error!( + error = &err as &dyn std::error::Error, + "Failed to set parent context on span" + ); + } span } diff --git a/crates/context/src/fmt.rs b/crates/context/src/fmt.rs index 25908a2ca..f4c4981e1 100644 --- a/crates/context/src/fmt.rs +++ b/crates/context/src/fmt.rs @@ -4,10 +4,7 @@ // Please see LICENSE files in the repository root for full details. use console::{Color, Style}; -use opentelemetry::{ - TraceId, - trace::{SamplingDecision, TraceContextExt}, -}; +use opentelemetry::TraceId; use tracing::{Level, Subscriber}; use tracing_opentelemetry::OtelData; use tracing_subscriber::{ @@ -131,31 +128,14 @@ where // If we have a OTEL span, we can add the trace ID to the end of the log line if let Some(span) = ctx.lookup_current() && let Some(otel) = span.extensions().get::() + && let Some(trace_id) = otel.trace_id() + && trace_id != TraceId::INVALID { - let parent_cx_span = otel.parent_cx.span(); - let sc = parent_cx_span.span_context(); - - // Check if the span is sampled, first from the span builder, - // then from the parent context if nothing is set there - if otel - .builder - .sampling_result - .as_ref() - .map_or(sc.is_sampled(), |r| { - r.decision == SamplingDecision::RecordAndSample - }) - { - // If it is the root span, the trace ID will be in the span builder. Else, it - // will be in the parent OTEL context - let trace_id = otel.builder.trace_id.unwrap_or(sc.trace_id()); - if trace_id != TraceId::INVALID { - let label = Style::new() - .italic() - .force_styling(ansi) - .apply_to("trace.id"); - write!(&mut writer, " {label}={trace_id}")?; - } - } + let label = Style::new() + .italic() + .force_styling(ansi) + .apply_to("trace.id"); + write!(&mut writer, " {label}={trace_id}")?; } writeln!(&mut writer) From cbc5f4c66eaf8955d0f8036c0cc06e66ee634a53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:22:35 +0000 Subject: [PATCH 141/296] build(deps-dev): bump vite in /frontend in the vite group Bumps the vite group in /frontend with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.1.7 to 7.1.9 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v7.1.9/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 7.1.9 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 8 ++++---- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index adc4de99e..efb992d45 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -65,7 +65,7 @@ "storybook": "^9.1.5", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.7", + "vite": "7.1.9", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", @@ -13273,9 +13273,9 @@ } }, "node_modules/vite": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz", - "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==", + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 9dffe59a4..ba5a6b99a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -75,7 +75,7 @@ "storybook": "^9.1.5", "tailwindcss": "^3.4.17", "typescript": "^5.9.2", - "vite": "7.1.7", + "vite": "7.1.9", "vite-plugin-compression": "^0.5.1", "vite-plugin-graphql-codegen": "^3.7.0", "vite-plugin-manifest-sri": "^0.2.0", From ba104bc12c5ff9e07d874d596ebb17c45c78ce9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:22:55 +0000 Subject: [PATCH 142/296] build(deps): bump the react group in /frontend with 2 updates Bumps the react group in /frontend with 2 updates: [react](https://github.com/facebook/react/tree/HEAD/packages/react) and [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom). Updates `react` from 19.1.1 to 19.2.0 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.0/packages/react) Updates `react-dom` from 19.1.1 to 19.2.0 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.0/packages/react-dom) --- updated-dependencies: - dependency-name: react dependency-version: 19.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: react - dependency-name: react-dom dependency-version: 19.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: react ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 44 +++++++++++++++++++------------------- frontend/package.json | 8 +++---- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index adc4de99e..e575ef45e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -21,8 +21,8 @@ "classnames": "^2.5.1", "date-fns": "^4.1.0", "i18next": "^25.5.3", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-i18next": "^16.0.0", "swagger-ui-dist": "^5.29.1", "valibot": "^1.1.0", @@ -45,8 +45,8 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^24.7.0", - "@types/react": "19.1.16", - "@types/react-dom": "19.1.9", + "@types/react": "19.2.2", + "@types/react-dom": "19.2.1", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.4", "@vitest/coverage-v8": "^3.2.4", @@ -5877,9 +5877,9 @@ } }, "node_modules/@types/react": { - "version": "19.1.16", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.16.tgz", - "integrity": "sha512-WBM/nDbEZmDUORKnh5i1bTnAz6vTohUf9b8esSMu+b24+srbaxa04UbJgWx78CVfNXA20sNu0odEIluZDFdCog==", + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -5887,13 +5887,13 @@ } }, "node_modules/@types/react-dom": { - "version": "19.1.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", - "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", "devOptional": true, "license": "MIT", "peerDependencies": { - "@types/react": "^19.0.0" + "@types/react": "^19.2.0" } }, "node_modules/@types/resolve": { @@ -11167,9 +11167,9 @@ } }, "node_modules/react": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", - "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11208,15 +11208,15 @@ } }, "node_modules/react-dom": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", - "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.1.1" + "react": "^19.2.0" } }, "node_modules/react-i18next": { @@ -11803,9 +11803,9 @@ "license": "MIT" }, "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/semver": { diff --git a/frontend/package.json b/frontend/package.json index 9dffe59a4..003dd158b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,8 +31,8 @@ "classnames": "^2.5.1", "date-fns": "^4.1.0", "i18next": "^25.5.3", - "react": "^19.1.1", - "react-dom": "^19.1.1", + "react": "^19.2.0", + "react-dom": "^19.2.0", "react-i18next": "^16.0.0", "swagger-ui-dist": "^5.29.1", "valibot": "^1.1.0", @@ -55,8 +55,8 @@ "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", "@types/node": "^24.7.0", - "@types/react": "19.1.16", - "@types/react-dom": "19.1.9", + "@types/react": "19.2.2", + "@types/react-dom": "19.2.1", "@types/swagger-ui-dist": "^3.30.6", "@vitejs/plugin-react": "^5.0.4", "@vitest/coverage-v8": "^3.2.4", From 8ea0208adc7e5ca72ac5be56746395d12288877c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:23:11 +0000 Subject: [PATCH 143/296] build(deps-dev): bump @graphql-codegen/client-preset Bumps the graphql-codegen group in /frontend with 1 update: [@graphql-codegen/client-preset](https://github.com/dotansimha/graphql-code-generator/tree/HEAD/packages/presets/client). Updates `@graphql-codegen/client-preset` from 5.0.2 to 5.1.0 - [Release notes](https://github.com/dotansimha/graphql-code-generator/releases) - [Changelog](https://github.com/dotansimha/graphql-code-generator/blob/master/packages/presets/client/CHANGELOG.md) - [Commits](https://github.com/dotansimha/graphql-code-generator/commits/@graphql-codegen/client-preset@5.1.0/packages/presets/client) --- updated-dependencies: - dependency-name: "@graphql-codegen/client-preset" dependency-version: 5.1.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: graphql-codegen ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 58 +++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index adc4de99e..d1a6d653f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -34,7 +34,7 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@graphql-codegen/cli": "^6.0.0", - "@graphql-codegen/client-preset": "^5.0.2", + "@graphql-codegen/client-preset": "^5.1.0", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.10", "@storybook/react-vite": "^9.1.10", @@ -2008,21 +2008,21 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/client-preset": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.0.2.tgz", - "integrity": "sha512-lBkVMz7QA7FHWb71BcNB/tFFOh0LDNCPIBaJ70Lj1SIPjOfCEYmbkK6D5piPZu87m60hyWN3XDwNHEH8eGoXNA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-5.1.0.tgz", + "integrity": "sha512-MYMy9dIlAgT3q1U8WUys6Y8yt/T9WLsm1DczRtrCpV5N11v4Rlg3hGWQmEvhJtBbWxgzfYoHZHb0TohtbLkJ+g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", "@graphql-codegen/add": "^6.0.0", - "@graphql-codegen/gql-tag-operations": "5.0.1", + "@graphql-codegen/gql-tag-operations": "5.0.2", "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/typed-document-node": "^6.0.1", - "@graphql-codegen/typescript": "^5.0.1", - "@graphql-codegen/typescript-operations": "^5.0.1", - "@graphql-codegen/visitor-plugin-common": "^6.0.1", + "@graphql-codegen/typed-document-node": "^6.0.2", + "@graphql-codegen/typescript": "^5.0.2", + "@graphql-codegen/typescript-operations": "^5.0.2", + "@graphql-codegen/visitor-plugin-common": "^6.1.0", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -2075,14 +2075,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.0.1.tgz", - "integrity": "sha512-GVd/B6mtRAXg6UxgeO805P7VDrCmVIb6qIMrE7O69j8e4EqIt/URdmJ7On+Bn8IIKp7TcpcLSo/VI28ptcssNw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-5.0.2.tgz", + "integrity": "sha512-iK+LFGv4ihHKeerADFPTL7Iq4iNr+J1jm2+GUMtwTSAL4nGk+BdfyruV7eR53R7Des8NFdI+9hBzKbbob7VwGQ==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.1", + "@graphql-codegen/visitor-plugin-common": "6.1.0", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" @@ -2155,14 +2155,14 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.0.1.tgz", - "integrity": "sha512-z0vvvmwfdozkY1AFqbNLeb/jAWyVwWJOIllZEEwPDKcVtCMPQZ1DRApPMRDRndRL6fOG4aXXnt7C5kgniC+qGw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-6.0.2.tgz", + "integrity": "sha512-nqcD23F87jLPQ1P2jJaepNAa4SY8Xy2soacPyQMwvxWtbRSXlg/LBUjtbEkCaU2SuLoa4L3w8VPuGoQ3EWUzeg==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.1", + "@graphql-codegen/visitor-plugin-common": "6.1.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -2182,15 +2182,15 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.1.tgz", - "integrity": "sha512-GqAl4pxFdWTvW1h+Ume7djrucYwt03wiaS88m4ErG+tHsJaR2ZCtoHOo+B4bh7KIuBKap14/xOZG0qY/ThWAhg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-OJYXpS9SRf4VFzqu3ZH/RmTftGhAVTCmscH63iPlvTlCT8NBmpSHdZ875AEa38LugdL8XgUcGsI3pprP3e5j/w==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", "@graphql-codegen/schema-ast": "^5.0.0", - "@graphql-codegen/visitor-plugin-common": "6.0.1", + "@graphql-codegen/visitor-plugin-common": "6.1.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2519,15 +2519,15 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.1.tgz", - "integrity": "sha512-uJwsOIqvXyxlOI1Mnoy8Mn3TiOHTzVTGDwqL9gHnpKqQZdFfvMgfDf/HyT7Mw3XCOfhSS99fe9ATW0bkMExBZg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-5.0.2.tgz", + "integrity": "sha512-i2nSJ5a65H+JgXwWvEuYehVYUImIvrHk3PTs+Fcj+OjZFvDl2qBziIhr6shCjV0KH9IZ6Y+1v4TzkxZr/+XFjA==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^6.0.0", - "@graphql-codegen/typescript": "^5.0.1", - "@graphql-codegen/visitor-plugin-common": "6.0.1", + "@graphql-codegen/typescript": "^5.0.2", + "@graphql-codegen/visitor-plugin-common": "6.1.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -2559,9 +2559,9 @@ "license": "0BSD" }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.0.1.tgz", - "integrity": "sha512-3gopoUYXn26PSj2UdCWmYj0QiRVD5qR3eDiXx72OQcN1Vb8qj6VfOWB+NDuD1Q1sgVYbCQVKgj92ERsSW1xH9Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-6.1.0.tgz", + "integrity": "sha512-AvGO1pe+b/kAa7+WBDlNDXOruRZWv/NnhLHgTggiW2XWRv33biuzg4cF1UTdpR2jmESZzJU4kXngLLX8RYJWLA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 9dffe59a4..041e232ce 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -44,7 +44,7 @@ "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", "@graphql-codegen/cli": "^6.0.0", - "@graphql-codegen/client-preset": "^5.0.2", + "@graphql-codegen/client-preset": "^5.1.0", "@graphql-codegen/typescript-msw": "^3.0.1", "@storybook/addon-docs": "^9.1.10", "@storybook/react-vite": "^9.1.10", From ff3ad020007406e66b1850eb620a2285d7ce9d8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:23:32 +0000 Subject: [PATCH 144/296] build(deps-dev): bump @biomejs/biome from 2.2.4 to 2.2.5 in /frontend Bumps [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome) from 2.2.4 to 2.2.5. - [Release notes](https://github.com/biomejs/biome/releases) - [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md) - [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.2.5/packages/@biomejs/biome) --- updated-dependencies: - dependency-name: "@biomejs/biome" dependency-version: 2.2.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 72 +++++++++++++++++++------------------- frontend/package.json | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index adc4de99e..bb3d88b10 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -29,7 +29,7 @@ "vaul": "^1.1.2" }, "devDependencies": { - "@biomejs/biome": "^2.2.4", + "@biomejs/biome": "^2.2.5", "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", @@ -1034,9 +1034,9 @@ } }, "node_modules/@biomejs/biome": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.4.tgz", - "integrity": "sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.5.tgz", + "integrity": "sha512-zcIi+163Rc3HtyHbEO7CjeHq8DjQRs40HsGbW6vx2WI0tg8mYQOPouhvHSyEnCBAorfYNnKdR64/IxO7xQ5faw==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -1050,20 +1050,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.2.4", - "@biomejs/cli-darwin-x64": "2.2.4", - "@biomejs/cli-linux-arm64": "2.2.4", - "@biomejs/cli-linux-arm64-musl": "2.2.4", - "@biomejs/cli-linux-x64": "2.2.4", - "@biomejs/cli-linux-x64-musl": "2.2.4", - "@biomejs/cli-win32-arm64": "2.2.4", - "@biomejs/cli-win32-x64": "2.2.4" + "@biomejs/cli-darwin-arm64": "2.2.5", + "@biomejs/cli-darwin-x64": "2.2.5", + "@biomejs/cli-linux-arm64": "2.2.5", + "@biomejs/cli-linux-arm64-musl": "2.2.5", + "@biomejs/cli-linux-x64": "2.2.5", + "@biomejs/cli-linux-x64-musl": "2.2.5", + "@biomejs/cli-win32-arm64": "2.2.5", + "@biomejs/cli-win32-x64": "2.2.5" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.4.tgz", - "integrity": "sha512-RJe2uiyaloN4hne4d2+qVj3d3gFJFbmrr5PYtkkjei1O9c+BjGXgpUPVbi8Pl8syumhzJjFsSIYkcLt2VlVLMA==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.5.tgz", + "integrity": "sha512-MYT+nZ38wEIWVcL5xLyOhYQQ7nlWD0b/4mgATW2c8dvq7R4OQjt/XGXFkXrmtWmQofaIM14L7V8qIz/M+bx5QQ==", "cpu": [ "arm64" ], @@ -1078,9 +1078,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.4.tgz", - "integrity": "sha512-cFsdB4ePanVWfTnPVaUX+yr8qV8ifxjBKMkZwN7gKb20qXPxd/PmwqUH8mY5wnM9+U0QwM76CxFyBRJhC9tQwg==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.5.tgz", + "integrity": "sha512-FLIEl73fv0R7dI10EnEiZLw+IMz3mWLnF95ASDI0kbx6DDLJjWxE5JxxBfmG+udz1hIDd3fr5wsuP7nwuTRdAg==", "cpu": [ "x64" ], @@ -1095,9 +1095,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.4.tgz", - "integrity": "sha512-M/Iz48p4NAzMXOuH+tsn5BvG/Jb07KOMTdSVwJpicmhN309BeEyRyQX+n1XDF0JVSlu28+hiTQ2L4rZPvu7nMw==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.5.tgz", + "integrity": "sha512-5DjiiDfHqGgR2MS9D+AZ8kOfrzTGqLKywn8hoXpXXlJXIECGQ32t+gt/uiS2XyGBM2XQhR6ztUvbjZWeccFMoQ==", "cpu": [ "arm64" ], @@ -1112,9 +1112,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.4.tgz", - "integrity": "sha512-7TNPkMQEWfjvJDaZRSkDCPT/2r5ESFPKx+TEev+I2BXDGIjfCZk2+b88FOhnJNHtksbOZv8ZWnxrA5gyTYhSsQ==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.5.tgz", + "integrity": "sha512-5Ov2wgAFwqDvQiESnu7b9ufD1faRa+40uwrohgBopeY84El2TnBDoMNXx6iuQdreoFGjwW8vH6k68G21EpNERw==", "cpu": [ "arm64" ], @@ -1129,9 +1129,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.4.tgz", - "integrity": "sha512-orr3nnf2Dpb2ssl6aihQtvcKtLySLta4E2UcXdp7+RTa7mfJjBgIsbS0B9GC8gVu0hjOu021aU8b3/I1tn+pVQ==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.5.tgz", + "integrity": "sha512-fq9meKm1AEXeAWan3uCg6XSP5ObA6F/Ovm89TwaMiy1DNIwdgxPkNwxlXJX8iM6oRbFysYeGnT0OG8diCWb9ew==", "cpu": [ "x64" ], @@ -1146,9 +1146,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.4.tgz", - "integrity": "sha512-m41nFDS0ksXK2gwXL6W6yZTYPMH0LughqbsxInSKetoH6morVj43szqKx79Iudkp8WRT5SxSh7qVb8KCUiewGg==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.5.tgz", + "integrity": "sha512-AVqLCDb/6K7aPNIcxHaTQj01sl1m989CJIQFQEaiQkGr2EQwyOpaATJ473h+nXDUuAcREhccfRpe/tu+0wu0eQ==", "cpu": [ "x64" ], @@ -1163,9 +1163,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.4.tgz", - "integrity": "sha512-NXnfTeKHDFUWfxAefa57DiGmu9VyKi0cDqFpdI+1hJWQjGJhJutHPX0b5m+eXvTKOaf+brU+P0JrQAZMb5yYaQ==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.5.tgz", + "integrity": "sha512-xaOIad4wBambwJa6mdp1FigYSIF9i7PCqRbvBqtIi9y29QtPVQ13sDGtUnsRoe6SjL10auMzQ6YAe+B3RpZXVg==", "cpu": [ "arm64" ], @@ -1180,9 +1180,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.4.tgz", - "integrity": "sha512-3Y4V4zVRarVh/B/eSHczR4LYoSVyv3Dfuvm3cWs5w/HScccS0+Wt/lHOcDTRYeHjQmMYVC3rIRWqyN2EI52+zg==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.5.tgz", + "integrity": "sha512-F/jhuXCssPFAuciMhHKk00xnCAxJRS/pUzVfXYmOMUp//XW7mO6QeCjsjvnm8L4AO/dG2VOB0O+fJPiJ2uXtIw==", "cpu": [ "x64" ], diff --git a/frontend/package.json b/frontend/package.json index 9dffe59a4..cd7833d7b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,7 +39,7 @@ "vaul": "^1.1.2" }, "devDependencies": { - "@biomejs/biome": "^2.2.4", + "@biomejs/biome": "^2.2.5", "@browser-logos/chrome": "^2.0.0", "@browser-logos/firefox": "^3.0.10", "@browser-logos/safari": "^2.1.0", From 4307995fa12e5cb7719430369710567a6c2ef008 Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Wed, 8 Oct 2025 11:25:05 +0200 Subject: [PATCH 145/296] Update snapshots --- .../CompatSessionDetail.test.tsx.snap | 16 +-- .../OAuth2SessionDetail.test.tsx.snap | 10 +- .../__snapshots__/CompatSession.test.tsx.snap | 2 +- .../__snapshots__/OAuth2Session.test.tsx.snap | 2 +- .../account/__snapshots__/index.test.tsx.snap | 112 +++++++++--------- 5 files changed, 71 insertions(+), 71 deletions(-) diff --git a/frontend/src/components/SessionDetail/__snapshots__/CompatSessionDetail.test.tsx.snap b/frontend/src/components/SessionDetail/__snapshots__/CompatSessionDetail.test.tsx.snap index d07848769..7849c7661 100644 --- a/frontend/src/components/SessionDetail/__snapshots__/CompatSessionDetail.test.tsx.snap +++ b/frontend/src/components/SessionDetail/__snapshots__/CompatSessionDetail.test.tsx.snap @@ -29,10 +29,10 @@ exports[` > renders a compatability session details 1`] = ` > element.io: Unknown device