From 57501d446f9d8753c56d171661f46582a6545ff1 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 8 Dec 2025 17:16:39 -0800 Subject: [PATCH 01/23] submissions-api: add audit events --- submissions-api-rs/src/external.rs | 30 +++++++ submissions-api-rs/src/types.rs | 130 +++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) diff --git a/submissions-api-rs/src/external.rs b/submissions-api-rs/src/external.rs index 8b8b6aa..1d929a8 100644 --- a/submissions-api-rs/src/external.rs +++ b/submissions-api-rs/src/external.rs @@ -263,6 +263,36 @@ impl Context{ ).await.map_err(Error::Response)? .json().await.map_err(Error::ReqwestJson) } + pub async fn get_mapfix_audit_events(&self,config:GetMapfixAuditEventsRequest)->Result,Error>{ + let url_raw=format!("{}/mapfixes/{}/audit-events",self.0.base_url,config.MapfixID); + let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?; + + { + let mut query_pairs=url.query_pairs_mut(); + query_pairs.append_pair("Page",config.Page.to_string().as_str()); + query_pairs.append_pair("Limit",config.Limit.to_string().as_str()); + } + + response_ok( + self.0.get(url).await.map_err(Error::Reqwest)? + ).await.map_err(Error::Response)? + .json().await.map_err(Error::ReqwestJson) + } + pub async fn get_submission_audit_events(&self,config:GetSubmissionAuditEventsRequest)->Result,Error>{ + let url_raw=format!("{}/submissions/{}/audit-events",self.0.base_url,config.SubmissionID); + let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?; + + { + let mut query_pairs=url.query_pairs_mut(); + query_pairs.append_pair("Page",config.Page.to_string().as_str()); + query_pairs.append_pair("Limit",config.Limit.to_string().as_str()); + } + + response_ok( + self.0.get(url).await.map_err(Error::Reqwest)? + ).await.map_err(Error::Response)? + .json().await.map_err(Error::ReqwestJson) + } pub async fn release_submissions(&self,config:ReleaseRequest<'_>)->Result{ let url_raw=format!("{}/release-submissions",self.0.base_url); let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?; diff --git a/submissions-api-rs/src/types.rs b/submissions-api-rs/src/types.rs index d695e66..219c440 100644 --- a/submissions-api-rs/src/types.rs +++ b/submissions-api-rs/src/types.rs @@ -404,6 +404,120 @@ pub struct MapResponse{ pub Date:i64, } +#[allow(nonstandard_style)] +#[derive(Clone,Debug)] +pub struct GetMapfixAuditEventsRequest{ + pub Page:u32, + pub Limit:u32, + pub MapfixID:i64, +} + +#[allow(nonstandard_style)] +#[derive(Clone,Debug)] +pub struct GetSubmissionAuditEventsRequest{ + pub Page:u32, + pub Limit:u32, + pub SubmissionID:i64, +} + +#[allow(nonstandard_style)] +#[derive(Clone,Debug,serde_repr::Deserialize_repr)] +#[repr(u32)] +pub enum AuditEventType{ + Action=0, + Comment=1, + ChangeModel=2, + ChangeValidatedModel=3, + ChangeDisplayName=4, + ChangeCreator=5, + Error=6, + CheckList=7, +} + + +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventAction{ + pub target_status:MapfixStatus, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventComment{ + pub comment:String, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventChangeModel{ + pub old_model_id:u64, + pub old_model_version:u64, + pub new_model_id:u64, + pub new_model_version:u64, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventChangeValidatedModel{ + pub validated_model_id:u64, + pub validated_model_version:u64, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventChangeName{ + pub old_name:String, + pub new_name:String, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventError{ + pub error:String, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventCheck{ + pub name:String, + pub summary:String, + pub passed:bool, +} +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventCheckList{ + pub check_list:Vec, +} + +#[allow(nonstandard_style)] +#[derive(Clone,Debug)] +pub enum AuditEventData{ + Action(AuditEventAction), + Comment(AuditEventComment), + ChangeModel(AuditEventChangeModel), + ChangeValidatedModel(AuditEventChangeValidatedModel), + ChangeDisplayName(AuditEventChangeName), + ChangeCreator(AuditEventChangeName), + Error(AuditEventError), + CheckList(AuditEventCheckList), +} + +#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)] +pub struct AuditEventID(pub(crate)i64); + +#[allow(nonstandard_style)] +#[derive(Clone,Debug,serde::Deserialize)] +pub struct AuditEventReponse{ + pub ID:AuditEventID, + pub Date:i64, + pub User:u64, + pub Username:String, + pub ResourceType:ResourceType, + pub ResourceID:ResourceID, + pub EventType:AuditEventType, + EventData:serde_json::Value, +} +impl AuditEventReponse{ + pub fn data(self)->serde_json::Result{ + Ok(match self.EventType{ + AuditEventType::Action=>AuditEventData::Action(serde_json::from_value(self.EventData)?), + AuditEventType::Comment=>AuditEventData::Comment(serde_json::from_value(self.EventData)?), + AuditEventType::ChangeModel=>AuditEventData::ChangeModel(serde_json::from_value(self.EventData)?), + AuditEventType::ChangeValidatedModel=>AuditEventData::ChangeValidatedModel(serde_json::from_value(self.EventData)?), + AuditEventType::ChangeDisplayName=>AuditEventData::ChangeDisplayName(serde_json::from_value(self.EventData)?), + AuditEventType::ChangeCreator=>AuditEventData::ChangeCreator(serde_json::from_value(self.EventData)?), + AuditEventType::Error=>AuditEventData::Error(serde_json::from_value(self.EventData)?), + AuditEventType::CheckList=>AuditEventData::CheckList(serde_json::from_value(self.EventData)?), + }) + } +} + #[allow(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct Check{ @@ -457,6 +571,14 @@ pub struct CreateSubmissionAuditCheckListRequest<'a>{ #[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)] pub struct SubmissionID(pub(crate)i64); +impl SubmissionID{ + pub const fn new(value:i64)->Self{ + Self(value) + } + pub const fn value(&self)->i64{ + self.0 + } +} #[allow(nonstandard_style)] #[derive(Clone,Debug)] @@ -510,6 +632,14 @@ pub struct CreateMapfixAuditCheckListRequest<'a>{ #[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)] pub struct MapfixID(pub(crate)i64); +impl MapfixID{ + pub const fn new(value:i64)->Self{ + Self(value) + } + pub const fn value(&self)->i64{ + self.0 + } +} #[allow(nonstandard_style)] #[derive(Clone,Debug)] -- 2.49.1 From 3400056c2380b4d7e9c1f23593edbd460f640d64 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Mon, 8 Dec 2025 18:10:32 -0800 Subject: [PATCH 02/23] submissions-api: v0.10.1 audit events --- Cargo.lock | 2 +- submissions-api-rs/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9e23988..a9246fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2019,7 +2019,7 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "submissions-api" -version = "0.10.0" +version = "0.10.1" dependencies = [ "chrono", "reqwest", diff --git a/submissions-api-rs/Cargo.toml b/submissions-api-rs/Cargo.toml index a7da31d..6582457 100644 --- a/submissions-api-rs/Cargo.toml +++ b/submissions-api-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "submissions-api" -version = "0.10.0" +version = "0.10.1" edition = "2024" publish = ["strafesnet"] repository = "https://git.itzana.me/StrafesNET/maps-service" -- 2.49.1 From 09022e7292d631e440fdb23ae81fe8034aca95b6 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 9 Dec 2025 14:34:16 -0800 Subject: [PATCH 03/23] change allow to expect --- submissions-api-rs/src/types.rs | 92 ++++++++++----------- validation/src/check.rs | 8 +- validation/src/check_mapfix.rs | 2 +- validation/src/check_submission.rs | 2 +- validation/src/create.rs | 6 +- validation/src/create_mapfix.rs | 2 +- validation/src/create_submission.rs | 2 +- validation/src/download.rs | 2 +- validation/src/main.rs | 2 +- validation/src/message_handler.rs | 2 +- validation/src/nats_types.rs | 22 ++--- validation/src/rbx_util.rs | 2 +- validation/src/release_submissions_batch.rs | 2 +- validation/src/upload_mapfix.rs | 4 +- validation/src/upload_submission.rs | 4 +- validation/src/validate_mapfix.rs | 2 +- validation/src/validate_submission.rs | 2 +- validation/src/validator.rs | 4 +- 18 files changed, 80 insertions(+), 82 deletions(-) diff --git a/submissions-api-rs/src/types.rs b/submissions-api-rs/src/types.rs index 219c440..f89d883 100644 --- a/submissions-api-rs/src/types.rs +++ b/submissions-api-rs/src/types.rs @@ -30,7 +30,7 @@ impl std::error::Error for SingleItemError where Items:std::fmt::D pub type ScriptSingleItemError=SingleItemError>; pub type ScriptPolicySingleItemError=SingleItemError>; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub struct UrlAndBody{ pub url:url::Url, @@ -76,7 +76,7 @@ pub enum GameID{ FlyTrials=5, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct CreateMapfixRequest<'a>{ pub OperationID:OperationID, @@ -89,13 +89,13 @@ pub struct CreateMapfixRequest<'a>{ pub TargetAssetID:u64, pub Description:&'a str, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct MapfixIDResponse{ pub MapfixID:MapfixID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct CreateSubmissionRequest<'a>{ pub OperationID:OperationID, @@ -108,7 +108,7 @@ pub struct CreateSubmissionRequest<'a>{ pub Status:u32, pub Roles:u32, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct SubmissionIDResponse{ pub SubmissionID:SubmissionID, @@ -127,11 +127,11 @@ pub enum ResourceType{ Submission=2, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct GetScriptRequest{ pub ScriptID:ScriptID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct GetScriptsRequest<'a>{ pub Page:u32, @@ -151,7 +151,7 @@ pub struct GetScriptsRequest<'a>{ pub struct HashRequest<'a>{ pub hash:&'a str, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct ScriptResponse{ pub ID:ScriptID, @@ -161,7 +161,7 @@ pub struct ScriptResponse{ pub ResourceType:ResourceType, pub ResourceID:ResourceID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct CreateScriptRequest<'a>{ pub Name:&'a str, @@ -170,7 +170,7 @@ pub struct CreateScriptRequest<'a>{ #[serde(skip_serializing_if="Option::is_none")] pub ResourceID:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct ScriptIDResponse{ pub ScriptID:ScriptID, @@ -186,11 +186,11 @@ pub enum Policy{ Replace=4, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct GetScriptPolicyRequest{ pub ScriptPolicyID:ScriptPolicyID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct GetScriptPoliciesRequest<'a>{ pub Page:u32, @@ -202,7 +202,7 @@ pub struct GetScriptPoliciesRequest<'a>{ #[serde(skip_serializing_if="Option::is_none")] pub Policy:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct ScriptPolicyResponse{ pub ID:ScriptPolicyID, @@ -210,20 +210,20 @@ pub struct ScriptPolicyResponse{ pub ToScriptID:ScriptID, pub Policy:Policy } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct CreateScriptPolicyRequest{ pub FromScriptID:ScriptID, pub ToScriptID:ScriptID, pub Policy:Policy, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct ScriptPolicyIDResponse{ pub ScriptPolicyID:ScriptPolicyID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct UpdateScriptPolicyRequest{ pub ID:ScriptPolicyID, @@ -235,7 +235,7 @@ pub struct UpdateScriptPolicyRequest{ pub Policy:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct UpdateSubmissionModelRequest{ pub SubmissionID:SubmissionID, @@ -276,7 +276,7 @@ pub enum MapfixStatus{ Released=10, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct GetMapfixesRequest<'a>{ pub Page:u32, @@ -292,7 +292,7 @@ pub struct GetMapfixesRequest<'a>{ pub StatusID:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize,serde::Deserialize)] pub struct MapfixResponse{ pub ID:MapfixID, @@ -312,7 +312,7 @@ pub struct MapfixResponse{ pub Description:String, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct MapfixesResponse{ pub Total:u64, @@ -342,7 +342,7 @@ pub enum SubmissionStatus{ Released=10, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct GetSubmissionsRequest<'a>{ pub Page:u32, @@ -358,7 +358,7 @@ pub struct GetSubmissionsRequest<'a>{ pub StatusID:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct SubmissionResponse{ pub ID:SubmissionID, @@ -376,14 +376,14 @@ pub struct SubmissionResponse{ pub StatusID:SubmissionStatus, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct SubmissionsResponse{ pub Total:u64, pub Submissions:Vec, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct GetMapsRequest<'a>{ pub Page:u32, @@ -394,7 +394,7 @@ pub struct GetMapsRequest<'a>{ pub GameID:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct MapResponse{ pub ID:i64, @@ -404,7 +404,7 @@ pub struct MapResponse{ pub Date:i64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct GetMapfixAuditEventsRequest{ pub Page:u32, @@ -412,7 +412,7 @@ pub struct GetMapfixAuditEventsRequest{ pub MapfixID:i64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct GetSubmissionAuditEventsRequest{ pub Page:u32, @@ -420,7 +420,6 @@ pub struct GetSubmissionAuditEventsRequest{ pub SubmissionID:i64, } -#[allow(nonstandard_style)] #[derive(Clone,Debug,serde_repr::Deserialize_repr)] #[repr(u32)] pub enum AuditEventType{ @@ -475,7 +474,6 @@ pub struct AuditEventCheckList{ pub check_list:Vec, } -#[allow(nonstandard_style)] #[derive(Clone,Debug)] pub enum AuditEventData{ Action(AuditEventAction), @@ -491,7 +489,7 @@ pub enum AuditEventData{ #[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)] pub struct AuditEventID(pub(crate)i64); -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct AuditEventReponse{ pub ID:AuditEventID, @@ -518,7 +516,7 @@ impl AuditEventReponse{ } } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct Check{ pub Name:&'static str, @@ -526,7 +524,7 @@ pub struct Check{ pub Passed:bool, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionSubmissionSubmittedRequest{ pub SubmissionID:SubmissionID, @@ -536,33 +534,33 @@ pub struct ActionSubmissionSubmittedRequest{ pub GameID:GameID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionSubmissionRequestChangesRequest{ pub SubmissionID:SubmissionID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionSubmissionUploadedRequest{ pub SubmissionID:SubmissionID, pub UploadedAssetID:u64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionSubmissionAcceptedRequest{ pub SubmissionID:SubmissionID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct CreateSubmissionAuditErrorRequest{ pub SubmissionID:SubmissionID, pub ErrorMessage:String, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct CreateSubmissionAuditCheckListRequest<'a>{ pub SubmissionID:SubmissionID, @@ -580,7 +578,7 @@ impl SubmissionID{ } } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct UpdateMapfixModelRequest{ pub MapfixID:MapfixID, @@ -588,7 +586,7 @@ pub struct UpdateMapfixModelRequest{ pub ModelVersion:u64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionMapfixSubmittedRequest{ pub MapfixID:MapfixID, @@ -598,32 +596,32 @@ pub struct ActionMapfixSubmittedRequest{ pub GameID:GameID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionMapfixRequestChangesRequest{ pub MapfixID:MapfixID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionMapfixUploadedRequest{ pub MapfixID:MapfixID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionMapfixAcceptedRequest{ pub MapfixID:MapfixID, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct CreateMapfixAuditErrorRequest{ pub MapfixID:MapfixID, pub ErrorMessage:String, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct CreateMapfixAuditCheckListRequest<'a>{ pub MapfixID:MapfixID, @@ -641,7 +639,7 @@ impl MapfixID{ } } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug)] pub struct ActionOperationFailedRequest{ pub OperationID:OperationID, @@ -668,7 +666,7 @@ impl Resource{ } } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Serialize)] pub struct ReleaseInfo{ pub SubmissionID:SubmissionID, @@ -678,7 +676,7 @@ pub struct ReleaseInfo{ pub struct ReleaseRequest<'a>{ pub schedule:&'a [ReleaseInfo], } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(Clone,Debug,serde::Deserialize)] pub struct OperationIDResponse{ pub OperationID:OperationID, diff --git a/validation/src/check.rs b/validation/src/check.rs index b802310..98952b0 100644 --- a/validation/src/check.rs +++ b/validation/src/check.rs @@ -6,7 +6,7 @@ use heck::{ToSnakeCase,ToTitleCase}; use rbx_dom_weak::Instance; use rust_grpc::validator::Check; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ModelInfoDownload(rbx_asset::cloud::GetError), @@ -33,7 +33,7 @@ macro_rules! lazy_regex{ }}; } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct CheckRequest{ ModelID:u64, SkipChecks:bool, @@ -79,7 +79,7 @@ struct ModeElement{ zone:Zone, mode_id:ModeID, } -#[allow(dead_code)] +#[expect(dead_code)] pub enum IDParseError{ NoCaptures, ParseInt(core::num::ParseIntError), @@ -442,7 +442,7 @@ pub struct MapInfoOwned{ pub creator:String, pub game_id:GameID, } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum IntoMapInfoOwnedError{ DisplayName(StringValueError), diff --git a/validation/src/check_mapfix.rs b/validation/src/check_mapfix.rs index eb2e4e4..6d75980 100644 --- a/validation/src/check_mapfix.rs +++ b/validation/src/check_mapfix.rs @@ -1,7 +1,7 @@ use crate::check::CheckListAndVersion; use crate::nats_types::CheckMapfixRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ Check(crate::check::Error), diff --git a/validation/src/check_submission.rs b/validation/src/check_submission.rs index 3ba70f9..40260c4 100644 --- a/validation/src/check_submission.rs +++ b/validation/src/check_submission.rs @@ -1,7 +1,7 @@ use crate::check::CheckListAndVersion; use crate::nats_types::CheckSubmissionRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ Check(crate::check::Error), diff --git a/validation/src/create.rs b/validation/src/create.rs index f29d4ca..6e84cac 100644 --- a/validation/src/create.rs +++ b/validation/src/create.rs @@ -1,7 +1,7 @@ use crate::download::download_asset_version; use crate::rbx_util::{get_root_instance,get_mapinfo,read_dom,MapInfo,ReadDomError,GetRootInstanceError,GameID}; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ CreatorTypeMustBeUser, @@ -17,11 +17,11 @@ impl std::fmt::Display for Error{ } impl std::error::Error for Error{} -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct CreateRequest{ pub ModelID:u64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct CreateResult{ pub AssetOwner:u64, pub DisplayName:Option, diff --git a/validation/src/create_mapfix.rs b/validation/src/create_mapfix.rs index 443f694..ad53cd9 100644 --- a/validation/src/create_mapfix.rs +++ b/validation/src/create_mapfix.rs @@ -1,7 +1,7 @@ use crate::nats_types::CreateMapfixRequest; use crate::create::CreateRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ Create(crate::create::Error), diff --git a/validation/src/create_submission.rs b/validation/src/create_submission.rs index e30ec26..6db85b5 100644 --- a/validation/src/create_submission.rs +++ b/validation/src/create_submission.rs @@ -2,7 +2,7 @@ use crate::nats_types::CreateSubmissionRequest; use crate::create::CreateRequest; use crate::rbx_util::GameID; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ Create(crate::create::Error), diff --git a/validation/src/download.rs b/validation/src/download.rs index 63f16ae..f6bd875 100644 --- a/validation/src/download.rs +++ b/validation/src/download.rs @@ -1,4 +1,4 @@ -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ModelLocationDownload(rbx_asset::cloud::GetError), diff --git a/validation/src/main.rs b/validation/src/main.rs index 226ba71..871409b 100644 --- a/validation/src/main.rs +++ b/validation/src/main.rs @@ -22,7 +22,7 @@ mod validator; mod validate_mapfix; mod validate_submission; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum StartupError{ API(tonic::transport::Error), diff --git a/validation/src/message_handler.rs b/validation/src/message_handler.rs index bcb8065..9f96cc5 100644 --- a/validation/src/message_handler.rs +++ b/validation/src/message_handler.rs @@ -1,4 +1,4 @@ -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum HandleMessageError{ Messages(async_nats::jetstream::consumer::pull::MessagesError), diff --git a/validation/src/nats_types.rs b/validation/src/nats_types.rs index 19f2a99..f418759 100644 --- a/validation/src/nats_types.rs +++ b/validation/src/nats_types.rs @@ -4,7 +4,7 @@ // Requests are sent from maps-service to validator // Validation invokes the REST api to update the submissions -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct CreateSubmissionRequest{ // operation_id is passed back in the response message @@ -18,7 +18,7 @@ pub struct CreateSubmissionRequest{ pub Roles:u32, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct CreateMapfixRequest{ pub OperationID:u32, @@ -27,7 +27,7 @@ pub struct CreateMapfixRequest{ pub Description:String, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct CheckSubmissionRequest{ pub SubmissionID:u64, @@ -35,7 +35,7 @@ pub struct CheckSubmissionRequest{ pub SkipChecks:bool, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct CheckMapfixRequest{ pub MapfixID:u64, @@ -43,7 +43,7 @@ pub struct CheckMapfixRequest{ pub SkipChecks:bool, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct ValidateSubmissionRequest{ // submission_id is passed back in the response message @@ -53,7 +53,7 @@ pub struct ValidateSubmissionRequest{ pub ValidatedModelID:Option, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct ValidateMapfixRequest{ // submission_id is passed back in the response message @@ -64,7 +64,7 @@ pub struct ValidateMapfixRequest{ } // Create a new map -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct UploadSubmissionRequest{ pub SubmissionID:u64, @@ -73,7 +73,7 @@ pub struct UploadSubmissionRequest{ pub ModelName:String, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct UploadMapfixRequest{ pub MapfixID:u64, @@ -83,7 +83,7 @@ pub struct UploadMapfixRequest{ } // Release a new map -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct ReleaseSubmissionRequest{ pub SubmissionID:u64, @@ -97,14 +97,14 @@ pub struct ReleaseSubmissionRequest{ pub Submitter:u64, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct ReleaseSubmissionsBatchRequest{ pub Submissions:Vec, pub OperationID:u32, } -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] #[derive(serde::Deserialize)] pub struct ReleaseMapfixRequest{ pub MapfixID:u64, diff --git a/validation/src/rbx_util.rs b/validation/src/rbx_util.rs index a8185f4..dbfc086 100644 --- a/validation/src/rbx_util.rs +++ b/validation/src/rbx_util.rs @@ -1,4 +1,4 @@ -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum ReadDomError{ Binary(rbx_binary::DecodeError), diff --git a/validation/src/release_submissions_batch.rs b/validation/src/release_submissions_batch.rs index 8d77eef..50cfcbf 100644 --- a/validation/src/release_submissions_batch.rs +++ b/validation/src/release_submissions_batch.rs @@ -183,7 +183,7 @@ async fn release_inner( Ok(()) } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ UpdateOperation(tonic::Status), diff --git a/validation/src/upload_mapfix.rs b/validation/src/upload_mapfix.rs index 17cdca4..3e8fcd6 100644 --- a/validation/src/upload_mapfix.rs +++ b/validation/src/upload_mapfix.rs @@ -1,7 +1,7 @@ use crate::download::download_asset_version; use crate::nats_types::UploadMapfixRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum InnerError{ Download(crate::download::Error), @@ -43,7 +43,7 @@ async fn upload_inner( Ok(()) } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ApiActionMapfixUploaded(tonic::Status), diff --git a/validation/src/upload_submission.rs b/validation/src/upload_submission.rs index abd762b..cf34ae5 100644 --- a/validation/src/upload_submission.rs +++ b/validation/src/upload_submission.rs @@ -1,7 +1,7 @@ use crate::download::download_asset_version; use crate::nats_types::UploadSubmissionRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum InnerError{ Download(crate::download::Error), @@ -44,7 +44,7 @@ async fn upload_inner( Ok(upload_response.AssetId) } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ApiActionSubmissionUploaded(tonic::Status), diff --git a/validation/src/validate_mapfix.rs b/validation/src/validate_mapfix.rs index 70e8002..40a8477 100644 --- a/validation/src/validate_mapfix.rs +++ b/validation/src/validate_mapfix.rs @@ -1,6 +1,6 @@ use crate::nats_types::ValidateMapfixRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ApiActionMapfixValidate(tonic::Status), diff --git a/validation/src/validate_submission.rs b/validation/src/validate_submission.rs index 7737263..d1572ce 100644 --- a/validation/src/validate_submission.rs +++ b/validation/src/validate_submission.rs @@ -1,6 +1,6 @@ use crate::nats_types::ValidateSubmissionRequest; -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ApiActionSubmissionValidate(tonic::Status), diff --git a/validation/src/validator.rs b/validation/src/validator.rs index 6ba0de5..68e0766 100644 --- a/validation/src/validator.rs +++ b/validation/src/validator.rs @@ -17,7 +17,7 @@ fn hash_source(source:&str)->u64{ std::hash::Hasher::finish(&hasher) } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug)] pub enum Error{ ModelInfoDownload(rbx_asset::cloud::GetError), @@ -52,7 +52,7 @@ impl std::fmt::Display for Error{ } impl std::error::Error for Error{} -#[allow(nonstandard_style)] +#[expect(nonstandard_style)] pub struct ValidateRequest{ pub ModelID:u64, pub ModelVersion:u64, -- 2.49.1 From 9ab80931bff8a1d97b3b5052d82d3ba8826e56f6 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Tue, 9 Dec 2025 14:34:39 -0800 Subject: [PATCH 04/23] remove unfulfilled lints --- submissions-api-rs/src/types.rs | 1 - validation/src/main.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/submissions-api-rs/src/types.rs b/submissions-api-rs/src/types.rs index f89d883..00ac43a 100644 --- a/submissions-api-rs/src/types.rs +++ b/submissions-api-rs/src/types.rs @@ -30,7 +30,6 @@ impl std::error::Error for SingleItemError where Items:std::fmt::D pub type ScriptSingleItemError=SingleItemError>; pub type ScriptPolicySingleItemError=SingleItemError>; -#[expect(dead_code)] #[derive(Debug)] pub struct UrlAndBody{ pub url:url::Url, diff --git a/validation/src/main.rs b/validation/src/main.rs index 871409b..cfc3670 100644 --- a/validation/src/main.rs +++ b/validation/src/main.rs @@ -22,7 +22,6 @@ mod validator; mod validate_mapfix; mod validate_submission; -#[expect(dead_code)] #[derive(Debug)] pub enum StartupError{ API(tonic::transport::Error), -- 2.49.1 From ca401d4b96c2e1520c4fc0ce72aedd25ddf61d50 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 22:56:59 +0000 Subject: [PATCH 05/23] Add batch thumbnail endpoint (#285) Step 1 of eliminating nextjs is adding a way to query thumbnails from roblox since nextjs handles that. This implements a batch endpoint and caching to do that. Bonus: thumbnails will actually work once we start using this. Reviewed-on: https://git.itzana.me/StrafesNET/maps-service/pulls/285 Co-authored-by: itzaname Co-committed-by: itzaname --- go.mod | 45 +- go.sum | 69 +- openapi.yaml | 174 +++++ pkg/api/oas_cfg_gen.go | 16 +- pkg/api/oas_client_gen.go | 582 +++++++++++++++-- pkg/api/oas_defaults_gen.go | 19 + pkg/api/oas_handlers_gen.go | 936 ++++++++++++++++++++++++--- pkg/api/oas_json_gen.go | 709 +++++++++++++++++++- pkg/api/oas_operations_gen.go | 4 + pkg/api/oas_parameters_gen.go | 596 ++++++++++++++--- pkg/api/oas_request_decoders_gen.go | 370 ++++++++--- pkg/api/oas_request_encoders_gen.go | 29 +- pkg/api/oas_response_decoders_gen.go | 385 ++++++++++- pkg/api/oas_response_encoders_gen.go | 85 ++- pkg/api/oas_router_gen.go | 379 ++++++++++- pkg/api/oas_schemas_gen.go | 609 +++++++++++++++++ pkg/api/oas_security_gen.go | 1 - pkg/api/oas_server_gen.go | 24 + pkg/api/oas_unimplemented_gen.go | 36 ++ pkg/api/oas_validators_gen.go | 625 +++++++++++++----- pkg/cmds/serve.go | 41 +- pkg/roblox/thumbnails.go | 160 +++++ pkg/service/service.go | 44 +- pkg/service/thumbnails.go | 218 +++++++ pkg/web_api/thumbnails.go | 135 ++++ 25 files changed, 5763 insertions(+), 528 deletions(-) create mode 100644 pkg/api/oas_defaults_gen.go create mode 100644 pkg/roblox/thumbnails.go create mode 100644 pkg/service/thumbnails.go create mode 100644 pkg/web_api/thumbnails.go diff --git a/go.mod b/go.mod index 876de48..1d3a4fe 100644 --- a/go.mod +++ b/go.mod @@ -11,17 +11,18 @@ require ( github.com/dchest/siphash v1.2.3 github.com/gin-gonic/gin v1.10.1 github.com/go-faster/errors v0.7.1 - github.com/go-faster/jx v1.1.0 + github.com/go-faster/jx v1.2.0 github.com/nats-io/nats.go v1.37.0 - github.com/ogen-go/ogen v1.2.1 + github.com/ogen-go/ogen v1.18.0 + github.com/redis/go-redis/v9 v9.10.0 github.com/sirupsen/logrus v1.9.3 github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.6 github.com/urfave/cli/v2 v2.27.6 - go.opentelemetry.io/otel v1.32.0 - go.opentelemetry.io/otel/metric v1.32.0 - go.opentelemetry.io/otel/trace v1.32.0 + go.opentelemetry.io/otel v1.39.0 + go.opentelemetry.io/otel/metric v1.39.0 + go.opentelemetry.io/otel/trace v1.39.0 google.golang.org/grpc v1.48.0 gorm.io/driver/postgres v1.6.0 gorm.io/gorm v1.25.12 @@ -33,9 +34,11 @@ require ( github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect @@ -55,7 +58,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.6 // indirect + github.com/klauspost/compress v1.18.1 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mailru/easyjson v0.7.6 // indirect @@ -65,36 +68,38 @@ require ( github.com/nats-io/nuid v1.0.1 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.32.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/tools v0.40.0 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) require ( - github.com/dlclark/regexp2 v1.11.0 // indirect - github.com/fatih/color v1.17.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-faster/yaml v0.4.6 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect // github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/segmentio/asm v1.2.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.23.0 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 344bdc5..0eba823 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,18 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= @@ -39,8 +45,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -49,6 +59,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -63,11 +75,13 @@ github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AY github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg= +github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI= +github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE= github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -113,8 +127,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -140,6 +154,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= +github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -159,6 +175,8 @@ github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -176,11 +194,15 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/ogen-go/ogen v1.2.1 h1:C5A0lvUMu2wl+eWIxnpXMWnuOJ26a2FyzR1CIC2qG0M= github.com/ogen-go/ogen v1.2.1/go.mod h1:P2zQdEu8UqaVRfD5GEFvl+9q63VjMLvDquq1wVbyInM= +github.com/ogen-go/ogen v1.18.0 h1:6RQ7lFBjOeNaUWu4getfqIh4GJbEY4hqKuzDtec/g60= +github.com/ogen-go/ogen v1.18.0/go.mod h1:dHFr2Wf6cA7tSxMI+zPC21UR5hAlDw8ZYUkK3PziURY= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs= +github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= @@ -188,6 +210,10 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -204,8 +230,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= @@ -221,12 +248,14 @@ github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5 github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= -go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= -go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= -go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= -go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= -go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -234,6 +263,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -242,15 +273,21 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -266,6 +303,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -275,6 +314,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -293,6 +334,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -303,6 +346,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -312,6 +357,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/openapi.yaml b/openapi.yaml index 2cc7b7d..cc02f0b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -1438,6 +1438,180 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /thumbnails/assets: + post: + summary: Batch fetch asset thumbnails + operationId: batchAssetThumbnails + tags: + - Thumbnails + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - assetIds + properties: + assetIds: + type: array + items: + type: integer + format: uint64 + maxItems: 100 + description: Array of asset IDs (max 100) + size: + type: string + enum: + - "150x150" + - "420x420" + - "768x432" + default: "420x420" + description: Thumbnail size + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: object + properties: + thumbnails: + type: object + additionalProperties: + type: string + description: Map of asset ID to thumbnail URL + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /thumbnails/asset/{AssetID}: + get: + summary: Get single asset thumbnail + operationId: getAssetThumbnail + tags: + - Thumbnails + security: [] + parameters: + - name: AssetID + in: path + required: true + schema: + type: integer + format: uint64 + - name: size + in: query + schema: + type: string + enum: + - "150x150" + - "420x420" + - "768x432" + default: "420x420" + responses: + "302": + description: Redirect to thumbnail URL + headers: + Location: + description: URL to redirect to + schema: + type: string + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /thumbnails/users: + post: + summary: Batch fetch user avatar thumbnails + operationId: batchUserThumbnails + tags: + - Thumbnails + security: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - userIds + properties: + userIds: + type: array + items: + type: integer + format: uint64 + maxItems: 100 + description: Array of user IDs (max 100) + size: + type: string + enum: + - "150x150" + - "420x420" + - "768x432" + default: "150x150" + description: Thumbnail size + responses: + "200": + description: Successful response + content: + application/json: + schema: + type: object + properties: + thumbnails: + type: object + additionalProperties: + type: string + description: Map of user ID to thumbnail URL + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /thumbnails/user/{UserID}: + get: + summary: Get single user avatar thumbnail + operationId: getUserThumbnail + tags: + - Thumbnails + security: [] + parameters: + - name: UserID + in: path + required: true + schema: + type: integer + format: uint64 + - name: size + in: query + schema: + type: string + enum: + - "150x150" + - "420x420" + - "768x432" + default: "150x150" + responses: + "302": + description: Redirect to thumbnail URL + headers: + Location: + description: URL to redirect to + schema: + type: string + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" components: securitySchemes: cookieAuth: diff --git a/pkg/api/oas_cfg_gen.go b/pkg/api/oas_cfg_gen.go index fc3ff34..5dafb54 100644 --- a/pkg/api/oas_cfg_gen.go +++ b/pkg/api/oas_cfg_gen.go @@ -5,14 +5,14 @@ package api import ( "net/http" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/trace" - ht "github.com/ogen-go/ogen/http" "github.com/ogen-go/ogen/middleware" "github.com/ogen-go/ogen/ogenerrors" "github.com/ogen-go/ogen/otelogen" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" ) var ( @@ -32,6 +32,7 @@ type otelConfig struct { Tracer trace.Tracer MeterProvider metric.MeterProvider Meter metric.Meter + Attributes []attribute.KeyValue } func (cfg *otelConfig) initOTEL() { @@ -215,6 +216,13 @@ func WithMeterProvider(provider metric.MeterProvider) Option { }) } +// WithAttributes specifies default otel attributes. +func WithAttributes(attributes ...attribute.KeyValue) Option { + return otelOptionFunc(func(cfg *otelConfig) { + cfg.Attributes = attributes + }) +} + // WithClient specifies http client to use. func WithClient(client ht.Client) ClientOption { return optionFunc[clientConfig](func(cfg *clientConfig) { diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index bc5d28a..7716981 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -9,17 +9,16 @@ import ( "time" "github.com/go-faster/errors" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" - "go.opentelemetry.io/otel/trace" - "github.com/ogen-go/ogen/conv" ht "github.com/ogen-go/ogen/http" "github.com/ogen-go/ogen/ogenerrors" "github.com/ogen-go/ogen/otelogen" "github.com/ogen-go/ogen/uri" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.37.0" + "go.opentelemetry.io/otel/trace" ) func trimTrailingSlashes(u *url.URL) { @@ -176,6 +175,18 @@ type Invoker interface { // // POST /submissions/{SubmissionID}/status/reset-uploading ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error + // BatchAssetThumbnails invokes batchAssetThumbnails operation. + // + // Batch fetch asset thumbnails. + // + // POST /thumbnails/assets + BatchAssetThumbnails(ctx context.Context, request *BatchAssetThumbnailsReq) (*BatchAssetThumbnailsOK, error) + // BatchUserThumbnails invokes batchUserThumbnails operation. + // + // Batch fetch user avatar thumbnails. + // + // POST /thumbnails/users + BatchUserThumbnails(ctx context.Context, request *BatchUserThumbnailsReq) (*BatchUserThumbnailsOK, error) // CreateMapfix invokes createMapfix operation. // // Trigger the validator to create a mapfix. @@ -236,6 +247,12 @@ type Invoker interface { // // GET /maps/{MapID}/download DownloadMapAsset(ctx context.Context, params DownloadMapAssetParams) (DownloadMapAssetOK, error) + // GetAssetThumbnail invokes getAssetThumbnail operation. + // + // Get single asset thumbnail. + // + // GET /thumbnails/asset/{AssetID} + GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (*GetAssetThumbnailFound, error) // GetMap invokes getMap operation. // // Retrieve map with ID. @@ -272,6 +289,12 @@ type Invoker interface { // // GET /submissions/{SubmissionID} GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error) + // GetUserThumbnail invokes getUserThumbnail operation. + // + // Get single user avatar thumbnail. + // + // GET /thumbnails/user/{UserID} + GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (*GetUserThumbnailFound, error) // ListMapfixAuditEvents invokes listMapfixAuditEvents operation. // // Retrieve a list of audit events. @@ -439,8 +462,9 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixAccepted"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-validating"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/reset-validating"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -563,8 +587,9 @@ func (c *Client) sendActionMapfixReject(ctx context.Context, params ActionMapfix otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixReject"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reject"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/reject"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -687,8 +712,9 @@ func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params Acti otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixRequestChanges"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/request-changes"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/request-changes"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -812,8 +838,9 @@ func (c *Client) sendActionMapfixResetSubmitting(ctx context.Context, params Act otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixResetSubmitting"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-submitting"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/reset-submitting"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -936,8 +963,9 @@ func (c *Client) sendActionMapfixRetryValidate(ctx context.Context, params Actio otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixRetryValidate"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/retry-validate"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/retry-validate"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1060,8 +1088,9 @@ func (c *Client) sendActionMapfixRevoke(ctx context.Context, params ActionMapfix otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixRevoke"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/revoke"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/revoke"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1184,8 +1213,9 @@ func (c *Client) sendActionMapfixTriggerRelease(ctx context.Context, params Acti otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixTriggerRelease"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-release"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/trigger-release"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1308,8 +1338,9 @@ func (c *Client) sendActionMapfixTriggerSubmit(ctx context.Context, params Actio otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixTriggerSubmit"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-submit"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/trigger-submit"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1432,8 +1463,9 @@ func (c *Client) sendActionMapfixTriggerSubmitUnchecked(ctx context.Context, par otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixTriggerSubmitUnchecked"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-submit-unchecked"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/trigger-submit-unchecked"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1556,8 +1588,9 @@ func (c *Client) sendActionMapfixTriggerUpload(ctx context.Context, params Actio otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixTriggerUpload"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-upload"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/trigger-upload"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1680,8 +1713,9 @@ func (c *Client) sendActionMapfixTriggerValidate(ctx context.Context, params Act otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixTriggerValidate"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-validate"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/trigger-validate"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1804,8 +1838,9 @@ func (c *Client) sendActionMapfixUploaded(ctx context.Context, params ActionMapf otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixUploaded"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-releasing"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/reset-releasing"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -1928,8 +1963,9 @@ func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMap otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionMapfixValidated"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-uploading"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/status/reset-uploading"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2052,8 +2088,9 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionAccepted"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-validating"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/reset-validating"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2176,8 +2213,9 @@ func (c *Client) sendActionSubmissionReject(ctx context.Context, params ActionSu otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionReject"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reject"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/reject"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2300,8 +2338,9 @@ func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionRequestChanges"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/request-changes"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/request-changes"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2425,8 +2464,9 @@ func (c *Client) sendActionSubmissionResetSubmitting(ctx context.Context, params otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionResetSubmitting"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-submitting"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/reset-submitting"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2549,8 +2589,9 @@ func (c *Client) sendActionSubmissionRetryValidate(ctx context.Context, params A otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionRetryValidate"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/retry-validate"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/retry-validate"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2673,8 +2714,9 @@ func (c *Client) sendActionSubmissionRevoke(ctx context.Context, params ActionSu otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionRevoke"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/revoke"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/revoke"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2797,8 +2839,9 @@ func (c *Client) sendActionSubmissionTriggerSubmit(ctx context.Context, params A otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionTriggerSubmit"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-submit"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/trigger-submit"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -2921,8 +2964,9 @@ func (c *Client) sendActionSubmissionTriggerSubmitUnchecked(ctx context.Context, otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionTriggerSubmitUnchecked"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-submit-unchecked"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/trigger-submit-unchecked"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3045,8 +3089,9 @@ func (c *Client) sendActionSubmissionTriggerUpload(ctx context.Context, params A otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionTriggerUpload"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-upload"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/trigger-upload"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3169,8 +3214,9 @@ func (c *Client) sendActionSubmissionTriggerValidate(ctx context.Context, params otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionTriggerValidate"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-validate"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/trigger-validate"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3294,8 +3340,9 @@ func (c *Client) sendActionSubmissionValidated(ctx context.Context, params Actio otelAttrs := []attribute.KeyValue{ otelogen.OperationID("actionSubmissionValidated"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-uploading"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/status/reset-uploading"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3404,6 +3451,158 @@ func (c *Client) sendActionSubmissionValidated(ctx context.Context, params Actio return result, nil } +// BatchAssetThumbnails invokes batchAssetThumbnails operation. +// +// Batch fetch asset thumbnails. +// +// POST /thumbnails/assets +func (c *Client) BatchAssetThumbnails(ctx context.Context, request *BatchAssetThumbnailsReq) (*BatchAssetThumbnailsOK, error) { + res, err := c.sendBatchAssetThumbnails(ctx, request) + return res, err +} + +func (c *Client) sendBatchAssetThumbnails(ctx context.Context, request *BatchAssetThumbnailsReq) (res *BatchAssetThumbnailsOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("batchAssetThumbnails"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.URLTemplateKey.String("/thumbnails/assets"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, BatchAssetThumbnailsOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/thumbnails/assets" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeBatchAssetThumbnailsRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeBatchAssetThumbnailsResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// BatchUserThumbnails invokes batchUserThumbnails operation. +// +// Batch fetch user avatar thumbnails. +// +// POST /thumbnails/users +func (c *Client) BatchUserThumbnails(ctx context.Context, request *BatchUserThumbnailsReq) (*BatchUserThumbnailsOK, error) { + res, err := c.sendBatchUserThumbnails(ctx, request) + return res, err +} + +func (c *Client) sendBatchUserThumbnails(ctx context.Context, request *BatchUserThumbnailsReq) (res *BatchUserThumbnailsOK, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("batchUserThumbnails"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.URLTemplateKey.String("/thumbnails/users"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, BatchUserThumbnailsOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/thumbnails/users" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeBatchUserThumbnailsRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeBatchUserThumbnailsResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // CreateMapfix invokes createMapfix operation. // // Trigger the validator to create a mapfix. @@ -3418,8 +3617,9 @@ func (c *Client) sendCreateMapfix(ctx context.Context, request *MapfixTriggerCre otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createMapfix"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes"), + semconv.URLTemplateKey.String("/mapfixes"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3526,8 +3726,9 @@ func (c *Client) sendCreateMapfixAuditComment(ctx context.Context, request Creat otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createMapfixAuditComment"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/comment"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/comment"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3653,8 +3854,9 @@ func (c *Client) sendCreateScript(ctx context.Context, request *ScriptCreate) (r otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createScript"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/scripts"), + semconv.URLTemplateKey.String("/scripts"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3761,8 +3963,9 @@ func (c *Client) sendCreateScriptPolicy(ctx context.Context, request *ScriptPoli otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createScriptPolicy"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/script-policy"), + semconv.URLTemplateKey.String("/script-policy"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3869,8 +4072,9 @@ func (c *Client) sendCreateSubmission(ctx context.Context, request *SubmissionTr otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createSubmission"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions"), + semconv.URLTemplateKey.String("/submissions"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -3977,8 +4181,9 @@ func (c *Client) sendCreateSubmissionAdmin(ctx context.Context, request *Submiss otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createSubmissionAdmin"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions-admin"), + semconv.URLTemplateKey.String("/submissions-admin"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4085,8 +4290,9 @@ func (c *Client) sendCreateSubmissionAuditComment(ctx context.Context, request C otelAttrs := []attribute.KeyValue{ otelogen.OperationID("createSubmissionAuditComment"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/comment"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/comment"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4212,8 +4418,9 @@ func (c *Client) sendDeleteScript(ctx context.Context, params DeleteScriptParams otelAttrs := []attribute.KeyValue{ otelogen.OperationID("deleteScript"), semconv.HTTPRequestMethodKey.String("DELETE"), - semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), + semconv.URLTemplateKey.String("/scripts/{ScriptID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4335,8 +4542,9 @@ func (c *Client) sendDeleteScriptPolicy(ctx context.Context, params DeleteScript otelAttrs := []attribute.KeyValue{ otelogen.OperationID("deleteScriptPolicy"), semconv.HTTPRequestMethodKey.String("DELETE"), - semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), + semconv.URLTemplateKey.String("/script-policy/{ScriptPolicyID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4458,8 +4666,9 @@ func (c *Client) sendDownloadMapAsset(ctx context.Context, params DownloadMapAss otelAttrs := []attribute.KeyValue{ otelogen.OperationID("downloadMapAsset"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/maps/{MapID}/download"), + semconv.URLTemplateKey.String("/maps/{MapID}/download"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4568,6 +4777,118 @@ func (c *Client) sendDownloadMapAsset(ctx context.Context, params DownloadMapAss return result, nil } +// GetAssetThumbnail invokes getAssetThumbnail operation. +// +// Get single asset thumbnail. +// +// GET /thumbnails/asset/{AssetID} +func (c *Client) GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (*GetAssetThumbnailFound, error) { + res, err := c.sendGetAssetThumbnail(ctx, params) + return res, err +} + +func (c *Client) sendGetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (res *GetAssetThumbnailFound, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getAssetThumbnail"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.URLTemplateKey.String("/thumbnails/asset/{AssetID}"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, GetAssetThumbnailOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/thumbnails/asset/" + { + // Encode "AssetID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "AssetID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Uint64ToString(params.AssetID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "size" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "size", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Size.Get(); ok { + return e.EncodeValue(conv.StringToString(string(val))) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGetAssetThumbnailResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // GetMap invokes getMap operation. // // Retrieve map with ID. @@ -4582,8 +4903,9 @@ func (c *Client) sendGetMap(ctx context.Context, params GetMapParams) (res *Map, otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getMap"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/maps/{MapID}"), + semconv.URLTemplateKey.String("/maps/{MapID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4672,8 +4994,9 @@ func (c *Client) sendGetMapfix(ctx context.Context, params GetMapfixParams) (res otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getMapfix"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4762,8 +5085,9 @@ func (c *Client) sendGetOperation(ctx context.Context, params GetOperationParams otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getOperation"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/operations/{OperationID}"), + semconv.URLTemplateKey.String("/operations/{OperationID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4885,8 +5209,9 @@ func (c *Client) sendGetScript(ctx context.Context, params GetScriptParams) (res otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getScript"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), + semconv.URLTemplateKey.String("/scripts/{ScriptID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -4975,8 +5300,9 @@ func (c *Client) sendGetScriptPolicy(ctx context.Context, params GetScriptPolicy otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getScriptPolicy"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), + semconv.URLTemplateKey.String("/script-policy/{ScriptPolicyID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5065,8 +5391,9 @@ func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionPara otelAttrs := []attribute.KeyValue{ otelogen.OperationID("getSubmission"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5141,6 +5468,118 @@ func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionPara return result, nil } +// GetUserThumbnail invokes getUserThumbnail operation. +// +// Get single user avatar thumbnail. +// +// GET /thumbnails/user/{UserID} +func (c *Client) GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (*GetUserThumbnailFound, error) { + res, err := c.sendGetUserThumbnail(ctx, params) + return res, err +} + +func (c *Client) sendGetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (res *GetUserThumbnailFound, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getUserThumbnail"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.URLTemplateKey.String("/thumbnails/user/{UserID}"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, GetUserThumbnailOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/thumbnails/user/" + { + // Encode "UserID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "UserID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Uint64ToString(params.UserID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "size" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "size", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Size.Get(); ok { + return e.EncodeValue(conv.StringToString(string(val))) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGetUserThumbnailResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // ListMapfixAuditEvents invokes listMapfixAuditEvents operation. // // Retrieve a list of audit events. @@ -5155,8 +5594,9 @@ func (c *Client) sendListMapfixAuditEvents(ctx context.Context, params ListMapfi otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listMapfixAuditEvents"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/audit-events"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/audit-events"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5278,8 +5718,9 @@ func (c *Client) sendListMapfixes(ctx context.Context, params ListMapfixesParams otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listMapfixes"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/mapfixes"), + semconv.URLTemplateKey.String("/mapfixes"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5535,8 +5976,9 @@ func (c *Client) sendListMaps(ctx context.Context, params ListMapsParams) (res [ otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listMaps"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/maps"), + semconv.URLTemplateKey.String("/maps"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5707,8 +6149,9 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listScriptPolicy"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/script-policy"), + semconv.URLTemplateKey.String("/script-policy"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -5862,8 +6305,9 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams) otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listScripts"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/scripts"), + semconv.URLTemplateKey.String("/scripts"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6051,8 +6495,9 @@ func (c *Client) sendListSubmissionAuditEvents(ctx context.Context, params ListS otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listSubmissionAuditEvents"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/audit-events"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/audit-events"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6174,8 +6619,9 @@ func (c *Client) sendListSubmissions(ctx context.Context, params ListSubmissions otelAttrs := []attribute.KeyValue{ otelogen.OperationID("listSubmissions"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/submissions"), + semconv.URLTemplateKey.String("/submissions"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6431,8 +6877,9 @@ func (c *Client) sendReleaseSubmissions(ctx context.Context, request []ReleaseIn otelAttrs := []attribute.KeyValue{ otelogen.OperationID("releaseSubmissions"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/release-submissions"), + semconv.URLTemplateKey.String("/release-submissions"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6539,8 +6986,9 @@ func (c *Client) sendSessionRoles(ctx context.Context) (res *Roles, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("sessionRoles"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/session/roles"), + semconv.URLTemplateKey.String("/session/roles"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6644,8 +7092,9 @@ func (c *Client) sendSessionUser(ctx context.Context) (res *User, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("sessionUser"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/session/user"), + semconv.URLTemplateKey.String("/session/user"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6749,8 +7198,9 @@ func (c *Client) sendSessionValidate(ctx context.Context) (res bool, err error) otelAttrs := []attribute.KeyValue{ otelogen.OperationID("sessionValidate"), semconv.HTTPRequestMethodKey.String("GET"), - semconv.HTTPRouteKey.String("/session/validate"), + semconv.URLTemplateKey.String("/session/validate"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6854,8 +7304,9 @@ func (c *Client) sendSetMapfixCompleted(ctx context.Context, params SetMapfixCom otelAttrs := []attribute.KeyValue{ otelogen.OperationID("setMapfixCompleted"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/completed"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/completed"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -6978,8 +7429,9 @@ func (c *Client) sendSetSubmissionCompleted(ctx context.Context, params SetSubmi otelAttrs := []attribute.KeyValue{ otelogen.OperationID("setSubmissionCompleted"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/completed"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/completed"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -7102,8 +7554,9 @@ func (c *Client) sendUpdateMapfixModel(ctx context.Context, params UpdateMapfixM otelAttrs := []attribute.KeyValue{ otelogen.OperationID("updateMapfixModel"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/model"), + semconv.URLTemplateKey.String("/mapfixes/{MapfixID}/model"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -7258,8 +7711,9 @@ func (c *Client) sendUpdateScript(ctx context.Context, request *ScriptUpdate, pa otelAttrs := []attribute.KeyValue{ otelogen.OperationID("updateScript"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), + semconv.URLTemplateKey.String("/scripts/{ScriptID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -7384,8 +7838,9 @@ func (c *Client) sendUpdateScriptPolicy(ctx context.Context, request *ScriptPoli otelAttrs := []attribute.KeyValue{ otelogen.OperationID("updateScriptPolicy"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), + semconv.URLTemplateKey.String("/script-policy/{ScriptPolicyID}"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() @@ -7510,8 +7965,9 @@ func (c *Client) sendUpdateSubmissionModel(ctx context.Context, params UpdateSub otelAttrs := []attribute.KeyValue{ otelogen.OperationID("updateSubmissionModel"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/model"), + semconv.URLTemplateKey.String("/submissions/{SubmissionID}/model"), } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) // Run stopwatch. startTime := time.Now() diff --git a/pkg/api/oas_defaults_gen.go b/pkg/api/oas_defaults_gen.go new file mode 100644 index 0000000..da8b721 --- /dev/null +++ b/pkg/api/oas_defaults_gen.go @@ -0,0 +1,19 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +// setDefaults set default value of fields. +func (s *BatchAssetThumbnailsReq) setDefaults() { + { + val := BatchAssetThumbnailsReqSize("420x420") + s.Size.SetTo(val) + } +} + +// setDefaults set default value of fields. +func (s *BatchUserThumbnailsReq) setDefaults() { + { + val := BatchUserThumbnailsReqSize("150x150") + s.Size.SetTo(val) + } +} diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 2d9f21e..00ea170 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -8,16 +8,15 @@ import ( "time" "github.com/go-faster/errors" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.26.0" - "go.opentelemetry.io/otel/trace" - ht "github.com/ogen-go/ogen/http" "github.com/ogen-go/ogen/middleware" "github.com/ogen-go/ogen/ogenerrors" "github.com/ogen-go/ogen/otelogen" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.37.0" + "go.opentelemetry.io/otel/trace" ) type codeRecorder struct { @@ -30,6 +29,10 @@ func (c *codeRecorder) WriteHeader(status int) { c.ResponseWriter.WriteHeader(status) } +func (c *codeRecorder) Unwrap() http.ResponseWriter { + return c.ResponseWriter +} + // handleActionMapfixAcceptedRequest handles actionMapfixAccepted operation. // // Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted. @@ -86,7 +89,7 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -161,6 +164,8 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b return } + var rawBody []byte + var response *ActionMapfixAcceptedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -169,6 +174,7 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b OperationSummary: "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted", OperationID: "actionMapfixAccepted", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -281,7 +287,7 @@ func (s *Server) handleActionMapfixRejectRequest(args [1]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -356,6 +362,8 @@ func (s *Server) handleActionMapfixRejectRequest(args [1]string, argsEscaped boo return } + var rawBody []byte + var response *ActionMapfixRejectNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -364,6 +372,7 @@ func (s *Server) handleActionMapfixRejectRequest(args [1]string, argsEscaped boo OperationSummary: "Role Reviewer changes status from Submitted -> Rejected", OperationID: "actionMapfixReject", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -476,7 +485,7 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -551,6 +560,8 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc return } + var rawBody []byte + var response *ActionMapfixRequestChangesNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -559,6 +570,7 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc OperationSummary: "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested", OperationID: "actionMapfixRequestChanges", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -672,7 +684,7 @@ func (s *Server) handleActionMapfixResetSubmittingRequest(args [1]string, argsEs // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -747,6 +759,8 @@ func (s *Server) handleActionMapfixResetSubmittingRequest(args [1]string, argsEs return } + var rawBody []byte + var response *ActionMapfixResetSubmittingNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -755,6 +769,7 @@ func (s *Server) handleActionMapfixResetSubmittingRequest(args [1]string, argsEs OperationSummary: "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction", OperationID: "actionMapfixResetSubmitting", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -867,7 +882,7 @@ func (s *Server) handleActionMapfixRetryValidateRequest(args [1]string, argsEsca // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -942,6 +957,8 @@ func (s *Server) handleActionMapfixRetryValidateRequest(args [1]string, argsEsca return } + var rawBody []byte + var response *ActionMapfixRetryValidateNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -950,6 +967,7 @@ func (s *Server) handleActionMapfixRetryValidateRequest(args [1]string, argsEsca OperationSummary: "Role Reviewer re-runs validation and changes status from Accepted -> Validating", OperationID: "actionMapfixRetryValidate", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -1062,7 +1080,7 @@ func (s *Server) handleActionMapfixRevokeRequest(args [1]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -1137,6 +1155,8 @@ func (s *Server) handleActionMapfixRevokeRequest(args [1]string, argsEscaped boo return } + var rawBody []byte + var response *ActionMapfixRevokeNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -1145,6 +1165,7 @@ func (s *Server) handleActionMapfixRevokeRequest(args [1]string, argsEscaped boo OperationSummary: "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction", OperationID: "actionMapfixRevoke", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -1257,7 +1278,7 @@ func (s *Server) handleActionMapfixTriggerReleaseRequest(args [1]string, argsEsc // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -1332,6 +1353,8 @@ func (s *Server) handleActionMapfixTriggerReleaseRequest(args [1]string, argsEsc return } + var rawBody []byte + var response *ActionMapfixTriggerReleaseNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -1340,6 +1363,7 @@ func (s *Server) handleActionMapfixTriggerReleaseRequest(args [1]string, argsEsc OperationSummary: "Role MapfixUpload changes status from Uploaded -> Releasing", OperationID: "actionMapfixTriggerRelease", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -1452,7 +1476,7 @@ func (s *Server) handleActionMapfixTriggerSubmitRequest(args [1]string, argsEsca // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -1527,6 +1551,8 @@ func (s *Server) handleActionMapfixTriggerSubmitRequest(args [1]string, argsEsca return } + var rawBody []byte + var response *ActionMapfixTriggerSubmitNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -1535,6 +1561,7 @@ func (s *Server) handleActionMapfixTriggerSubmitRequest(args [1]string, argsEsca OperationSummary: "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting", OperationID: "actionMapfixTriggerSubmit", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -1647,7 +1674,7 @@ func (s *Server) handleActionMapfixTriggerSubmitUncheckedRequest(args [1]string, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -1722,6 +1749,8 @@ func (s *Server) handleActionMapfixTriggerSubmitUncheckedRequest(args [1]string, return } + var rawBody []byte + var response *ActionMapfixTriggerSubmitUncheckedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -1730,6 +1759,7 @@ func (s *Server) handleActionMapfixTriggerSubmitUncheckedRequest(args [1]string, OperationSummary: "Role Reviewer changes status from ChangesRequested -> Submitting", OperationID: "actionMapfixTriggerSubmitUnchecked", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -1842,7 +1872,7 @@ func (s *Server) handleActionMapfixTriggerUploadRequest(args [1]string, argsEsca // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -1917,6 +1947,8 @@ func (s *Server) handleActionMapfixTriggerUploadRequest(args [1]string, argsEsca return } + var rawBody []byte + var response *ActionMapfixTriggerUploadNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -1925,6 +1957,7 @@ func (s *Server) handleActionMapfixTriggerUploadRequest(args [1]string, argsEsca OperationSummary: "Role MapfixUpload changes status from Validated -> Uploading", OperationID: "actionMapfixTriggerUpload", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -2037,7 +2070,7 @@ func (s *Server) handleActionMapfixTriggerValidateRequest(args [1]string, argsEs // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -2112,6 +2145,8 @@ func (s *Server) handleActionMapfixTriggerValidateRequest(args [1]string, argsEs return } + var rawBody []byte + var response *ActionMapfixTriggerValidateNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -2120,6 +2155,7 @@ func (s *Server) handleActionMapfixTriggerValidateRequest(args [1]string, argsEs OperationSummary: "Role Reviewer triggers validation and changes status from Submitted -> Validating", OperationID: "actionMapfixTriggerValidate", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -2232,7 +2268,7 @@ func (s *Server) handleActionMapfixUploadedRequest(args [1]string, argsEscaped b // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -2307,6 +2343,8 @@ func (s *Server) handleActionMapfixUploadedRequest(args [1]string, argsEscaped b return } + var rawBody []byte + var response *ActionMapfixUploadedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -2315,6 +2353,7 @@ func (s *Server) handleActionMapfixUploadedRequest(args [1]string, argsEscaped b OperationSummary: "Role MapfixUpload manually resets releasing softlock and changes status from Releasing -> Uploaded", OperationID: "actionMapfixUploaded", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -2427,7 +2466,7 @@ func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -2502,6 +2541,8 @@ func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response *ActionMapfixValidatedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -2510,6 +2551,7 @@ func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped OperationSummary: "Role MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated", OperationID: "actionMapfixValidated", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -2622,7 +2664,7 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -2697,6 +2739,8 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap return } + var rawBody []byte + var response *ActionSubmissionAcceptedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -2705,6 +2749,7 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap OperationSummary: "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted", OperationID: "actionSubmissionAccepted", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -2817,7 +2862,7 @@ func (s *Server) handleActionSubmissionRejectRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -2892,6 +2937,8 @@ func (s *Server) handleActionSubmissionRejectRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response *ActionSubmissionRejectNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -2900,6 +2947,7 @@ func (s *Server) handleActionSubmissionRejectRequest(args [1]string, argsEscaped OperationSummary: "Role Reviewer changes status from Submitted -> Rejected", OperationID: "actionSubmissionReject", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3012,7 +3060,7 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -3087,6 +3135,8 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg return } + var rawBody []byte + var response *ActionSubmissionRequestChangesNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -3095,6 +3145,7 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg OperationSummary: "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested", OperationID: "actionSubmissionRequestChanges", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3208,7 +3259,7 @@ func (s *Server) handleActionSubmissionResetSubmittingRequest(args [1]string, ar // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -3283,6 +3334,8 @@ func (s *Server) handleActionSubmissionResetSubmittingRequest(args [1]string, ar return } + var rawBody []byte + var response *ActionSubmissionResetSubmittingNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -3291,6 +3344,7 @@ func (s *Server) handleActionSubmissionResetSubmittingRequest(args [1]string, ar OperationSummary: "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction", OperationID: "actionSubmissionResetSubmitting", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3403,7 +3457,7 @@ func (s *Server) handleActionSubmissionRetryValidateRequest(args [1]string, args // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -3478,6 +3532,8 @@ func (s *Server) handleActionSubmissionRetryValidateRequest(args [1]string, args return } + var rawBody []byte + var response *ActionSubmissionRetryValidateNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -3486,6 +3542,7 @@ func (s *Server) handleActionSubmissionRetryValidateRequest(args [1]string, args OperationSummary: "Role Reviewer re-runs validation and changes status from Accepted -> Validating", OperationID: "actionSubmissionRetryValidate", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3598,7 +3655,7 @@ func (s *Server) handleActionSubmissionRevokeRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -3673,6 +3730,8 @@ func (s *Server) handleActionSubmissionRevokeRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response *ActionSubmissionRevokeNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -3681,6 +3740,7 @@ func (s *Server) handleActionSubmissionRevokeRequest(args [1]string, argsEscaped OperationSummary: "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction", OperationID: "actionSubmissionRevoke", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3793,7 +3853,7 @@ func (s *Server) handleActionSubmissionTriggerSubmitRequest(args [1]string, args // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -3868,6 +3928,8 @@ func (s *Server) handleActionSubmissionTriggerSubmitRequest(args [1]string, args return } + var rawBody []byte + var response *ActionSubmissionTriggerSubmitNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -3876,6 +3938,7 @@ func (s *Server) handleActionSubmissionTriggerSubmitRequest(args [1]string, args OperationSummary: "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting", OperationID: "actionSubmissionTriggerSubmit", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -3988,7 +4051,7 @@ func (s *Server) handleActionSubmissionTriggerSubmitUncheckedRequest(args [1]str // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -4063,6 +4126,8 @@ func (s *Server) handleActionSubmissionTriggerSubmitUncheckedRequest(args [1]str return } + var rawBody []byte + var response *ActionSubmissionTriggerSubmitUncheckedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -4071,6 +4136,7 @@ func (s *Server) handleActionSubmissionTriggerSubmitUncheckedRequest(args [1]str OperationSummary: "Role Reviewer changes status from ChangesRequested -> Submitting", OperationID: "actionSubmissionTriggerSubmitUnchecked", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -4183,7 +4249,7 @@ func (s *Server) handleActionSubmissionTriggerUploadRequest(args [1]string, args // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -4258,6 +4324,8 @@ func (s *Server) handleActionSubmissionTriggerUploadRequest(args [1]string, args return } + var rawBody []byte + var response *ActionSubmissionTriggerUploadNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -4266,6 +4334,7 @@ func (s *Server) handleActionSubmissionTriggerUploadRequest(args [1]string, args OperationSummary: "Role SubmissionUpload changes status from Validated -> Uploading", OperationID: "actionSubmissionTriggerUpload", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -4378,7 +4447,7 @@ func (s *Server) handleActionSubmissionTriggerValidateRequest(args [1]string, ar // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -4453,6 +4522,8 @@ func (s *Server) handleActionSubmissionTriggerValidateRequest(args [1]string, ar return } + var rawBody []byte + var response *ActionSubmissionTriggerValidateNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -4461,6 +4532,7 @@ func (s *Server) handleActionSubmissionTriggerValidateRequest(args [1]string, ar OperationSummary: "Role Reviewer triggers validation and changes status from Submitted -> Validating", OperationID: "actionSubmissionTriggerValidate", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -4574,7 +4646,7 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -4649,6 +4721,8 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca return } + var rawBody []byte + var response *ActionSubmissionValidatedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -4657,6 +4731,7 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca OperationSummary: "Role SubmissionUpload manually resets uploading softlock and changes status from Uploading -> Validated", OperationID: "actionSubmissionValidated", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -4713,6 +4788,310 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca } } +// handleBatchAssetThumbnailsRequest handles batchAssetThumbnails operation. +// +// Batch fetch asset thumbnails. +// +// POST /thumbnails/assets +func (s *Server) handleBatchAssetThumbnailsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("batchAssetThumbnails"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/thumbnails/assets"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), BatchAssetThumbnailsOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: BatchAssetThumbnailsOperation, + ID: "batchAssetThumbnails", + } + ) + + var rawBody []byte + request, rawBody, close, err := s.decodeBatchAssetThumbnailsRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *BatchAssetThumbnailsOK + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: BatchAssetThumbnailsOperation, + OperationSummary: "Batch fetch asset thumbnails", + OperationID: "batchAssetThumbnails", + Body: request, + RawBody: rawBody, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = *BatchAssetThumbnailsReq + Params = struct{} + Response = *BatchAssetThumbnailsOK + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.BatchAssetThumbnails(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.BatchAssetThumbnails(ctx, request) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeBatchAssetThumbnailsResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleBatchUserThumbnailsRequest handles batchUserThumbnails operation. +// +// Batch fetch user avatar thumbnails. +// +// POST /thumbnails/users +func (s *Server) handleBatchUserThumbnailsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("batchUserThumbnails"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/thumbnails/users"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), BatchUserThumbnailsOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: BatchUserThumbnailsOperation, + ID: "batchUserThumbnails", + } + ) + + var rawBody []byte + request, rawBody, close, err := s.decodeBatchUserThumbnailsRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *BatchUserThumbnailsOK + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: BatchUserThumbnailsOperation, + OperationSummary: "Batch fetch user avatar thumbnails", + OperationID: "batchUserThumbnails", + Body: request, + RawBody: rawBody, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = *BatchUserThumbnailsReq + Params = struct{} + Response = *BatchUserThumbnailsOK + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.BatchUserThumbnails(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.BatchUserThumbnails(ctx, request) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeBatchUserThumbnailsResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleCreateMapfixRequest handles createMapfix operation. // // Trigger the validator to create a mapfix. @@ -4769,7 +5148,7 @@ func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -4833,7 +5212,9 @@ func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w h return } } - request, close, err := s.decodeCreateMapfixRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateMapfixRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -4857,6 +5238,7 @@ func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w h OperationSummary: "Trigger the validator to create a mapfix", OperationID: "createMapfix", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -4964,7 +5346,7 @@ func (s *Server) handleCreateMapfixAuditCommentRequest(args [1]string, argsEscap // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -5038,7 +5420,9 @@ func (s *Server) handleCreateMapfixAuditCommentRequest(args [1]string, argsEscap s.cfg.ErrorHandler(ctx, w, r, err) return } - request, close, err := s.decodeCreateMapfixAuditCommentRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateMapfixAuditCommentRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -5062,6 +5446,7 @@ func (s *Server) handleCreateMapfixAuditCommentRequest(args [1]string, argsEscap OperationSummary: "Post a comment to the audit log", OperationID: "createMapfixAuditComment", Body: request, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -5174,7 +5559,7 @@ func (s *Server) handleCreateScriptRequest(args [0]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -5238,7 +5623,9 @@ func (s *Server) handleCreateScriptRequest(args [0]string, argsEscaped bool, w h return } } - request, close, err := s.decodeCreateScriptRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateScriptRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -5262,6 +5649,7 @@ func (s *Server) handleCreateScriptRequest(args [0]string, argsEscaped bool, w h OperationSummary: "Create a new script", OperationID: "createScript", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -5369,7 +5757,7 @@ func (s *Server) handleCreateScriptPolicyRequest(args [0]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -5433,7 +5821,9 @@ func (s *Server) handleCreateScriptPolicyRequest(args [0]string, argsEscaped boo return } } - request, close, err := s.decodeCreateScriptPolicyRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateScriptPolicyRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -5457,6 +5847,7 @@ func (s *Server) handleCreateScriptPolicyRequest(args [0]string, argsEscaped boo OperationSummary: "Create a new script policy", OperationID: "createScriptPolicy", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -5564,7 +5955,7 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -5628,7 +6019,9 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, return } } - request, close, err := s.decodeCreateSubmissionRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateSubmissionRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -5652,6 +6045,7 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, OperationSummary: "Trigger the validator to create a new submission", OperationID: "createSubmission", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -5759,7 +6153,7 @@ func (s *Server) handleCreateSubmissionAdminRequest(args [0]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -5823,7 +6217,9 @@ func (s *Server) handleCreateSubmissionAdminRequest(args [0]string, argsEscaped return } } - request, close, err := s.decodeCreateSubmissionAdminRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateSubmissionAdminRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -5847,6 +6243,7 @@ func (s *Server) handleCreateSubmissionAdminRequest(args [0]string, argsEscaped OperationSummary: "Trigger the validator to create a new submission", OperationID: "createSubmissionAdmin", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -5954,7 +6351,7 @@ func (s *Server) handleCreateSubmissionAuditCommentRequest(args [1]string, argsE // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6028,7 +6425,9 @@ func (s *Server) handleCreateSubmissionAuditCommentRequest(args [1]string, argsE s.cfg.ErrorHandler(ctx, w, r, err) return } - request, close, err := s.decodeCreateSubmissionAuditCommentRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeCreateSubmissionAuditCommentRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -6052,6 +6451,7 @@ func (s *Server) handleCreateSubmissionAuditCommentRequest(args [1]string, argsE OperationSummary: "Post a comment to the audit log", OperationID: "createSubmissionAuditComment", Body: request, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -6164,7 +6564,7 @@ func (s *Server) handleDeleteScriptRequest(args [1]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6239,6 +6639,8 @@ func (s *Server) handleDeleteScriptRequest(args [1]string, argsEscaped bool, w h return } + var rawBody []byte + var response *DeleteScriptNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -6247,6 +6649,7 @@ func (s *Server) handleDeleteScriptRequest(args [1]string, argsEscaped bool, w h OperationSummary: "Delete the specified script by ID", OperationID: "deleteScript", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptID", @@ -6359,7 +6762,7 @@ func (s *Server) handleDeleteScriptPolicyRequest(args [1]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6434,6 +6837,8 @@ func (s *Server) handleDeleteScriptPolicyRequest(args [1]string, argsEscaped boo return } + var rawBody []byte + var response *DeleteScriptPolicyNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -6442,6 +6847,7 @@ func (s *Server) handleDeleteScriptPolicyRequest(args [1]string, argsEscaped boo OperationSummary: "Delete the specified script policy by ID", OperationID: "deleteScriptPolicy", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptPolicyID", @@ -6554,7 +6960,7 @@ func (s *Server) handleDownloadMapAssetRequest(args [1]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6629,6 +7035,8 @@ func (s *Server) handleDownloadMapAssetRequest(args [1]string, argsEscaped bool, return } + var rawBody []byte + var response DownloadMapAssetOK if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -6637,6 +7045,7 @@ func (s *Server) handleDownloadMapAssetRequest(args [1]string, argsEscaped bool, OperationSummary: "Download the map asset", OperationID: "downloadMapAsset", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapID", @@ -6693,6 +7102,162 @@ func (s *Server) handleDownloadMapAssetRequest(args [1]string, argsEscaped bool, } } +// handleGetAssetThumbnailRequest handles getAssetThumbnail operation. +// +// Get single asset thumbnail. +// +// GET /thumbnails/asset/{AssetID} +func (s *Server) handleGetAssetThumbnailRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getAssetThumbnail"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/thumbnails/asset/{AssetID}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), GetAssetThumbnailOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: GetAssetThumbnailOperation, + ID: "getAssetThumbnail", + } + ) + params, err := decodeGetAssetThumbnailParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var rawBody []byte + + var response *GetAssetThumbnailFound + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: GetAssetThumbnailOperation, + OperationSummary: "Get single asset thumbnail", + OperationID: "getAssetThumbnail", + Body: nil, + RawBody: rawBody, + Params: middleware.Parameters{ + { + Name: "AssetID", + In: "path", + }: params.AssetID, + { + Name: "size", + In: "query", + }: params.Size, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = GetAssetThumbnailParams + Response = *GetAssetThumbnailFound + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackGetAssetThumbnailParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GetAssetThumbnail(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.GetAssetThumbnail(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeGetAssetThumbnailResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleGetMapRequest handles getMap operation. // // Retrieve map with ID. @@ -6749,7 +7314,7 @@ func (s *Server) handleGetMapRequest(args [1]string, argsEscaped bool, w http.Re // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6778,6 +7343,8 @@ func (s *Server) handleGetMapRequest(args [1]string, argsEscaped bool, w http.Re return } + var rawBody []byte + var response *Map if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -6786,6 +7353,7 @@ func (s *Server) handleGetMapRequest(args [1]string, argsEscaped bool, w http.Re OperationSummary: "Retrieve map with ID", OperationID: "getMap", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapID", @@ -6898,7 +7466,7 @@ func (s *Server) handleGetMapfixRequest(args [1]string, argsEscaped bool, w http // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -6927,6 +7495,8 @@ func (s *Server) handleGetMapfixRequest(args [1]string, argsEscaped bool, w http return } + var rawBody []byte + var response *Mapfix if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -6935,6 +7505,7 @@ func (s *Server) handleGetMapfixRequest(args [1]string, argsEscaped bool, w http OperationSummary: "Retrieve map with ID", OperationID: "getMapfix", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -7047,7 +7618,7 @@ func (s *Server) handleGetOperationRequest(args [1]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7122,6 +7693,8 @@ func (s *Server) handleGetOperationRequest(args [1]string, argsEscaped bool, w h return } + var rawBody []byte + var response *Operation if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7130,6 +7703,7 @@ func (s *Server) handleGetOperationRequest(args [1]string, argsEscaped bool, w h OperationSummary: "Retrieve operation with ID", OperationID: "getOperation", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "OperationID", @@ -7242,7 +7816,7 @@ func (s *Server) handleGetScriptRequest(args [1]string, argsEscaped bool, w http // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7271,6 +7845,8 @@ func (s *Server) handleGetScriptRequest(args [1]string, argsEscaped bool, w http return } + var rawBody []byte + var response *Script if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7279,6 +7855,7 @@ func (s *Server) handleGetScriptRequest(args [1]string, argsEscaped bool, w http OperationSummary: "Get the specified script by ID", OperationID: "getScript", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptID", @@ -7391,7 +7968,7 @@ func (s *Server) handleGetScriptPolicyRequest(args [1]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7420,6 +7997,8 @@ func (s *Server) handleGetScriptPolicyRequest(args [1]string, argsEscaped bool, return } + var rawBody []byte + var response *ScriptPolicy if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7428,6 +8007,7 @@ func (s *Server) handleGetScriptPolicyRequest(args [1]string, argsEscaped bool, OperationSummary: "Get the specified script policy by ID", OperationID: "getScriptPolicy", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptPolicyID", @@ -7540,7 +8120,7 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7569,6 +8149,8 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w return } + var rawBody []byte + var response *Submission if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7577,6 +8159,7 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w OperationSummary: "Retrieve map with ID", OperationID: "getSubmission", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -7633,6 +8216,162 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w } } +// handleGetUserThumbnailRequest handles getUserThumbnail operation. +// +// Get single user avatar thumbnail. +// +// GET /thumbnails/user/{UserID} +func (s *Server) handleGetUserThumbnailRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getUserThumbnail"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/thumbnails/user/{UserID}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), GetUserThumbnailOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: GetUserThumbnailOperation, + ID: "getUserThumbnail", + } + ) + params, err := decodeGetUserThumbnailParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var rawBody []byte + + var response *GetUserThumbnailFound + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: GetUserThumbnailOperation, + OperationSummary: "Get single user avatar thumbnail", + OperationID: "getUserThumbnail", + Body: nil, + RawBody: rawBody, + Params: middleware.Parameters{ + { + Name: "UserID", + In: "path", + }: params.UserID, + { + Name: "size", + In: "query", + }: params.Size, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = GetUserThumbnailParams + Response = *GetUserThumbnailFound + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackGetUserThumbnailParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GetUserThumbnail(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.GetUserThumbnail(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeGetUserThumbnailResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleListMapfixAuditEventsRequest handles listMapfixAuditEvents operation. // // Retrieve a list of audit events. @@ -7689,7 +8428,7 @@ func (s *Server) handleListMapfixAuditEventsRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7718,6 +8457,8 @@ func (s *Server) handleListMapfixAuditEventsRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response []AuditEvent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7726,6 +8467,7 @@ func (s *Server) handleListMapfixAuditEventsRequest(args [1]string, argsEscaped OperationSummary: "Retrieve a list of audit events", OperationID: "listMapfixAuditEvents", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -7846,7 +8588,7 @@ func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -7875,6 +8617,8 @@ func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w h return } + var rawBody []byte + var response *Mapfixes if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -7883,6 +8627,7 @@ func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w h OperationSummary: "Get list of mapfixes", OperationID: "listMapfixes", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "Page", @@ -8035,7 +8780,7 @@ func (s *Server) handleListMapsRequest(args [0]string, argsEscaped bool, w http. // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8064,6 +8809,8 @@ func (s *Server) handleListMapsRequest(args [0]string, argsEscaped bool, w http. return } + var rawBody []byte + var response []Map if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -8072,6 +8819,7 @@ func (s *Server) handleListMapsRequest(args [0]string, argsEscaped bool, w http. OperationSummary: "Get list of maps", OperationID: "listMaps", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "Page", @@ -8204,7 +8952,7 @@ func (s *Server) handleListScriptPolicyRequest(args [0]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8233,6 +8981,8 @@ func (s *Server) handleListScriptPolicyRequest(args [0]string, argsEscaped bool, return } + var rawBody []byte + var response []ScriptPolicy if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -8241,6 +8991,7 @@ func (s *Server) handleListScriptPolicyRequest(args [0]string, argsEscaped bool, OperationSummary: "Get list of script policies", OperationID: "listScriptPolicy", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "Page", @@ -8369,7 +9120,7 @@ func (s *Server) handleListScriptsRequest(args [0]string, argsEscaped bool, w ht // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8398,6 +9149,8 @@ func (s *Server) handleListScriptsRequest(args [0]string, argsEscaped bool, w ht return } + var rawBody []byte + var response []Script if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -8406,6 +9159,7 @@ func (s *Server) handleListScriptsRequest(args [0]string, argsEscaped bool, w ht OperationSummary: "Get list of scripts", OperationID: "listScripts", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "Page", @@ -8542,7 +9296,7 @@ func (s *Server) handleListSubmissionAuditEventsRequest(args [1]string, argsEsca // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8571,6 +9325,8 @@ func (s *Server) handleListSubmissionAuditEventsRequest(args [1]string, argsEsca return } + var rawBody []byte + var response []AuditEvent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -8579,6 +9335,7 @@ func (s *Server) handleListSubmissionAuditEventsRequest(args [1]string, argsEsca OperationSummary: "Retrieve a list of audit events", OperationID: "listSubmissionAuditEvents", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -8699,7 +9456,7 @@ func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8728,6 +9485,8 @@ func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, return } + var rawBody []byte + var response *Submissions if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -8736,6 +9495,7 @@ func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, OperationSummary: "Get list of submissions", OperationID: "listSubmissions", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "Page", @@ -8888,7 +9648,7 @@ func (s *Server) handleReleaseSubmissionsRequest(args [0]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -8952,7 +9712,9 @@ func (s *Server) handleReleaseSubmissionsRequest(args [0]string, argsEscaped boo return } } - request, close, err := s.decodeReleaseSubmissionsRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeReleaseSubmissionsRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -8976,6 +9738,7 @@ func (s *Server) handleReleaseSubmissionsRequest(args [0]string, argsEscaped boo OperationSummary: "Release a set of uploaded maps. Role SubmissionRelease", OperationID: "releaseSubmissions", Body: request, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -9083,7 +9846,7 @@ func (s *Server) handleSessionRolesRequest(args [0]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -9148,6 +9911,8 @@ func (s *Server) handleSessionRolesRequest(args [0]string, argsEscaped bool, w h } } + var rawBody []byte + var response *Roles if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -9156,6 +9921,7 @@ func (s *Server) handleSessionRolesRequest(args [0]string, argsEscaped bool, w h OperationSummary: "Get list of roles for the current session", OperationID: "sessionRoles", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -9263,7 +10029,7 @@ func (s *Server) handleSessionUserRequest(args [0]string, argsEscaped bool, w ht // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -9328,6 +10094,8 @@ func (s *Server) handleSessionUserRequest(args [0]string, argsEscaped bool, w ht } } + var rawBody []byte + var response *User if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -9336,6 +10104,7 @@ func (s *Server) handleSessionUserRequest(args [0]string, argsEscaped bool, w ht OperationSummary: "Get information about the currently logged in user", OperationID: "sessionUser", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -9443,7 +10212,7 @@ func (s *Server) handleSessionValidateRequest(args [0]string, argsEscaped bool, // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -9508,6 +10277,8 @@ func (s *Server) handleSessionValidateRequest(args [0]string, argsEscaped bool, } } + var rawBody []byte + var response bool if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -9516,6 +10287,7 @@ func (s *Server) handleSessionValidateRequest(args [0]string, argsEscaped bool, OperationSummary: "Ask if the current session is valid", OperationID: "sessionValidate", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{}, Raw: r, } @@ -9623,7 +10395,7 @@ func (s *Server) handleSetMapfixCompletedRequest(args [1]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -9698,6 +10470,8 @@ func (s *Server) handleSetMapfixCompletedRequest(args [1]string, argsEscaped boo return } + var rawBody []byte + var response *SetMapfixCompletedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -9706,6 +10480,7 @@ func (s *Server) handleSetMapfixCompletedRequest(args [1]string, argsEscaped boo OperationSummary: "Called by maptest when a player completes the map", OperationID: "setMapfixCompleted", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -9818,7 +10593,7 @@ func (s *Server) handleSetSubmissionCompletedRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -9893,6 +10668,8 @@ func (s *Server) handleSetSubmissionCompletedRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response *SetSubmissionCompletedNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -9901,6 +10678,7 @@ func (s *Server) handleSetSubmissionCompletedRequest(args [1]string, argsEscaped OperationSummary: "Called by maptest when a player completes the map", OperationID: "setSubmissionCompleted", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", @@ -10013,7 +10791,7 @@ func (s *Server) handleUpdateMapfixModelRequest(args [1]string, argsEscaped bool // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -10088,6 +10866,8 @@ func (s *Server) handleUpdateMapfixModelRequest(args [1]string, argsEscaped bool return } + var rawBody []byte + var response *UpdateMapfixModelNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -10096,6 +10876,7 @@ func (s *Server) handleUpdateMapfixModelRequest(args [1]string, argsEscaped bool OperationSummary: "Update model following role restrictions", OperationID: "updateMapfixModel", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "MapfixID", @@ -10216,7 +10997,7 @@ func (s *Server) handleUpdateScriptRequest(args [1]string, argsEscaped bool, w h // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -10290,7 +11071,9 @@ func (s *Server) handleUpdateScriptRequest(args [1]string, argsEscaped bool, w h s.cfg.ErrorHandler(ctx, w, r, err) return } - request, close, err := s.decodeUpdateScriptRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeUpdateScriptRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -10314,6 +11097,7 @@ func (s *Server) handleUpdateScriptRequest(args [1]string, argsEscaped bool, w h OperationSummary: "Update the specified script by ID", OperationID: "updateScript", Body: request, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptID", @@ -10426,7 +11210,7 @@ func (s *Server) handleUpdateScriptPolicyRequest(args [1]string, argsEscaped boo // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -10500,7 +11284,9 @@ func (s *Server) handleUpdateScriptPolicyRequest(args [1]string, argsEscaped boo s.cfg.ErrorHandler(ctx, w, r, err) return } - request, close, err := s.decodeUpdateScriptPolicyRequest(r) + + var rawBody []byte + request, rawBody, close, err := s.decodeUpdateScriptPolicyRequest(r) if err != nil { err = &ogenerrors.DecodeRequestError{ OperationContext: opErrContext, @@ -10524,6 +11310,7 @@ func (s *Server) handleUpdateScriptPolicyRequest(args [1]string, argsEscaped boo OperationSummary: "Update the specified script policy by ID", OperationID: "updateScriptPolicy", Body: request, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "ScriptPolicyID", @@ -10636,7 +11423,7 @@ func (s *Server) handleUpdateSubmissionModelRequest(args [1]string, argsEscaped // unless there was another error (e.g., network error receiving the response body; or 3xx codes with // max redirects exceeded), in which case status MUST be set to Error. code := statusWriter.status - if code >= 100 && code < 500 { + if code < 100 || code >= 500 { span.SetStatus(codes.Error, stage) } @@ -10711,6 +11498,8 @@ func (s *Server) handleUpdateSubmissionModelRequest(args [1]string, argsEscaped return } + var rawBody []byte + var response *UpdateSubmissionModelNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ @@ -10719,6 +11508,7 @@ func (s *Server) handleUpdateSubmissionModelRequest(args [1]string, argsEscaped OperationSummary: "Update model following role restrictions", OperationID: "updateSubmissionModel", Body: nil, + RawBody: rawBody, Params: middleware.Parameters{ { Name: "SubmissionID", diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go index 7ee6f05..7456cf8 100644 --- a/pkg/api/oas_json_gen.go +++ b/pkg/api/oas_json_gen.go @@ -8,7 +8,6 @@ import ( "github.com/go-faster/errors" "github.com/go-faster/jx" - "github.com/ogen-go/ogen/json" "github.com/ogen-go/ogen/validate" ) @@ -284,6 +283,580 @@ func (s *AuditEventEventData) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *BatchAssetThumbnailsOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *BatchAssetThumbnailsOK) encodeFields(e *jx.Encoder) { + { + if s.Thumbnails.Set { + e.FieldStart("thumbnails") + s.Thumbnails.Encode(e) + } + } +} + +var jsonFieldsNameOfBatchAssetThumbnailsOK = [1]string{ + 0: "thumbnails", +} + +// Decode decodes BatchAssetThumbnailsOK from json. +func (s *BatchAssetThumbnailsOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchAssetThumbnailsOK to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "thumbnails": + if err := func() error { + s.Thumbnails.Reset() + if err := s.Thumbnails.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"thumbnails\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchAssetThumbnailsOK") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *BatchAssetThumbnailsOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchAssetThumbnailsOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s BatchAssetThumbnailsOKThumbnails) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields implements json.Marshaler. +func (s BatchAssetThumbnailsOKThumbnails) encodeFields(e *jx.Encoder) { + for k, elem := range s { + e.FieldStart(k) + + e.Str(elem) + } +} + +// Decode decodes BatchAssetThumbnailsOKThumbnails from json. +func (s *BatchAssetThumbnailsOKThumbnails) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchAssetThumbnailsOKThumbnails to nil") + } + m := s.init() + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + var elem string + if err := func() error { + v, err := d.Str() + elem = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrapf(err, "decode field %q", k) + } + m[string(k)] = elem + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchAssetThumbnailsOKThumbnails") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s BatchAssetThumbnailsOKThumbnails) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchAssetThumbnailsOKThumbnails) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *BatchAssetThumbnailsReq) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *BatchAssetThumbnailsReq) encodeFields(e *jx.Encoder) { + { + e.FieldStart("assetIds") + e.ArrStart() + for _, elem := range s.AssetIds { + e.UInt64(elem) + } + e.ArrEnd() + } + { + if s.Size.Set { + e.FieldStart("size") + s.Size.Encode(e) + } + } +} + +var jsonFieldsNameOfBatchAssetThumbnailsReq = [2]string{ + 0: "assetIds", + 1: "size", +} + +// Decode decodes BatchAssetThumbnailsReq from json. +func (s *BatchAssetThumbnailsReq) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchAssetThumbnailsReq to nil") + } + var requiredBitSet [1]uint8 + s.setDefaults() + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "assetIds": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + s.AssetIds = make([]uint64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem uint64 + v, err := d.UInt64() + elem = uint64(v) + if err != nil { + return err + } + s.AssetIds = append(s.AssetIds, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"assetIds\"") + } + case "size": + if err := func() error { + s.Size.Reset() + if err := s.Size.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"size\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchAssetThumbnailsReq") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfBatchAssetThumbnailsReq) { + name = jsonFieldsNameOfBatchAssetThumbnailsReq[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *BatchAssetThumbnailsReq) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchAssetThumbnailsReq) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes BatchAssetThumbnailsReqSize as json. +func (s BatchAssetThumbnailsReqSize) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes BatchAssetThumbnailsReqSize from json. +func (s *BatchAssetThumbnailsReqSize) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchAssetThumbnailsReqSize to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch BatchAssetThumbnailsReqSize(v) { + case BatchAssetThumbnailsReqSize150x150: + *s = BatchAssetThumbnailsReqSize150x150 + case BatchAssetThumbnailsReqSize420x420: + *s = BatchAssetThumbnailsReqSize420x420 + case BatchAssetThumbnailsReqSize768x432: + *s = BatchAssetThumbnailsReqSize768x432 + default: + *s = BatchAssetThumbnailsReqSize(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s BatchAssetThumbnailsReqSize) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchAssetThumbnailsReqSize) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *BatchUserThumbnailsOK) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *BatchUserThumbnailsOK) encodeFields(e *jx.Encoder) { + { + if s.Thumbnails.Set { + e.FieldStart("thumbnails") + s.Thumbnails.Encode(e) + } + } +} + +var jsonFieldsNameOfBatchUserThumbnailsOK = [1]string{ + 0: "thumbnails", +} + +// Decode decodes BatchUserThumbnailsOK from json. +func (s *BatchUserThumbnailsOK) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchUserThumbnailsOK to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "thumbnails": + if err := func() error { + s.Thumbnails.Reset() + if err := s.Thumbnails.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"thumbnails\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchUserThumbnailsOK") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *BatchUserThumbnailsOK) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchUserThumbnailsOK) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s BatchUserThumbnailsOKThumbnails) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields implements json.Marshaler. +func (s BatchUserThumbnailsOKThumbnails) encodeFields(e *jx.Encoder) { + for k, elem := range s { + e.FieldStart(k) + + e.Str(elem) + } +} + +// Decode decodes BatchUserThumbnailsOKThumbnails from json. +func (s *BatchUserThumbnailsOKThumbnails) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchUserThumbnailsOKThumbnails to nil") + } + m := s.init() + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + var elem string + if err := func() error { + v, err := d.Str() + elem = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrapf(err, "decode field %q", k) + } + m[string(k)] = elem + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchUserThumbnailsOKThumbnails") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s BatchUserThumbnailsOKThumbnails) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchUserThumbnailsOKThumbnails) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *BatchUserThumbnailsReq) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *BatchUserThumbnailsReq) encodeFields(e *jx.Encoder) { + { + e.FieldStart("userIds") + e.ArrStart() + for _, elem := range s.UserIds { + e.UInt64(elem) + } + e.ArrEnd() + } + { + if s.Size.Set { + e.FieldStart("size") + s.Size.Encode(e) + } + } +} + +var jsonFieldsNameOfBatchUserThumbnailsReq = [2]string{ + 0: "userIds", + 1: "size", +} + +// Decode decodes BatchUserThumbnailsReq from json. +func (s *BatchUserThumbnailsReq) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchUserThumbnailsReq to nil") + } + var requiredBitSet [1]uint8 + s.setDefaults() + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "userIds": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + s.UserIds = make([]uint64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem uint64 + v, err := d.UInt64() + elem = uint64(v) + if err != nil { + return err + } + s.UserIds = append(s.UserIds, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"userIds\"") + } + case "size": + if err := func() error { + s.Size.Reset() + if err := s.Size.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"size\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode BatchUserThumbnailsReq") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfBatchUserThumbnailsReq) { + name = jsonFieldsNameOfBatchUserThumbnailsReq[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *BatchUserThumbnailsReq) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchUserThumbnailsReq) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes BatchUserThumbnailsReqSize as json. +func (s BatchUserThumbnailsReqSize) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes BatchUserThumbnailsReqSize from json. +func (s *BatchUserThumbnailsReqSize) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode BatchUserThumbnailsReqSize to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch BatchUserThumbnailsReqSize(v) { + case BatchUserThumbnailsReqSize150x150: + *s = BatchUserThumbnailsReqSize150x150 + case BatchUserThumbnailsReqSize420x420: + *s = BatchUserThumbnailsReqSize420x420 + case BatchUserThumbnailsReqSize768x432: + *s = BatchUserThumbnailsReqSize768x432 + default: + *s = BatchUserThumbnailsReqSize(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s BatchUserThumbnailsReqSize) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *BatchUserThumbnailsReqSize) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *Error) Encode(e *jx.Encoder) { e.ObjStart() @@ -1546,6 +2119,140 @@ func (s *OperationID) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes BatchAssetThumbnailsOKThumbnails as json. +func (o OptBatchAssetThumbnailsOKThumbnails) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes BatchAssetThumbnailsOKThumbnails from json. +func (o *OptBatchAssetThumbnailsOKThumbnails) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBatchAssetThumbnailsOKThumbnails to nil") + } + o.Set = true + o.Value = make(BatchAssetThumbnailsOKThumbnails) + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBatchAssetThumbnailsOKThumbnails) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBatchAssetThumbnailsOKThumbnails) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes BatchAssetThumbnailsReqSize as json. +func (o OptBatchAssetThumbnailsReqSize) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes BatchAssetThumbnailsReqSize from json. +func (o *OptBatchAssetThumbnailsReqSize) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBatchAssetThumbnailsReqSize to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBatchAssetThumbnailsReqSize) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBatchAssetThumbnailsReqSize) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes BatchUserThumbnailsOKThumbnails as json. +func (o OptBatchUserThumbnailsOKThumbnails) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes BatchUserThumbnailsOKThumbnails from json. +func (o *OptBatchUserThumbnailsOKThumbnails) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBatchUserThumbnailsOKThumbnails to nil") + } + o.Set = true + o.Value = make(BatchUserThumbnailsOKThumbnails) + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBatchUserThumbnailsOKThumbnails) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBatchUserThumbnailsOKThumbnails) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes BatchUserThumbnailsReqSize as json. +func (o OptBatchUserThumbnailsReqSize) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes BatchUserThumbnailsReqSize from json. +func (o *OptBatchUserThumbnailsReqSize) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBatchUserThumbnailsReqSize to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBatchUserThumbnailsReqSize) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBatchUserThumbnailsReqSize) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode encodes int32 as json. func (o OptInt32) Encode(e *jx.Encoder) { if !o.Set { diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index fa2d75d..b251bf1 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -30,6 +30,8 @@ const ( ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload" ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate" ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated" + BatchAssetThumbnailsOperation OperationName = "BatchAssetThumbnails" + BatchUserThumbnailsOperation OperationName = "BatchUserThumbnails" CreateMapfixOperation OperationName = "CreateMapfix" CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment" CreateScriptOperation OperationName = "CreateScript" @@ -40,12 +42,14 @@ const ( DeleteScriptOperation OperationName = "DeleteScript" DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy" DownloadMapAssetOperation OperationName = "DownloadMapAsset" + GetAssetThumbnailOperation OperationName = "GetAssetThumbnail" GetMapOperation OperationName = "GetMap" GetMapfixOperation OperationName = "GetMapfix" GetOperationOperation OperationName = "GetOperation" GetScriptOperation OperationName = "GetScript" GetScriptPolicyOperation OperationName = "GetScriptPolicy" GetSubmissionOperation OperationName = "GetSubmission" + GetUserThumbnailOperation OperationName = "GetUserThumbnail" ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents" ListMapfixesOperation OperationName = "ListMapfixes" ListMapsOperation OperationName = "ListMaps" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go index 5107683..b6b84b5 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/api/oas_parameters_gen.go @@ -7,7 +7,6 @@ import ( "net/url" "github.com/go-faster/errors" - "github.com/ogen-go/ogen/conv" "github.com/ogen-go/ogen/middleware" "github.com/ogen-go/ogen/ogenerrors" @@ -77,6 +76,7 @@ func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http. MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -160,6 +160,7 @@ func decodeActionMapfixRejectParams(args [1]string, argsEscaped bool, r *http.Re MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -243,6 +244,7 @@ func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -326,6 +328,7 @@ func decodeActionMapfixResetSubmittingParams(args [1]string, argsEscaped bool, r MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -409,6 +412,7 @@ func decodeActionMapfixRetryValidateParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -492,6 +496,7 @@ func decodeActionMapfixRevokeParams(args [1]string, argsEscaped bool, r *http.Re MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -575,6 +580,7 @@ func decodeActionMapfixTriggerReleaseParams(args [1]string, argsEscaped bool, r MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -658,6 +664,7 @@ func decodeActionMapfixTriggerSubmitParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -741,6 +748,7 @@ func decodeActionMapfixTriggerSubmitUncheckedParams(args [1]string, argsEscaped MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -824,6 +832,7 @@ func decodeActionMapfixTriggerUploadParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -907,6 +916,7 @@ func decodeActionMapfixTriggerValidateParams(args [1]string, argsEscaped bool, r MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -990,6 +1000,7 @@ func decodeActionMapfixUploadedParams(args [1]string, argsEscaped bool, r *http. MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -1073,6 +1084,7 @@ func decodeActionMapfixValidatedParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -1156,6 +1168,7 @@ func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *h MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1239,6 +1252,7 @@ func decodeActionSubmissionRejectParams(args [1]string, argsEscaped bool, r *htt MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1322,6 +1336,7 @@ func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1405,6 +1420,7 @@ func decodeActionSubmissionResetSubmittingParams(args [1]string, argsEscaped boo MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1488,6 +1504,7 @@ func decodeActionSubmissionRetryValidateParams(args [1]string, argsEscaped bool, MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1571,6 +1588,7 @@ func decodeActionSubmissionRevokeParams(args [1]string, argsEscaped bool, r *htt MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1654,6 +1672,7 @@ func decodeActionSubmissionTriggerSubmitParams(args [1]string, argsEscaped bool, MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1737,6 +1756,7 @@ func decodeActionSubmissionTriggerSubmitUncheckedParams(args [1]string, argsEsca MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1820,6 +1840,7 @@ func decodeActionSubmissionTriggerUploadParams(args [1]string, argsEscaped bool, MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1903,6 +1924,7 @@ func decodeActionSubmissionTriggerValidateParams(args [1]string, argsEscaped boo MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -1986,6 +2008,7 @@ func decodeActionSubmissionValidatedParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -2069,6 +2092,7 @@ func decodeCreateMapfixAuditCommentParams(args [1]string, argsEscaped bool, r *h MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -2152,6 +2176,7 @@ func decodeCreateSubmissionAuditCommentParams(args [1]string, argsEscaped bool, MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -2235,6 +2260,7 @@ func decodeDeleteScriptParams(args [1]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -2318,6 +2344,7 @@ func decodeDeleteScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Re MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptPolicyID)); err != nil { return errors.Wrap(err, "int") } @@ -2400,6 +2427,7 @@ func decodeDownloadMapAssetParams(args [1]string, argsEscaped bool, r *http.Requ MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapID)); err != nil { return errors.Wrap(err, "int") } @@ -2421,6 +2449,143 @@ func decodeDownloadMapAssetParams(args [1]string, argsEscaped bool, r *http.Requ return params, nil } +// GetAssetThumbnailParams is parameters of getAssetThumbnail operation. +type GetAssetThumbnailParams struct { + AssetID uint64 + Size OptGetAssetThumbnailSize `json:",omitempty,omitzero"` +} + +func unpackGetAssetThumbnailParams(packed middleware.Parameters) (params GetAssetThumbnailParams) { + { + key := middleware.ParameterKey{ + Name: "AssetID", + In: "path", + } + params.AssetID = packed[key].(uint64) + } + { + key := middleware.ParameterKey{ + Name: "size", + In: "query", + } + if v, ok := packed[key]; ok { + params.Size = v.(OptGetAssetThumbnailSize) + } + } + return params +} + +func decodeGetAssetThumbnailParams(args [1]string, argsEscaped bool, r *http.Request) (params GetAssetThumbnailParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode path: AssetID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "AssetID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToUint64(val) + if err != nil { + return err + } + + params.AssetID = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "AssetID", + In: "path", + Err: err, + } + } + // Set default value for query: size. + { + val := GetAssetThumbnailSize("420x420") + params.Size.SetTo(val) + } + // Decode query: size. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "size", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + var paramsDotSizeVal GetAssetThumbnailSize + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + paramsDotSizeVal = GetAssetThumbnailSize(c) + return nil + }(); err != nil { + return err + } + params.Size.SetTo(paramsDotSizeVal) + return nil + }); err != nil { + return err + } + if err := func() error { + if value, ok := params.Size.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "size", + In: "query", + Err: err, + } + } + return params, nil +} + // GetMapParams is parameters of getMap operation. type GetMapParams struct { // The unique identifier for a map. @@ -2483,6 +2648,7 @@ func decodeGetMapParams(args [1]string, argsEscaped bool, r *http.Request) (para MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapID)); err != nil { return errors.Wrap(err, "int") } @@ -2566,6 +2732,7 @@ func decodeGetMapfixParams(args [1]string, argsEscaped bool, r *http.Request) (p MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -2649,6 +2816,7 @@ func decodeGetOperationParams(args [1]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.OperationID)); err != nil { return errors.Wrap(err, "int") } @@ -2732,6 +2900,7 @@ func decodeGetScriptParams(args [1]string, argsEscaped bool, r *http.Request) (p MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -2815,6 +2984,7 @@ func decodeGetScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptPolicyID)); err != nil { return errors.Wrap(err, "int") } @@ -2898,6 +3068,7 @@ func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -2919,6 +3090,143 @@ func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request return params, nil } +// GetUserThumbnailParams is parameters of getUserThumbnail operation. +type GetUserThumbnailParams struct { + UserID uint64 + Size OptGetUserThumbnailSize `json:",omitempty,omitzero"` +} + +func unpackGetUserThumbnailParams(packed middleware.Parameters) (params GetUserThumbnailParams) { + { + key := middleware.ParameterKey{ + Name: "UserID", + In: "path", + } + params.UserID = packed[key].(uint64) + } + { + key := middleware.ParameterKey{ + Name: "size", + In: "query", + } + if v, ok := packed[key]; ok { + params.Size = v.(OptGetUserThumbnailSize) + } + } + return params +} + +func decodeGetUserThumbnailParams(args [1]string, argsEscaped bool, r *http.Request) (params GetUserThumbnailParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode path: UserID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "UserID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToUint64(val) + if err != nil { + return err + } + + params.UserID = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "UserID", + In: "path", + Err: err, + } + } + // Set default value for query: size. + { + val := GetUserThumbnailSize("150x150") + params.Size.SetTo(val) + } + // Decode query: size. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "size", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + var paramsDotSizeVal GetUserThumbnailSize + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + paramsDotSizeVal = GetUserThumbnailSize(c) + return nil + }(); err != nil { + return err + } + params.Size.SetTo(paramsDotSizeVal) + return nil + }); err != nil { + return err + } + if err := func() error { + if value, ok := params.Size.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "size", + In: "query", + Err: err, + } + } + return params, nil +} + // ListMapfixAuditEventsParams is parameters of listMapfixAuditEvents operation. type ListMapfixAuditEventsParams struct { // The unique identifier for a mapfix. @@ -2998,6 +3306,7 @@ func decodeListMapfixAuditEventsParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -3051,6 +3360,7 @@ func decodeListMapfixAuditEventsParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -3104,6 +3414,7 @@ func decodeListMapfixAuditEventsParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -3129,24 +3440,24 @@ func decodeListMapfixAuditEventsParams(args [1]string, argsEscaped bool, r *http type ListMapfixesParams struct { Page int32 Limit int32 - DisplayName OptString - Creator OptString + DisplayName OptString `json:",omitempty,omitzero"` + Creator OptString `json:",omitempty,omitzero"` // Game ID: * `1` - Bhop * `2` - Surf * `5` - FlyTrials. - GameID OptInt32 + GameID OptInt32 `json:",omitempty,omitzero"` // Sort order: * `0` - Disabled * `1` - DisplayNameAscending * `2` - DisplayNameDescending * `3` - // DateAscending * `4` - DateDescending. - Sort OptInt32 - Submitter OptInt64 - AssetID OptInt64 - AssetVersion OptInt64 - TargetAssetID OptInt64 + Sort OptInt32 `json:",omitempty,omitzero"` + Submitter OptInt64 `json:",omitempty,omitzero"` + AssetID OptInt64 `json:",omitempty,omitzero"` + AssetVersion OptInt64 `json:",omitempty,omitzero"` + TargetAssetID OptInt64 `json:",omitempty,omitzero"` // // Phase: Creation * `0` - UnderConstruction * `1` - ChangesRequested // // Phase: Review * `2` - Submitting * `3` - Submitted // // Phase: Testing * `4` - AcceptedUnvalidated // pending script review, can re-trigger validation // * `5` - Validating * `6` - Validated * `7` - Uploading // // Phase: Final MapfixStatus * `8` - Uploaded // uploaded to the group, but pending release * `9` // - Rejected. - StatusID OptInt32 + StatusID OptInt32 `json:",omitempty,omitzero"` } func unpackListMapfixesParams(packed middleware.Parameters) (params ListMapfixesParams) { @@ -3285,6 +3596,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -3338,6 +3650,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -3392,13 +3705,17 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) if value, ok := params.DisplayName.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -3456,13 +3773,17 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) if value, ok := params.Creator.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -3528,6 +3849,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3593,6 +3915,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3658,6 +3981,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3723,6 +4047,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3788,6 +4113,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3853,6 +4179,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3918,6 +4245,7 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -3946,12 +4274,12 @@ func decodeListMapfixesParams(args [0]string, argsEscaped bool, r *http.Request) type ListMapsParams struct { Page int32 Limit int32 - DisplayName OptString - Creator OptString - GameID OptInt32 + DisplayName OptString `json:",omitempty,omitzero"` + Creator OptString `json:",omitempty,omitzero"` + GameID OptInt32 `json:",omitempty,omitzero"` // Sort order: * `0` - Disabled * `1` - DisplayNameAscending * `2` - DisplayNameDescending * `3` - // DateAscending * `4` - DateDescending. - Sort OptInt32 + Sort OptInt32 `json:",omitempty,omitzero"` } func unpackListMapsParams(packed middleware.Parameters) (params ListMapsParams) { @@ -4045,6 +4373,7 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -4098,6 +4427,7 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -4152,13 +4482,17 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa if value, ok := params.DisplayName.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -4216,13 +4550,17 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa if value, ok := params.Creator.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -4288,6 +4626,7 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -4353,6 +4692,7 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -4381,9 +4721,9 @@ func decodeListMapsParams(args [0]string, argsEscaped bool, r *http.Request) (pa type ListScriptPolicyParams struct { Page int32 Limit int32 - FromScriptHash OptString - ToScriptID OptInt64 - Policy OptInt32 + FromScriptHash OptString `json:",omitempty,omitzero"` + ToScriptID OptInt64 `json:",omitempty,omitzero"` + Policy OptInt32 `json:",omitempty,omitzero"` } func unpackListScriptPolicyParams(packed middleware.Parameters) (params ListScriptPolicyParams) { @@ -4468,6 +4808,7 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -4521,6 +4862,7 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -4575,13 +4917,17 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ if value, ok := params.FromScriptHash.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 16, - MinLengthSet: true, - MaxLength: 16, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 16, + MinLengthSet: true, + MaxLength: 16, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -4647,6 +4993,7 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -4712,6 +5059,7 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -4740,11 +5088,11 @@ func decodeListScriptPolicyParams(args [0]string, argsEscaped bool, r *http.Requ type ListScriptsParams struct { Page int32 Limit int32 - Hash OptString - Name OptString - Source OptString - ResourceType OptInt32 - ResourceID OptInt64 + Hash OptString `json:",omitempty,omitzero"` + Name OptString `json:",omitempty,omitzero"` + Source OptString `json:",omitempty,omitzero"` + ResourceType OptInt32 `json:",omitempty,omitzero"` + ResourceID OptInt64 `json:",omitempty,omitzero"` } func unpackListScriptsParams(packed middleware.Parameters) (params ListScriptsParams) { @@ -4847,6 +5195,7 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -4900,6 +5249,7 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -4954,13 +5304,17 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) if value, ok := params.Hash.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 16, - MinLengthSet: true, - MaxLength: 16, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 16, + MinLengthSet: true, + MaxLength: 16, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -5018,13 +5372,17 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) if value, ok := params.Name.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -5082,13 +5440,17 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) if value, ok := params.Source.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 1048576, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 1048576, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -5154,6 +5516,7 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -5219,6 +5582,7 @@ func decodeListScriptsParams(args [0]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -5322,6 +5686,7 @@ func decodeListSubmissionAuditEventsParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -5375,6 +5740,7 @@ func decodeListSubmissionAuditEventsParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -5428,6 +5794,7 @@ func decodeListSubmissionAuditEventsParams(args [1]string, argsEscaped bool, r * MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -5453,24 +5820,24 @@ func decodeListSubmissionAuditEventsParams(args [1]string, argsEscaped bool, r * type ListSubmissionsParams struct { Page int32 Limit int32 - DisplayName OptString - Creator OptString + DisplayName OptString `json:",omitempty,omitzero"` + Creator OptString `json:",omitempty,omitzero"` // Game ID: * `1` - Bhop * `2` - Surf * `5` - FlyTrials. - GameID OptInt32 + GameID OptInt32 `json:",omitempty,omitzero"` // Sort order: * `0` - Disabled * `1` - DisplayNameAscending * `2` - DisplayNameDescending * `3` - // DateAscending * `4` - DateDescending. - Sort OptInt32 - Submitter OptInt64 - AssetID OptInt64 - AssetVersion OptInt64 - UploadedAssetID OptInt64 + Sort OptInt32 `json:",omitempty,omitzero"` + Submitter OptInt64 `json:",omitempty,omitzero"` + AssetID OptInt64 `json:",omitempty,omitzero"` + AssetVersion OptInt64 `json:",omitempty,omitzero"` + UploadedAssetID OptInt64 `json:",omitempty,omitzero"` // // Phase: Creation * `0` - UnderConstruction * `1` - ChangesRequested // // Phase: Review * `2` - Submitting * `3` - Submitted // // Phase: Testing * `4` - AcceptedUnvalidated // pending script review, can re-trigger validation // * `5` - Validating * `6` - Validated * `7` - Uploading * `8` - Uploaded // uploaded to the group, // but pending release // // Phase: Final SubmissionStatus * `9` - Rejected * `10` - Released. - StatusID OptInt32 + StatusID OptInt32 `json:",omitempty,omitzero"` } func unpackListSubmissionsParams(packed middleware.Parameters) (params ListSubmissionsParams) { @@ -5609,6 +5976,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Page)); err != nil { return errors.Wrap(err, "int") } @@ -5662,6 +6030,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.Limit)); err != nil { return errors.Wrap(err, "int") } @@ -5716,13 +6085,17 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque if value, ok := params.DisplayName.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -5780,13 +6153,17 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque if value, ok := params.Creator.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -5852,6 +6229,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -5917,6 +6295,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -5982,6 +6361,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -6047,6 +6427,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -6112,6 +6493,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -6177,6 +6559,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -6242,6 +6625,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -6328,6 +6712,7 @@ func decodeSetMapfixCompletedParams(args [1]string, argsEscaped bool, r *http.Re MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -6411,6 +6796,7 @@ func decodeSetSubmissionCompletedParams(args [1]string, argsEscaped bool, r *htt MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -6511,6 +6897,7 @@ func decodeUpdateMapfixModelParams(args [1]string, argsEscaped bool, r *http.Req MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.MapfixID)); err != nil { return errors.Wrap(err, "int") } @@ -6564,6 +6951,7 @@ func decodeUpdateMapfixModelParams(args [1]string, argsEscaped bool, r *http.Req MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ModelID)); err != nil { return errors.Wrap(err, "int") } @@ -6617,6 +7005,7 @@ func decodeUpdateMapfixModelParams(args [1]string, argsEscaped bool, r *http.Req MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ModelVersion)); err != nil { return errors.Wrap(err, "int") } @@ -6700,6 +7089,7 @@ func decodeUpdateScriptParams(args [1]string, argsEscaped bool, r *http.Request) MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -6783,6 +7173,7 @@ func decodeUpdateScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Re MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ScriptPolicyID)); err != nil { return errors.Wrap(err, "int") } @@ -6883,6 +7274,7 @@ func decodeUpdateSubmissionModelParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -6936,6 +7328,7 @@ func decodeUpdateSubmissionModelParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ModelID)); err != nil { return errors.Wrap(err, "int") } @@ -6989,6 +7382,7 @@ func decodeUpdateSubmissionModelParams(args [1]string, argsEscaped bool, r *http MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(params.ModelVersion)); err != nil { return errors.Wrap(err, "int") } diff --git a/pkg/api/oas_request_decoders_gen.go b/pkg/api/oas_request_decoders_gen.go index 24ca5bf..8e8cbb3 100644 --- a/pkg/api/oas_request_decoders_gen.go +++ b/pkg/api/oas_request_decoders_gen.go @@ -3,6 +3,7 @@ package api import ( + "bytes" "fmt" "io" "mime" @@ -10,13 +11,13 @@ import ( "github.com/go-faster/errors" "github.com/go-faster/jx" - "github.com/ogen-go/ogen/ogenerrors" "github.com/ogen-go/ogen/validate" ) -func (s *Server) decodeCreateMapfixRequest(r *http.Request) ( - req *MapfixTriggerCreate, +func (s *Server) decodeBatchAssetThumbnailsRequest(r *http.Request) ( + req *BatchAssetThumbnailsReq, + rawBody []byte, close func() error, rerr error, ) { @@ -37,22 +38,187 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) + d := jx.DecodeBytes(buf) + + var request BatchAssetThumbnailsReq + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, rawBody, close, err + } + if err := func() error { + if err := request.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return req, rawBody, close, errors.Wrap(err, "validate") + } + return &request, rawBody, close, nil + default: + return req, rawBody, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeBatchUserThumbnailsRequest(r *http.Request) ( + req *BatchUserThumbnailsReq, + rawBody []byte, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = errors.Join(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = errors.Join(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, rawBody, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, rawBody, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() + if err != nil { + return req, rawBody, close, err + } + + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + + if len(buf) == 0 { + return req, rawBody, close, validate.ErrBodyRequired + } + + rawBody = append(rawBody, buf...) + d := jx.DecodeBytes(buf) + + var request BatchUserThumbnailsReq + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, rawBody, close, err + } + if err := func() error { + if err := request.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return req, rawBody, close, errors.Wrap(err, "validate") + } + return &request, rawBody, close, nil + default: + return req, rawBody, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeCreateMapfixRequest(r *http.Request) ( + req *MapfixTriggerCreate, + rawBody []byte, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = errors.Join(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = errors.Join(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, rawBody, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, rawBody, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() + if err != nil { + return req, rawBody, close, err + } + + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + + if len(buf) == 0 { + return req, rawBody, close, validate.ErrBodyRequired + } + + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request MapfixTriggerCreate @@ -70,7 +236,7 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -78,16 +244,17 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) ( req CreateMapfixAuditCommentReq, + rawBody []byte, close func() error, rerr error, ) { @@ -108,20 +275,21 @@ func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "text/plain": reader := r.Body request := CreateMapfixAuditCommentReq{Data: reader} - return request, close, nil + return request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateScriptRequest(r *http.Request) ( req *ScriptCreate, + rawBody []byte, close func() error, rerr error, ) { @@ -142,22 +310,29 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request ScriptCreate @@ -175,7 +350,7 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -183,16 +358,17 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) ( req *ScriptPolicyCreate, + rawBody []byte, close func() error, rerr error, ) { @@ -213,22 +389,29 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request ScriptPolicyCreate @@ -246,7 +429,7 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -254,16 +437,17 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateSubmissionRequest(r *http.Request) ( req *SubmissionTriggerCreate, + rawBody []byte, close func() error, rerr error, ) { @@ -284,22 +468,29 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request SubmissionTriggerCreate @@ -317,7 +508,7 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -325,16 +516,17 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) ( req *SubmissionTriggerCreate, + rawBody []byte, close func() error, rerr error, ) { @@ -355,22 +547,29 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request SubmissionTriggerCreate @@ -388,7 +587,7 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -396,16 +595,17 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) ( req CreateSubmissionAuditCommentReq, + rawBody []byte, close func() error, rerr error, ) { @@ -426,20 +626,21 @@ func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "text/plain": reader := r.Body request := CreateSubmissionAuditCommentReq{Data: reader} - return request, close, nil + return request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) ( req []ReleaseInfo, + rawBody []byte, close func() error, rerr error, ) { @@ -460,22 +661,29 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request []ReleaseInfo @@ -501,7 +709,7 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if request == nil { @@ -534,16 +742,17 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return request, close, nil + return request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeUpdateScriptRequest(r *http.Request) ( req *ScriptUpdate, + rawBody []byte, close func() error, rerr error, ) { @@ -564,22 +773,29 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request ScriptUpdate @@ -597,7 +813,7 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -605,16 +821,17 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) ( req *ScriptPolicyUpdate, + rawBody []byte, close func() error, rerr error, ) { @@ -635,22 +852,29 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) ( }() ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { - return req, close, errors.Wrap(err, "parse media type") + return req, rawBody, close, errors.Wrap(err, "parse media type") } switch { case ct == "application/json": if r.ContentLength == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } buf, err := io.ReadAll(r.Body) + defer func() { + _ = r.Body.Close() + }() if err != nil { - return req, close, err + return req, rawBody, close, err } + // Reset the body to allow for downstream reading. + r.Body = io.NopCloser(bytes.NewBuffer(buf)) + if len(buf) == 0 { - return req, close, validate.ErrBodyRequired + return req, rawBody, close, validate.ErrBodyRequired } + rawBody = append(rawBody, buf...) d := jx.DecodeBytes(buf) var request ScriptPolicyUpdate @@ -668,7 +892,7 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) ( Body: buf, Err: err, } - return req, close, err + return req, rawBody, close, err } if err := func() error { if err := request.Validate(); err != nil { @@ -676,10 +900,10 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) ( } return nil }(); err != nil { - return req, close, errors.Wrap(err, "validate") + return req, rawBody, close, errors.Wrap(err, "validate") } - return &request, close, nil + return &request, rawBody, close, nil default: - return req, close, validate.InvalidContentType(ct) + return req, rawBody, close, validate.InvalidContentType(ct) } } diff --git a/pkg/api/oas_request_encoders_gen.go b/pkg/api/oas_request_encoders_gen.go index 09c700c..6520bb4 100644 --- a/pkg/api/oas_request_encoders_gen.go +++ b/pkg/api/oas_request_encoders_gen.go @@ -7,10 +7,37 @@ import ( "net/http" "github.com/go-faster/jx" - ht "github.com/ogen-go/ogen/http" ) +func encodeBatchAssetThumbnailsRequest( + req *BatchAssetThumbnailsReq, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeBatchUserThumbnailsRequest( + req *BatchUserThumbnailsReq, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + func encodeCreateMapfixRequest( req *MapfixTriggerCreate, r *http.Request, diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index 25ecc22..c5de549 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -11,8 +11,9 @@ import ( "github.com/go-faster/errors" "github.com/go-faster/jx" - + "github.com/ogen-go/ogen/conv" "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/uri" "github.com/ogen-go/ogen/validate" ) @@ -1456,6 +1457,190 @@ func decodeActionSubmissionValidatedResponse(resp *http.Response) (res *ActionSu return res, errors.Wrap(defRes, "error") } +func decodeBatchAssetThumbnailsResponse(resp *http.Response) (res *BatchAssetThumbnailsOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response BatchAssetThumbnailsOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + +func decodeBatchUserThumbnailsResponse(resp *http.Response) (res *BatchUserThumbnailsOK, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response BatchUserThumbnailsOK + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeCreateMapfixResponse(resp *http.Response) (res *OperationID, _ error) { switch resp.StatusCode { case 201: @@ -2277,6 +2462,105 @@ func decodeDownloadMapAssetResponse(resp *http.Response) (res DownloadMapAssetOK return res, errors.Wrap(defRes, "error") } +func decodeGetAssetThumbnailResponse(resp *http.Response) (res *GetAssetThumbnailFound, _ error) { + switch resp.StatusCode { + case 302: + // Code 302. + var wrapper GetAssetThumbnailFound + h := uri.NewHeaderDecoder(resp.Header) + // Parse "Location" header. + { + cfg := uri.HeaderParameterDecodingConfig{ + Name: "Location", + Explode: false, + } + if err := func() error { + if err := h.HasParam(cfg); err == nil { + if err := h.DecodeParam(cfg, func(d uri.Decoder) error { + var wrapperDotLocationVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + wrapperDotLocationVal = c + return nil + }(); err != nil { + return err + } + wrapper.Location.SetTo(wrapperDotLocationVal) + return nil + }); err != nil { + return err + } + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "parse Location header") + } + } + return &wrapper, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeGetMapResponse(resp *http.Response) (res *Map, _ error) { switch resp.StatusCode { case 200: @@ -2883,6 +3167,105 @@ func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) return res, errors.Wrap(defRes, "error") } +func decodeGetUserThumbnailResponse(resp *http.Response) (res *GetUserThumbnailFound, _ error) { + switch resp.StatusCode { + case 302: + // Code 302. + var wrapper GetUserThumbnailFound + h := uri.NewHeaderDecoder(resp.Header) + // Parse "Location" header. + { + cfg := uri.HeaderParameterDecodingConfig{ + Name: "Location", + Explode: false, + } + if err := func() error { + if err := h.HasParam(cfg); err == nil { + if err := h.DecodeParam(cfg, func(d uri.Decoder) error { + var wrapperDotLocationVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + wrapperDotLocationVal = c + return nil + }(); err != nil { + return err + } + wrapper.Location.SetTo(wrapperDotLocationVal) + return nil + }); err != nil { + return err + } + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "parse Location header") + } + } + return &wrapper, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeListMapfixAuditEventsResponse(resp *http.Response) (res []AuditEvent, _ error) { switch resp.StatusCode { case 200: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index abd0578..483cfe6 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -8,10 +8,11 @@ import ( "github.com/go-faster/errors" "github.com/go-faster/jx" + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/uri" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/trace" - - ht "github.com/ogen-go/ogen/http" ) func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, w http.ResponseWriter, span trace.Span) error { @@ -182,6 +183,34 @@ func encodeActionSubmissionValidatedResponse(response *ActionSubmissionValidated return nil } +func encodeBatchAssetThumbnailsResponse(response *BatchAssetThumbnailsOK, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeBatchUserThumbnailsResponse(response *BatchUserThumbnailsOK, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + func encodeCreateMapfixResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(201) @@ -296,6 +325,32 @@ func encodeDownloadMapAssetResponse(response DownloadMapAssetOK, w http.Response return nil } +func encodeGetAssetThumbnailResponse(response *GetAssetThumbnailFound, w http.ResponseWriter, span trace.Span) error { + // Encoding response headers. + { + h := uri.NewHeaderEncoder(w.Header()) + // Encode "Location" header. + { + cfg := uri.HeaderParameterEncodingConfig{ + Name: "Location", + Explode: false, + } + if err := h.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := response.Location.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode Location header") + } + } + } + w.WriteHeader(302) + span.SetStatus(codes.Ok, http.StatusText(302)) + + return nil +} + func encodeGetMapResponse(response *Map, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) @@ -380,6 +435,32 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp return nil } +func encodeGetUserThumbnailResponse(response *GetUserThumbnailFound, w http.ResponseWriter, span trace.Span) error { + // Encoding response headers. + { + h := uri.NewHeaderEncoder(w.Header()) + // Encode "Location" header. + { + cfg := uri.HeaderParameterEncodingConfig{ + Name: "Location", + Explode: false, + } + if err := h.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := response.Location.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode Location header") + } + } + } + w.WriteHeader(302) + span.SetStatus(codes.Ok, http.StatusText(302)) + + return nil +} + func encodeListMapfixAuditEventsResponse(response []AuditEvent, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index 50cc71f..cbba73d 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -1431,6 +1431,150 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } + case 't': // Prefix: "thumbnails/" + + if l := len("thumbnails/"); len(elem) >= l && elem[0:l] == "thumbnails/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'a': // Prefix: "asset" + + if l := len("asset"); len(elem) >= l && elem[0:l] == "asset" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "AssetID" + // Leaf parameter, slashes are prohibited + idx := strings.IndexByte(elem, '/') + if idx >= 0 { + break + } + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleGetAssetThumbnailRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleBatchAssetThumbnailsRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + case 'u': // Prefix: "user" + + if l := len("user"); len(elem) >= l && elem[0:l] == "user" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "UserID" + // Leaf parameter, slashes are prohibited + idx := strings.IndexByte(elem, '/') + if idx >= 0 { + break + } + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleGetUserThumbnailRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleBatchUserThumbnailsRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + + } + } } @@ -1440,12 +1584,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Route is route object. type Route struct { - name string - summary string - operationID string - pathPattern string - count int - args [1]string + name string + summary string + operationID string + operationGroup string + pathPattern string + count int + args [1]string } // Name returns ogen operation name. @@ -1465,6 +1610,11 @@ func (r Route) OperationID() string { return r.operationID } +// OperationGroup returns the x-ogen-operation-group value. +func (r Route) OperationGroup() string { + return r.operationGroup +} + // PathPattern returns OpenAPI path. func (r Route) PathPattern() string { return r.pathPattern @@ -1551,6 +1701,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListMapfixesOperation r.summary = "Get list of mapfixes" r.operationID = "listMapfixes" + r.operationGroup = "" r.pathPattern = "/mapfixes" r.args = args r.count = 0 @@ -1559,6 +1710,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateMapfixOperation r.summary = "Trigger the validator to create a mapfix" r.operationID = "createMapfix" + r.operationGroup = "" r.pathPattern = "/mapfixes" r.args = args r.count = 0 @@ -1591,6 +1743,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetMapfixOperation r.summary = "Retrieve map with ID" r.operationID = "getMapfix" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}" r.args = args r.count = 1 @@ -1627,6 +1780,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListMapfixAuditEventsOperation r.summary = "Retrieve a list of audit events" r.operationID = "listMapfixAuditEvents" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/audit-events" r.args = args r.count = 1 @@ -1663,6 +1817,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateMapfixAuditCommentOperation r.summary = "Post a comment to the audit log" r.operationID = "createMapfixAuditComment" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/comment" r.args = args r.count = 1 @@ -1687,6 +1842,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = SetMapfixCompletedOperation r.summary = "Called by maptest when a player completes the map" r.operationID = "setMapfixCompleted" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/completed" r.args = args r.count = 1 @@ -1713,6 +1869,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = UpdateMapfixModelOperation r.summary = "Update model following role restrictions" r.operationID = "updateMapfixModel" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/model" r.args = args r.count = 1 @@ -1761,6 +1918,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixRejectOperation r.summary = "Role Reviewer changes status from Submitted -> Rejected" r.operationID = "actionMapfixReject" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/reject" r.args = args r.count = 1 @@ -1785,6 +1943,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixRequestChangesOperation r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested" r.operationID = "actionMapfixRequestChanges" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/request-changes" r.args = args r.count = 1 @@ -1821,6 +1980,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixUploadedOperation r.summary = "Role MapfixUpload manually resets releasing softlock and changes status from Releasing -> Uploaded" r.operationID = "actionMapfixUploaded" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/reset-releasing" r.args = args r.count = 1 @@ -1845,6 +2005,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixResetSubmittingOperation r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction" r.operationID = "actionMapfixResetSubmitting" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/reset-submitting" r.args = args r.count = 1 @@ -1869,6 +2030,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixValidatedOperation r.summary = "Role MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated" r.operationID = "actionMapfixValidated" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/reset-uploading" r.args = args r.count = 1 @@ -1893,6 +2055,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixAcceptedOperation r.summary = "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted" r.operationID = "actionMapfixAccepted" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/reset-validating" r.args = args r.count = 1 @@ -1919,6 +2082,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixRetryValidateOperation r.summary = "Role Reviewer re-runs validation and changes status from Accepted -> Validating" r.operationID = "actionMapfixRetryValidate" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/retry-validate" r.args = args r.count = 1 @@ -1943,6 +2107,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixRevokeOperation r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction" r.operationID = "actionMapfixRevoke" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/revoke" r.args = args r.count = 1 @@ -1981,6 +2146,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixTriggerReleaseOperation r.summary = "Role MapfixUpload changes status from Uploaded -> Releasing" r.operationID = "actionMapfixTriggerRelease" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-release" r.args = args r.count = 1 @@ -2004,6 +2170,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixTriggerSubmitOperation r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting" r.operationID = "actionMapfixTriggerSubmit" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit" r.args = args r.count = 1 @@ -2028,6 +2195,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixTriggerSubmitUncheckedOperation r.summary = "Role Reviewer changes status from ChangesRequested -> Submitting" r.operationID = "actionMapfixTriggerSubmitUnchecked" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit-unchecked" r.args = args r.count = 1 @@ -2054,6 +2222,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixTriggerUploadOperation r.summary = "Role MapfixUpload changes status from Validated -> Uploading" r.operationID = "actionMapfixTriggerUpload" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-upload" r.args = args r.count = 1 @@ -2078,6 +2247,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionMapfixTriggerValidateOperation r.summary = "Role Reviewer triggers validation and changes status from Submitted -> Validating" r.operationID = "actionMapfixTriggerValidate" + r.operationGroup = "" r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-validate" r.args = args r.count = 1 @@ -2111,6 +2281,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListMapsOperation r.summary = "Get list of maps" r.operationID = "listMaps" + r.operationGroup = "" r.pathPattern = "/maps" r.args = args r.count = 0 @@ -2143,6 +2314,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetMapOperation r.summary = "Retrieve map with ID" r.operationID = "getMap" + r.operationGroup = "" r.pathPattern = "/maps/{MapID}" r.args = args r.count = 1 @@ -2167,6 +2339,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = DownloadMapAssetOperation r.summary = "Download the map asset" r.operationID = "downloadMapAsset" + r.operationGroup = "" r.pathPattern = "/maps/{MapID}/download" r.args = args r.count = 1 @@ -2206,6 +2379,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetOperationOperation r.summary = "Retrieve operation with ID" r.operationID = "getOperation" + r.operationGroup = "" r.pathPattern = "/operations/{OperationID}" r.args = args r.count = 1 @@ -2230,6 +2404,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ReleaseSubmissionsOperation r.summary = "Release a set of uploaded maps. Role SubmissionRelease" r.operationID = "releaseSubmissions" + r.operationGroup = "" r.pathPattern = "/release-submissions" r.args = args r.count = 0 @@ -2277,6 +2452,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListScriptPolicyOperation r.summary = "Get list of script policies" r.operationID = "listScriptPolicy" + r.operationGroup = "" r.pathPattern = "/script-policy" r.args = args r.count = 0 @@ -2285,6 +2461,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateScriptPolicyOperation r.summary = "Create a new script policy" r.operationID = "createScriptPolicy" + r.operationGroup = "" r.pathPattern = "/script-policy" r.args = args r.count = 0 @@ -2318,6 +2495,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = DeleteScriptPolicyOperation r.summary = "Delete the specified script policy by ID" r.operationID = "deleteScriptPolicy" + r.operationGroup = "" r.pathPattern = "/script-policy/{ScriptPolicyID}" r.args = args r.count = 1 @@ -2326,6 +2504,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetScriptPolicyOperation r.summary = "Get the specified script policy by ID" r.operationID = "getScriptPolicy" + r.operationGroup = "" r.pathPattern = "/script-policy/{ScriptPolicyID}" r.args = args r.count = 1 @@ -2334,6 +2513,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = UpdateScriptPolicyOperation r.summary = "Update the specified script policy by ID" r.operationID = "updateScriptPolicy" + r.operationGroup = "" r.pathPattern = "/script-policy/{ScriptPolicyID}" r.args = args r.count = 1 @@ -2359,6 +2539,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListScriptsOperation r.summary = "Get list of scripts" r.operationID = "listScripts" + r.operationGroup = "" r.pathPattern = "/scripts" r.args = args r.count = 0 @@ -2367,6 +2548,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateScriptOperation r.summary = "Create a new script" r.operationID = "createScript" + r.operationGroup = "" r.pathPattern = "/scripts" r.args = args r.count = 0 @@ -2400,6 +2582,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = DeleteScriptOperation r.summary = "Delete the specified script by ID" r.operationID = "deleteScript" + r.operationGroup = "" r.pathPattern = "/scripts/{ScriptID}" r.args = args r.count = 1 @@ -2408,6 +2591,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetScriptOperation r.summary = "Get the specified script by ID" r.operationID = "getScript" + r.operationGroup = "" r.pathPattern = "/scripts/{ScriptID}" r.args = args r.count = 1 @@ -2416,6 +2600,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = UpdateScriptOperation r.summary = "Update the specified script by ID" r.operationID = "updateScript" + r.operationGroup = "" r.pathPattern = "/scripts/{ScriptID}" r.args = args r.count = 1 @@ -2456,6 +2641,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = SessionRolesOperation r.summary = "Get list of roles for the current session" r.operationID = "sessionRoles" + r.operationGroup = "" r.pathPattern = "/session/roles" r.args = args r.count = 0 @@ -2480,6 +2666,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = SessionUserOperation r.summary = "Get information about the currently logged in user" r.operationID = "sessionUser" + r.operationGroup = "" r.pathPattern = "/session/user" r.args = args r.count = 0 @@ -2504,6 +2691,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = SessionValidateOperation r.summary = "Ask if the current session is valid" r.operationID = "sessionValidate" + r.operationGroup = "" r.pathPattern = "/session/validate" r.args = args r.count = 0 @@ -2529,6 +2717,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListSubmissionsOperation r.summary = "Get list of submissions" r.operationID = "listSubmissions" + r.operationGroup = "" r.pathPattern = "/submissions" r.args = args r.count = 0 @@ -2537,6 +2726,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateSubmissionOperation r.summary = "Trigger the validator to create a new submission" r.operationID = "createSubmission" + r.operationGroup = "" r.pathPattern = "/submissions" r.args = args r.count = 0 @@ -2561,6 +2751,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateSubmissionAdminOperation r.summary = "Trigger the validator to create a new submission" r.operationID = "createSubmissionAdmin" + r.operationGroup = "" r.pathPattern = "/submissions-admin" r.args = args r.count = 0 @@ -2593,6 +2784,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = GetSubmissionOperation r.summary = "Retrieve map with ID" r.operationID = "getSubmission" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}" r.args = args r.count = 1 @@ -2629,6 +2821,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ListSubmissionAuditEventsOperation r.summary = "Retrieve a list of audit events" r.operationID = "listSubmissionAuditEvents" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/audit-events" r.args = args r.count = 1 @@ -2665,6 +2858,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = CreateSubmissionAuditCommentOperation r.summary = "Post a comment to the audit log" r.operationID = "createSubmissionAuditComment" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/comment" r.args = args r.count = 1 @@ -2689,6 +2883,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = SetSubmissionCompletedOperation r.summary = "Called by maptest when a player completes the map" r.operationID = "setSubmissionCompleted" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/completed" r.args = args r.count = 1 @@ -2715,6 +2910,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = UpdateSubmissionModelOperation r.summary = "Update model following role restrictions" r.operationID = "updateSubmissionModel" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/model" r.args = args r.count = 1 @@ -2763,6 +2959,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionRejectOperation r.summary = "Role Reviewer changes status from Submitted -> Rejected" r.operationID = "actionSubmissionReject" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/reject" r.args = args r.count = 1 @@ -2787,6 +2984,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionRequestChangesOperation r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested" r.operationID = "actionSubmissionRequestChanges" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/request-changes" r.args = args r.count = 1 @@ -2823,6 +3021,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionResetSubmittingOperation r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction" r.operationID = "actionSubmissionResetSubmitting" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/reset-submitting" r.args = args r.count = 1 @@ -2847,6 +3046,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionValidatedOperation r.summary = "Role SubmissionUpload manually resets uploading softlock and changes status from Uploading -> Validated" r.operationID = "actionSubmissionValidated" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/reset-uploading" r.args = args r.count = 1 @@ -2871,6 +3071,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionAcceptedOperation r.summary = "Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted" r.operationID = "actionSubmissionAccepted" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/reset-validating" r.args = args r.count = 1 @@ -2897,6 +3098,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionRetryValidateOperation r.summary = "Role Reviewer re-runs validation and changes status from Accepted -> Validating" r.operationID = "actionSubmissionRetryValidate" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/retry-validate" r.args = args r.count = 1 @@ -2921,6 +3123,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionRevokeOperation r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction" r.operationID = "actionSubmissionRevoke" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/revoke" r.args = args r.count = 1 @@ -2958,6 +3161,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionTriggerSubmitOperation r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting" r.operationID = "actionSubmissionTriggerSubmit" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/trigger-submit" r.args = args r.count = 1 @@ -2982,6 +3186,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionTriggerSubmitUncheckedOperation r.summary = "Role Reviewer changes status from ChangesRequested -> Submitting" r.operationID = "actionSubmissionTriggerSubmitUnchecked" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/trigger-submit-unchecked" r.args = args r.count = 1 @@ -3008,6 +3213,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionTriggerUploadOperation r.summary = "Role SubmissionUpload changes status from Validated -> Uploading" r.operationID = "actionSubmissionTriggerUpload" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/trigger-upload" r.args = args r.count = 1 @@ -3032,6 +3238,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { r.name = ActionSubmissionTriggerValidateOperation r.summary = "Role Reviewer triggers validation and changes status from Submitted -> Validating" r.operationID = "actionSubmissionTriggerValidate" + r.operationGroup = "" r.pathPattern = "/submissions/{SubmissionID}/status/trigger-validate" r.args = args r.count = 1 @@ -3053,6 +3260,166 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } + case 't': // Prefix: "thumbnails/" + + if l := len("thumbnails/"); len(elem) >= l && elem[0:l] == "thumbnails/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'a': // Prefix: "asset" + + if l := len("asset"); len(elem) >= l && elem[0:l] == "asset" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "AssetID" + // Leaf parameter, slashes are prohibited + idx := strings.IndexByte(elem, '/') + if idx >= 0 { + break + } + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = GetAssetThumbnailOperation + r.summary = "Get single asset thumbnail" + r.operationID = "getAssetThumbnail" + r.operationGroup = "" + r.pathPattern = "/thumbnails/asset/{AssetID}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = BatchAssetThumbnailsOperation + r.summary = "Batch fetch asset thumbnails" + r.operationID = "batchAssetThumbnails" + r.operationGroup = "" + r.pathPattern = "/thumbnails/assets" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + + } + + case 'u': // Prefix: "user" + + if l := len("user"); len(elem) >= l && elem[0:l] == "user" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + // Param: "UserID" + // Leaf parameter, slashes are prohibited + idx := strings.IndexByte(elem, '/') + if idx >= 0 { + break + } + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = GetUserThumbnailOperation + r.summary = "Get single user avatar thumbnail" + r.operationID = "getUserThumbnail" + r.operationGroup = "" + r.pathPattern = "/thumbnails/user/{UserID}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 's': // Prefix: "s" + + if l := len("s"); len(elem) >= l && elem[0:l] == "s" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = BatchUserThumbnailsOperation + r.summary = "Batch fetch user avatar thumbnails" + r.operationID = "batchUserThumbnails" + r.operationGroup = "" + r.pathPattern = "/thumbnails/users" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + + } + + } + } } diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 26e9c6d..8a5bb50 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -7,6 +7,7 @@ import ( "io" "time" + "github.com/go-faster/errors" "github.com/go-faster/jx" ) @@ -192,6 +193,212 @@ func (s *AuditEventEventData) init() AuditEventEventData { return m } +type BatchAssetThumbnailsOK struct { + // Map of asset ID to thumbnail URL. + Thumbnails OptBatchAssetThumbnailsOKThumbnails `json:"thumbnails"` +} + +// GetThumbnails returns the value of Thumbnails. +func (s *BatchAssetThumbnailsOK) GetThumbnails() OptBatchAssetThumbnailsOKThumbnails { + return s.Thumbnails +} + +// SetThumbnails sets the value of Thumbnails. +func (s *BatchAssetThumbnailsOK) SetThumbnails(val OptBatchAssetThumbnailsOKThumbnails) { + s.Thumbnails = val +} + +// Map of asset ID to thumbnail URL. +type BatchAssetThumbnailsOKThumbnails map[string]string + +func (s *BatchAssetThumbnailsOKThumbnails) init() BatchAssetThumbnailsOKThumbnails { + m := *s + if m == nil { + m = map[string]string{} + *s = m + } + return m +} + +type BatchAssetThumbnailsReq struct { + // Array of asset IDs (max 100). + AssetIds []uint64 `json:"assetIds"` + // Thumbnail size. + Size OptBatchAssetThumbnailsReqSize `json:"size"` +} + +// GetAssetIds returns the value of AssetIds. +func (s *BatchAssetThumbnailsReq) GetAssetIds() []uint64 { + return s.AssetIds +} + +// GetSize returns the value of Size. +func (s *BatchAssetThumbnailsReq) GetSize() OptBatchAssetThumbnailsReqSize { + return s.Size +} + +// SetAssetIds sets the value of AssetIds. +func (s *BatchAssetThumbnailsReq) SetAssetIds(val []uint64) { + s.AssetIds = val +} + +// SetSize sets the value of Size. +func (s *BatchAssetThumbnailsReq) SetSize(val OptBatchAssetThumbnailsReqSize) { + s.Size = val +} + +// Thumbnail size. +type BatchAssetThumbnailsReqSize string + +const ( + BatchAssetThumbnailsReqSize150x150 BatchAssetThumbnailsReqSize = "150x150" + BatchAssetThumbnailsReqSize420x420 BatchAssetThumbnailsReqSize = "420x420" + BatchAssetThumbnailsReqSize768x432 BatchAssetThumbnailsReqSize = "768x432" +) + +// AllValues returns all BatchAssetThumbnailsReqSize values. +func (BatchAssetThumbnailsReqSize) AllValues() []BatchAssetThumbnailsReqSize { + return []BatchAssetThumbnailsReqSize{ + BatchAssetThumbnailsReqSize150x150, + BatchAssetThumbnailsReqSize420x420, + BatchAssetThumbnailsReqSize768x432, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s BatchAssetThumbnailsReqSize) MarshalText() ([]byte, error) { + switch s { + case BatchAssetThumbnailsReqSize150x150: + return []byte(s), nil + case BatchAssetThumbnailsReqSize420x420: + return []byte(s), nil + case BatchAssetThumbnailsReqSize768x432: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *BatchAssetThumbnailsReqSize) UnmarshalText(data []byte) error { + switch BatchAssetThumbnailsReqSize(data) { + case BatchAssetThumbnailsReqSize150x150: + *s = BatchAssetThumbnailsReqSize150x150 + return nil + case BatchAssetThumbnailsReqSize420x420: + *s = BatchAssetThumbnailsReqSize420x420 + return nil + case BatchAssetThumbnailsReqSize768x432: + *s = BatchAssetThumbnailsReqSize768x432 + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +type BatchUserThumbnailsOK struct { + // Map of user ID to thumbnail URL. + Thumbnails OptBatchUserThumbnailsOKThumbnails `json:"thumbnails"` +} + +// GetThumbnails returns the value of Thumbnails. +func (s *BatchUserThumbnailsOK) GetThumbnails() OptBatchUserThumbnailsOKThumbnails { + return s.Thumbnails +} + +// SetThumbnails sets the value of Thumbnails. +func (s *BatchUserThumbnailsOK) SetThumbnails(val OptBatchUserThumbnailsOKThumbnails) { + s.Thumbnails = val +} + +// Map of user ID to thumbnail URL. +type BatchUserThumbnailsOKThumbnails map[string]string + +func (s *BatchUserThumbnailsOKThumbnails) init() BatchUserThumbnailsOKThumbnails { + m := *s + if m == nil { + m = map[string]string{} + *s = m + } + return m +} + +type BatchUserThumbnailsReq struct { + // Array of user IDs (max 100). + UserIds []uint64 `json:"userIds"` + // Thumbnail size. + Size OptBatchUserThumbnailsReqSize `json:"size"` +} + +// GetUserIds returns the value of UserIds. +func (s *BatchUserThumbnailsReq) GetUserIds() []uint64 { + return s.UserIds +} + +// GetSize returns the value of Size. +func (s *BatchUserThumbnailsReq) GetSize() OptBatchUserThumbnailsReqSize { + return s.Size +} + +// SetUserIds sets the value of UserIds. +func (s *BatchUserThumbnailsReq) SetUserIds(val []uint64) { + s.UserIds = val +} + +// SetSize sets the value of Size. +func (s *BatchUserThumbnailsReq) SetSize(val OptBatchUserThumbnailsReqSize) { + s.Size = val +} + +// Thumbnail size. +type BatchUserThumbnailsReqSize string + +const ( + BatchUserThumbnailsReqSize150x150 BatchUserThumbnailsReqSize = "150x150" + BatchUserThumbnailsReqSize420x420 BatchUserThumbnailsReqSize = "420x420" + BatchUserThumbnailsReqSize768x432 BatchUserThumbnailsReqSize = "768x432" +) + +// AllValues returns all BatchUserThumbnailsReqSize values. +func (BatchUserThumbnailsReqSize) AllValues() []BatchUserThumbnailsReqSize { + return []BatchUserThumbnailsReqSize{ + BatchUserThumbnailsReqSize150x150, + BatchUserThumbnailsReqSize420x420, + BatchUserThumbnailsReqSize768x432, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s BatchUserThumbnailsReqSize) MarshalText() ([]byte, error) { + switch s { + case BatchUserThumbnailsReqSize150x150: + return []byte(s), nil + case BatchUserThumbnailsReqSize420x420: + return []byte(s), nil + case BatchUserThumbnailsReqSize768x432: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *BatchUserThumbnailsReqSize) UnmarshalText(data []byte) error { + switch BatchUserThumbnailsReqSize(data) { + case BatchUserThumbnailsReqSize150x150: + *s = BatchUserThumbnailsReqSize150x150 + return nil + case BatchUserThumbnailsReqSize420x420: + *s = BatchUserThumbnailsReqSize420x420 + return nil + case BatchUserThumbnailsReqSize768x432: + *s = BatchUserThumbnailsReqSize768x432 + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + type CookieAuth struct { APIKey string Roles []string @@ -324,6 +531,132 @@ func (s *ErrorStatusCode) SetResponse(val Error) { s.Response = val } +// GetAssetThumbnailFound is response for GetAssetThumbnail operation. +type GetAssetThumbnailFound struct { + Location OptString +} + +// GetLocation returns the value of Location. +func (s *GetAssetThumbnailFound) GetLocation() OptString { + return s.Location +} + +// SetLocation sets the value of Location. +func (s *GetAssetThumbnailFound) SetLocation(val OptString) { + s.Location = val +} + +type GetAssetThumbnailSize string + +const ( + GetAssetThumbnailSize150x150 GetAssetThumbnailSize = "150x150" + GetAssetThumbnailSize420x420 GetAssetThumbnailSize = "420x420" + GetAssetThumbnailSize768x432 GetAssetThumbnailSize = "768x432" +) + +// AllValues returns all GetAssetThumbnailSize values. +func (GetAssetThumbnailSize) AllValues() []GetAssetThumbnailSize { + return []GetAssetThumbnailSize{ + GetAssetThumbnailSize150x150, + GetAssetThumbnailSize420x420, + GetAssetThumbnailSize768x432, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s GetAssetThumbnailSize) MarshalText() ([]byte, error) { + switch s { + case GetAssetThumbnailSize150x150: + return []byte(s), nil + case GetAssetThumbnailSize420x420: + return []byte(s), nil + case GetAssetThumbnailSize768x432: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *GetAssetThumbnailSize) UnmarshalText(data []byte) error { + switch GetAssetThumbnailSize(data) { + case GetAssetThumbnailSize150x150: + *s = GetAssetThumbnailSize150x150 + return nil + case GetAssetThumbnailSize420x420: + *s = GetAssetThumbnailSize420x420 + return nil + case GetAssetThumbnailSize768x432: + *s = GetAssetThumbnailSize768x432 + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +// GetUserThumbnailFound is response for GetUserThumbnail operation. +type GetUserThumbnailFound struct { + Location OptString +} + +// GetLocation returns the value of Location. +func (s *GetUserThumbnailFound) GetLocation() OptString { + return s.Location +} + +// SetLocation sets the value of Location. +func (s *GetUserThumbnailFound) SetLocation(val OptString) { + s.Location = val +} + +type GetUserThumbnailSize string + +const ( + GetUserThumbnailSize150x150 GetUserThumbnailSize = "150x150" + GetUserThumbnailSize420x420 GetUserThumbnailSize = "420x420" + GetUserThumbnailSize768x432 GetUserThumbnailSize = "768x432" +) + +// AllValues returns all GetUserThumbnailSize values. +func (GetUserThumbnailSize) AllValues() []GetUserThumbnailSize { + return []GetUserThumbnailSize{ + GetUserThumbnailSize150x150, + GetUserThumbnailSize420x420, + GetUserThumbnailSize768x432, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s GetUserThumbnailSize) MarshalText() ([]byte, error) { + switch s { + case GetUserThumbnailSize150x150: + return []byte(s), nil + case GetUserThumbnailSize420x420: + return []byte(s), nil + case GetUserThumbnailSize768x432: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *GetUserThumbnailSize) UnmarshalText(data []byte) error { + switch GetUserThumbnailSize(data) { + case GetUserThumbnailSize150x150: + *s = GetUserThumbnailSize150x150 + return nil + case GetUserThumbnailSize420x420: + *s = GetUserThumbnailSize420x420 + return nil + case GetUserThumbnailSize768x432: + *s = GetUserThumbnailSize768x432 + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + // Ref: #/components/schemas/Map type Map struct { ID int64 `json:"ID"` @@ -777,6 +1110,282 @@ func (s *OperationID) SetOperationID(val int32) { s.OperationID = val } +// NewOptBatchAssetThumbnailsOKThumbnails returns new OptBatchAssetThumbnailsOKThumbnails with value set to v. +func NewOptBatchAssetThumbnailsOKThumbnails(v BatchAssetThumbnailsOKThumbnails) OptBatchAssetThumbnailsOKThumbnails { + return OptBatchAssetThumbnailsOKThumbnails{ + Value: v, + Set: true, + } +} + +// OptBatchAssetThumbnailsOKThumbnails is optional BatchAssetThumbnailsOKThumbnails. +type OptBatchAssetThumbnailsOKThumbnails struct { + Value BatchAssetThumbnailsOKThumbnails + Set bool +} + +// IsSet returns true if OptBatchAssetThumbnailsOKThumbnails was set. +func (o OptBatchAssetThumbnailsOKThumbnails) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBatchAssetThumbnailsOKThumbnails) Reset() { + var v BatchAssetThumbnailsOKThumbnails + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBatchAssetThumbnailsOKThumbnails) SetTo(v BatchAssetThumbnailsOKThumbnails) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBatchAssetThumbnailsOKThumbnails) Get() (v BatchAssetThumbnailsOKThumbnails, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBatchAssetThumbnailsOKThumbnails) Or(d BatchAssetThumbnailsOKThumbnails) BatchAssetThumbnailsOKThumbnails { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptBatchAssetThumbnailsReqSize returns new OptBatchAssetThumbnailsReqSize with value set to v. +func NewOptBatchAssetThumbnailsReqSize(v BatchAssetThumbnailsReqSize) OptBatchAssetThumbnailsReqSize { + return OptBatchAssetThumbnailsReqSize{ + Value: v, + Set: true, + } +} + +// OptBatchAssetThumbnailsReqSize is optional BatchAssetThumbnailsReqSize. +type OptBatchAssetThumbnailsReqSize struct { + Value BatchAssetThumbnailsReqSize + Set bool +} + +// IsSet returns true if OptBatchAssetThumbnailsReqSize was set. +func (o OptBatchAssetThumbnailsReqSize) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBatchAssetThumbnailsReqSize) Reset() { + var v BatchAssetThumbnailsReqSize + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBatchAssetThumbnailsReqSize) SetTo(v BatchAssetThumbnailsReqSize) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBatchAssetThumbnailsReqSize) Get() (v BatchAssetThumbnailsReqSize, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBatchAssetThumbnailsReqSize) Or(d BatchAssetThumbnailsReqSize) BatchAssetThumbnailsReqSize { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptBatchUserThumbnailsOKThumbnails returns new OptBatchUserThumbnailsOKThumbnails with value set to v. +func NewOptBatchUserThumbnailsOKThumbnails(v BatchUserThumbnailsOKThumbnails) OptBatchUserThumbnailsOKThumbnails { + return OptBatchUserThumbnailsOKThumbnails{ + Value: v, + Set: true, + } +} + +// OptBatchUserThumbnailsOKThumbnails is optional BatchUserThumbnailsOKThumbnails. +type OptBatchUserThumbnailsOKThumbnails struct { + Value BatchUserThumbnailsOKThumbnails + Set bool +} + +// IsSet returns true if OptBatchUserThumbnailsOKThumbnails was set. +func (o OptBatchUserThumbnailsOKThumbnails) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBatchUserThumbnailsOKThumbnails) Reset() { + var v BatchUserThumbnailsOKThumbnails + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBatchUserThumbnailsOKThumbnails) SetTo(v BatchUserThumbnailsOKThumbnails) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBatchUserThumbnailsOKThumbnails) Get() (v BatchUserThumbnailsOKThumbnails, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBatchUserThumbnailsOKThumbnails) Or(d BatchUserThumbnailsOKThumbnails) BatchUserThumbnailsOKThumbnails { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptBatchUserThumbnailsReqSize returns new OptBatchUserThumbnailsReqSize with value set to v. +func NewOptBatchUserThumbnailsReqSize(v BatchUserThumbnailsReqSize) OptBatchUserThumbnailsReqSize { + return OptBatchUserThumbnailsReqSize{ + Value: v, + Set: true, + } +} + +// OptBatchUserThumbnailsReqSize is optional BatchUserThumbnailsReqSize. +type OptBatchUserThumbnailsReqSize struct { + Value BatchUserThumbnailsReqSize + Set bool +} + +// IsSet returns true if OptBatchUserThumbnailsReqSize was set. +func (o OptBatchUserThumbnailsReqSize) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBatchUserThumbnailsReqSize) Reset() { + var v BatchUserThumbnailsReqSize + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBatchUserThumbnailsReqSize) SetTo(v BatchUserThumbnailsReqSize) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBatchUserThumbnailsReqSize) Get() (v BatchUserThumbnailsReqSize, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBatchUserThumbnailsReqSize) Or(d BatchUserThumbnailsReqSize) BatchUserThumbnailsReqSize { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptGetAssetThumbnailSize returns new OptGetAssetThumbnailSize with value set to v. +func NewOptGetAssetThumbnailSize(v GetAssetThumbnailSize) OptGetAssetThumbnailSize { + return OptGetAssetThumbnailSize{ + Value: v, + Set: true, + } +} + +// OptGetAssetThumbnailSize is optional GetAssetThumbnailSize. +type OptGetAssetThumbnailSize struct { + Value GetAssetThumbnailSize + Set bool +} + +// IsSet returns true if OptGetAssetThumbnailSize was set. +func (o OptGetAssetThumbnailSize) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptGetAssetThumbnailSize) Reset() { + var v GetAssetThumbnailSize + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptGetAssetThumbnailSize) SetTo(v GetAssetThumbnailSize) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptGetAssetThumbnailSize) Get() (v GetAssetThumbnailSize, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptGetAssetThumbnailSize) Or(d GetAssetThumbnailSize) GetAssetThumbnailSize { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptGetUserThumbnailSize returns new OptGetUserThumbnailSize with value set to v. +func NewOptGetUserThumbnailSize(v GetUserThumbnailSize) OptGetUserThumbnailSize { + return OptGetUserThumbnailSize{ + Value: v, + Set: true, + } +} + +// OptGetUserThumbnailSize is optional GetUserThumbnailSize. +type OptGetUserThumbnailSize struct { + Value GetUserThumbnailSize + Set bool +} + +// IsSet returns true if OptGetUserThumbnailSize was set. +func (o OptGetUserThumbnailSize) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptGetUserThumbnailSize) Reset() { + var v GetUserThumbnailSize + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptGetUserThumbnailSize) SetTo(v GetUserThumbnailSize) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptGetUserThumbnailSize) Get() (v GetUserThumbnailSize, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptGetUserThumbnailSize) Or(d GetUserThumbnailSize) GetUserThumbnailSize { + if v, ok := o.Get(); ok { + return v + } + return d +} + // NewOptInt32 returns new OptInt32 with value set to v. func NewOptInt32(v int32) OptInt32 { return OptInt32{ diff --git a/pkg/api/oas_security_gen.go b/pkg/api/oas_security_gen.go index ddc2925..86db301 100644 --- a/pkg/api/oas_security_gen.go +++ b/pkg/api/oas_security_gen.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/go-faster/errors" - "github.com/ogen-go/ogen/ogenerrors" ) diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index 88cc775..5e955fd 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -155,6 +155,18 @@ type Handler interface { // // POST /submissions/{SubmissionID}/status/reset-uploading ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error + // BatchAssetThumbnails implements batchAssetThumbnails operation. + // + // Batch fetch asset thumbnails. + // + // POST /thumbnails/assets + BatchAssetThumbnails(ctx context.Context, req *BatchAssetThumbnailsReq) (*BatchAssetThumbnailsOK, error) + // BatchUserThumbnails implements batchUserThumbnails operation. + // + // Batch fetch user avatar thumbnails. + // + // POST /thumbnails/users + BatchUserThumbnails(ctx context.Context, req *BatchUserThumbnailsReq) (*BatchUserThumbnailsOK, error) // CreateMapfix implements createMapfix operation. // // Trigger the validator to create a mapfix. @@ -215,6 +227,12 @@ type Handler interface { // // GET /maps/{MapID}/download DownloadMapAsset(ctx context.Context, params DownloadMapAssetParams) (DownloadMapAssetOK, error) + // GetAssetThumbnail implements getAssetThumbnail operation. + // + // Get single asset thumbnail. + // + // GET /thumbnails/asset/{AssetID} + GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (*GetAssetThumbnailFound, error) // GetMap implements getMap operation. // // Retrieve map with ID. @@ -251,6 +269,12 @@ type Handler interface { // // GET /submissions/{SubmissionID} GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error) + // GetUserThumbnail implements getUserThumbnail operation. + // + // Get single user avatar thumbnail. + // + // GET /thumbnails/user/{UserID} + GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (*GetUserThumbnailFound, error) // ListMapfixAuditEvents implements listMapfixAuditEvents operation. // // Retrieve a list of audit events. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index 5321159..d27f4a3 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -232,6 +232,24 @@ func (UnimplementedHandler) ActionSubmissionValidated(ctx context.Context, param return ht.ErrNotImplemented } +// BatchAssetThumbnails implements batchAssetThumbnails operation. +// +// Batch fetch asset thumbnails. +// +// POST /thumbnails/assets +func (UnimplementedHandler) BatchAssetThumbnails(ctx context.Context, req *BatchAssetThumbnailsReq) (r *BatchAssetThumbnailsOK, _ error) { + return r, ht.ErrNotImplemented +} + +// BatchUserThumbnails implements batchUserThumbnails operation. +// +// Batch fetch user avatar thumbnails. +// +// POST /thumbnails/users +func (UnimplementedHandler) BatchUserThumbnails(ctx context.Context, req *BatchUserThumbnailsReq) (r *BatchUserThumbnailsOK, _ error) { + return r, ht.ErrNotImplemented +} + // CreateMapfix implements createMapfix operation. // // Trigger the validator to create a mapfix. @@ -322,6 +340,15 @@ func (UnimplementedHandler) DownloadMapAsset(ctx context.Context, params Downloa return r, ht.ErrNotImplemented } +// GetAssetThumbnail implements getAssetThumbnail operation. +// +// Get single asset thumbnail. +// +// GET /thumbnails/asset/{AssetID} +func (UnimplementedHandler) GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (r *GetAssetThumbnailFound, _ error) { + return r, ht.ErrNotImplemented +} + // GetMap implements getMap operation. // // Retrieve map with ID. @@ -376,6 +403,15 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss return r, ht.ErrNotImplemented } +// GetUserThumbnail implements getUserThumbnail operation. +// +// Get single user avatar thumbnail. +// +// GET /thumbnails/user/{UserID} +func (UnimplementedHandler) GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (r *GetUserThumbnailFound, _ error) { + return r, ht.ErrNotImplemented +} + // ListMapfixAuditEvents implements listMapfixAuditEvents operation. // // Retrieve a list of audit events. diff --git a/pkg/api/oas_validators_gen.go b/pkg/api/oas_validators_gen.go index 6e768bc..8f40139 100644 --- a/pkg/api/oas_validators_gen.go +++ b/pkg/api/oas_validators_gen.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/go-faster/errors" - "github.com/ogen-go/ogen/validate" ) @@ -18,13 +17,17 @@ func (s *AuditEvent) Validate() error { var failures []validate.FieldError if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 64, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 64, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Username)); err != nil { return errors.Wrap(err, "string") } @@ -41,6 +44,130 @@ func (s *AuditEvent) Validate() error { return nil } +func (s *BatchAssetThumbnailsReq) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if s.AssetIds == nil { + return errors.New("nil is invalid value") + } + if err := (validate.Array{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 100, + MaxLengthSet: true, + }).ValidateLength(len(s.AssetIds)); err != nil { + return errors.Wrap(err, "array") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "assetIds", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Size.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "size", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s BatchAssetThumbnailsReqSize) Validate() error { + switch s { + case "150x150": + return nil + case "420x420": + return nil + case "768x432": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s *BatchUserThumbnailsReq) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if s.UserIds == nil { + return errors.New("nil is invalid value") + } + if err := (validate.Array{ + MinLength: 0, + MinLengthSet: false, + MaxLength: 100, + MaxLengthSet: true, + }).ValidateLength(len(s.UserIds)); err != nil { + return errors.Wrap(err, "array") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "userIds", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Size.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "size", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s BatchUserThumbnailsReqSize) Validate() error { + switch s { + case "150x150": + return nil + case "420x420": + return nil + case "768x432": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + func (s *Error) Validate() error { if s == nil { return validate.ErrNilPointer @@ -57,6 +184,7 @@ func (s *Error) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Code)); err != nil { return errors.Wrap(err, "int") } @@ -96,6 +224,32 @@ func (s *ErrorStatusCode) Validate() error { return nil } +func (s GetAssetThumbnailSize) Validate() error { + switch s { + case "150x150": + return nil + case "420x420": + return nil + case "768x432": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s GetUserThumbnailSize) Validate() error { + switch s { + case "150x150": + return nil + case "420x420": + return nil + case "768x432": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + func (s *Map) Validate() error { if s == nil { return validate.ErrNilPointer @@ -112,6 +266,7 @@ func (s *Map) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -124,13 +279,17 @@ func (s *Map) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.DisplayName)); err != nil { return errors.Wrap(err, "string") } @@ -143,13 +302,17 @@ func (s *Map) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Creator)); err != nil { return errors.Wrap(err, "string") } @@ -170,6 +333,7 @@ func (s *Map) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.GameID)); err != nil { return errors.Wrap(err, "int") } @@ -190,6 +354,7 @@ func (s *Map) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Date)); err != nil { return errors.Wrap(err, "int") } @@ -222,6 +387,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -234,13 +400,17 @@ func (s *Mapfix) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.DisplayName)); err != nil { return errors.Wrap(err, "string") } @@ -253,13 +423,17 @@ func (s *Mapfix) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Creator)); err != nil { return errors.Wrap(err, "string") } @@ -280,6 +454,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.GameID)); err != nil { return errors.Wrap(err, "int") } @@ -300,6 +475,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.CreatedAt)); err != nil { return errors.Wrap(err, "int") } @@ -320,6 +496,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.UpdatedAt)); err != nil { return errors.Wrap(err, "int") } @@ -340,6 +517,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Submitter)); err != nil { return errors.Wrap(err, "int") } @@ -360,6 +538,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetID)); err != nil { return errors.Wrap(err, "int") } @@ -380,6 +559,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetVersion)); err != nil { return errors.Wrap(err, "int") } @@ -402,6 +582,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -429,6 +610,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -454,6 +636,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.TargetAssetID)); err != nil { return errors.Wrap(err, "int") } @@ -474,6 +657,7 @@ func (s *Mapfix) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.StatusID)); err != nil { return errors.Wrap(err, "int") } @@ -486,13 +670,17 @@ func (s *Mapfix) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 256, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 256, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Description)); err != nil { return errors.Wrap(err, "string") } @@ -525,6 +713,7 @@ func (s *MapfixTriggerCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetID)); err != nil { return errors.Wrap(err, "int") } @@ -545,6 +734,7 @@ func (s *MapfixTriggerCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.TargetAssetID)); err != nil { return errors.Wrap(err, "int") } @@ -557,13 +747,17 @@ func (s *MapfixTriggerCreate) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 256, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 256, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Description)); err != nil { return errors.Wrap(err, "string") } @@ -596,6 +790,7 @@ func (s *Mapfixes) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Total)); err != nil { return errors.Wrap(err, "int") } @@ -656,6 +851,7 @@ func (s *Operation) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.OperationID)); err != nil { return errors.Wrap(err, "int") } @@ -676,6 +872,7 @@ func (s *Operation) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Date)); err != nil { return errors.Wrap(err, "int") } @@ -696,6 +893,7 @@ func (s *Operation) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Owner)); err != nil { return errors.Wrap(err, "int") } @@ -716,6 +914,7 @@ func (s *Operation) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Status)); err != nil { return errors.Wrap(err, "int") } @@ -728,13 +927,17 @@ func (s *Operation) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 256, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 256, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.StatusMessage)); err != nil { return errors.Wrap(err, "string") } @@ -747,13 +950,17 @@ func (s *Operation) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Path)); err != nil { return errors.Wrap(err, "string") } @@ -786,6 +993,7 @@ func (s *OperationID) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.OperationID)); err != nil { return errors.Wrap(err, "int") } @@ -818,6 +1026,7 @@ func (s *ReleaseInfo) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.SubmissionID)); err != nil { return errors.Wrap(err, "int") } @@ -850,6 +1059,7 @@ func (s *Roles) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Roles)); err != nil { return errors.Wrap(err, "int") } @@ -882,6 +1092,7 @@ func (s *Script) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -894,13 +1105,17 @@ func (s *Script) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Name)); err != nil { return errors.Wrap(err, "string") } @@ -913,13 +1128,17 @@ func (s *Script) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 16, - MinLengthSet: true, - MaxLength: 16, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 16, + MinLengthSet: true, + MaxLength: 16, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Hash)); err != nil { return errors.Wrap(err, "string") } @@ -932,13 +1151,17 @@ func (s *Script) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 1048576, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 1048576, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Source)); err != nil { return errors.Wrap(err, "string") } @@ -959,6 +1182,7 @@ func (s *Script) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ResourceType)); err != nil { return errors.Wrap(err, "int") } @@ -979,6 +1203,7 @@ func (s *Script) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ResourceID)); err != nil { return errors.Wrap(err, "int") } @@ -1003,13 +1228,17 @@ func (s *ScriptCreate) Validate() error { var failures []validate.FieldError if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 256, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 256, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Name)); err != nil { return errors.Wrap(err, "string") } @@ -1022,13 +1251,17 @@ func (s *ScriptCreate) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 1048576, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 1048576, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Source)); err != nil { return errors.Wrap(err, "string") } @@ -1049,6 +1282,7 @@ func (s *ScriptCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ResourceType)); err != nil { return errors.Wrap(err, "int") } @@ -1071,6 +1305,7 @@ func (s *ScriptCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1108,6 +1343,7 @@ func (s *ScriptID) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -1140,6 +1376,7 @@ func (s *ScriptPolicy) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -1152,13 +1389,17 @@ func (s *ScriptPolicy) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 16, - MinLengthSet: true, - MaxLength: 16, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 16, + MinLengthSet: true, + MaxLength: 16, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.FromScriptHash)); err != nil { return errors.Wrap(err, "string") } @@ -1179,6 +1420,7 @@ func (s *ScriptPolicy) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ToScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -1199,6 +1441,7 @@ func (s *ScriptPolicy) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Policy)); err != nil { return errors.Wrap(err, "int") } @@ -1231,6 +1474,7 @@ func (s *ScriptPolicyCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.FromScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -1251,6 +1495,7 @@ func (s *ScriptPolicyCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ToScriptID)); err != nil { return errors.Wrap(err, "int") } @@ -1271,6 +1516,7 @@ func (s *ScriptPolicyCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Policy)); err != nil { return errors.Wrap(err, "int") } @@ -1303,6 +1549,7 @@ func (s *ScriptPolicyID) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ScriptPolicyID)); err != nil { return errors.Wrap(err, "int") } @@ -1335,6 +1582,7 @@ func (s *ScriptPolicyUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -1357,6 +1605,7 @@ func (s *ScriptPolicyUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1384,6 +1633,7 @@ func (s *ScriptPolicyUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1411,6 +1661,7 @@ func (s *ScriptPolicyUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1448,6 +1699,7 @@ func (s *ScriptUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -1462,13 +1714,17 @@ func (s *ScriptUpdate) Validate() error { if value, ok := s.Name.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -1488,13 +1744,17 @@ func (s *ScriptUpdate) Validate() error { if value, ok := s.Source.Get(); ok { if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 1048576, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 1048576, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(value)); err != nil { return errors.Wrap(err, "string") } @@ -1522,6 +1782,7 @@ func (s *ScriptUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1549,6 +1810,7 @@ func (s *ScriptUpdate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1586,6 +1848,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.ID)); err != nil { return errors.Wrap(err, "int") } @@ -1598,13 +1861,17 @@ func (s *Submission) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.DisplayName)); err != nil { return errors.Wrap(err, "string") } @@ -1617,13 +1884,17 @@ func (s *Submission) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Creator)); err != nil { return errors.Wrap(err, "string") } @@ -1644,6 +1915,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.GameID)); err != nil { return errors.Wrap(err, "int") } @@ -1664,6 +1936,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.CreatedAt)); err != nil { return errors.Wrap(err, "int") } @@ -1684,6 +1957,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.UpdatedAt)); err != nil { return errors.Wrap(err, "int") } @@ -1704,6 +1978,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Submitter)); err != nil { return errors.Wrap(err, "int") } @@ -1724,6 +1999,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetID)); err != nil { return errors.Wrap(err, "int") } @@ -1744,6 +2020,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetVersion)); err != nil { return errors.Wrap(err, "int") } @@ -1766,6 +2043,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1793,6 +2071,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1820,6 +2099,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(value)); err != nil { return errors.Wrap(err, "int") } @@ -1845,6 +2125,7 @@ func (s *Submission) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.StatusID)); err != nil { return errors.Wrap(err, "int") } @@ -1877,6 +2158,7 @@ func (s *SubmissionTriggerCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.AssetID)); err != nil { return errors.Wrap(err, "int") } @@ -1889,13 +2171,17 @@ func (s *SubmissionTriggerCreate) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.DisplayName)); err != nil { return errors.Wrap(err, "string") } @@ -1908,13 +2194,17 @@ func (s *SubmissionTriggerCreate) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Creator)); err != nil { return errors.Wrap(err, "string") } @@ -1935,6 +2225,7 @@ func (s *SubmissionTriggerCreate) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.GameID)); err != nil { return errors.Wrap(err, "int") } @@ -1967,6 +2258,7 @@ func (s *Submissions) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.Total)); err != nil { return errors.Wrap(err, "int") } @@ -2027,6 +2319,7 @@ func (s *User) Validate() error { MaxExclusive: false, MultipleOfSet: false, MultipleOf: 0, + Pattern: nil, }).Validate(int64(s.UserID)); err != nil { return errors.Wrap(err, "int") } @@ -2039,13 +2332,17 @@ func (s *User) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 128, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 128, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.Username)); err != nil { return errors.Wrap(err, "string") } @@ -2058,13 +2355,17 @@ func (s *User) Validate() error { } if err := func() error { if err := (validate.String{ - MinLength: 0, - MinLengthSet: false, - MaxLength: 256, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, + MinLength: 0, + MinLengthSet: false, + MaxLength: 256, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + MinNumeric: 0, + MinNumericSet: false, + MaxNumeric: 0, + MaxNumericSet: false, }).Validate(string(s.AvatarURL)); err != nil { return errors.Wrap(err, "string") } diff --git a/pkg/cmds/serve.go b/pkg/cmds/serve.go index c01b503..24b151e 100644 --- a/pkg/cmds/serve.go +++ b/pkg/cmds/serve.go @@ -18,6 +18,7 @@ import ( "git.itzana.me/strafesnet/maps-service/pkg/validator_controller" "git.itzana.me/strafesnet/maps-service/pkg/web_api" "github.com/nats-io/nats.go" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" "google.golang.org/grpc" @@ -102,6 +103,24 @@ func NewServeCommand() *cli.Command { EnvVars: []string{"RBX_API_KEY"}, Required: true, }, + &cli.StringFlag{ + Name: "redis-host", + Usage: "Host of Redis cache", + EnvVars: []string{"REDIS_HOST"}, + Value: "localhost:6379", + }, + &cli.StringFlag{ + Name: "redis-password", + Usage: "Password for Redis", + EnvVars: []string{"REDIS_PASSWORD"}, + Value: "", + }, + &cli.IntFlag{ + Name: "redis-db", + Usage: "Redis database number", + EnvVars: []string{"REDIS_DB"}, + Value: 0, + }, }, } } @@ -129,6 +148,24 @@ func serve(ctx *cli.Context) error { log.WithError(err).Fatal("failed to add stream") } + // Initialize Redis client + redisClient := redis.NewClient(&redis.Options{ + Addr: ctx.String("redis-host"), + Password: ctx.String("redis-password"), + DB: ctx.Int("redis-db"), + }) + + // Test Redis connection + if err := redisClient.Ping(ctx.Context).Err(); err != nil { + log.WithError(err).Warn("failed to connect to Redis - thumbnails will not be cached") + } + + // Initialize Roblox client + robloxClient := &roblox.Client{ + HttpClient: http.DefaultClient, + ApiKey: ctx.String("rbx-api-key"), + } + // connect to main game database conn, err := grpc.Dial(ctx.String("data-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { @@ -139,13 +176,15 @@ func serve(ctx *cli.Context) error { js, maps.NewMapsServiceClient(conn), users.NewUsersServiceClient(conn), + robloxClient, + redisClient, ) svc_external := web_api.NewService( &svc_inner, roblox.Client{ HttpClient: http.DefaultClient, - ApiKey: ctx.String("rbx-api-key"), + ApiKey: ctx.String("rbx-api-key"), }, ) diff --git a/pkg/roblox/thumbnails.go b/pkg/roblox/thumbnails.go new file mode 100644 index 0000000..2d5e6be --- /dev/null +++ b/pkg/roblox/thumbnails.go @@ -0,0 +1,160 @@ +package roblox + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" +) + +// ThumbnailSize represents valid Roblox thumbnail sizes +type ThumbnailSize string + +const ( + Size150x150 ThumbnailSize = "150x150" + Size420x420 ThumbnailSize = "420x420" + Size768x432 ThumbnailSize = "768x432" +) + +// ThumbnailFormat represents the image format +type ThumbnailFormat string + +const ( + FormatPng ThumbnailFormat = "Png" + FormatJpeg ThumbnailFormat = "Jpeg" +) + +// ThumbnailRequest represents a single thumbnail request +type ThumbnailRequest struct { + RequestID string `json:"requestId,omitempty"` + Type string `json:"type"` + TargetID uint64 `json:"targetId"` + Size string `json:"size,omitempty"` + Format string `json:"format,omitempty"` +} + +// ThumbnailData represents a single thumbnail response +type ThumbnailData struct { + TargetID uint64 `json:"targetId"` + State string `json:"state"` // "Completed", "Error", "Pending" + ImageURL string `json:"imageUrl"` +} + +// BatchThumbnailsResponse represents the API response +type BatchThumbnailsResponse struct { + Data []ThumbnailData `json:"data"` +} + +// GetAssetThumbnails fetches thumbnails for multiple assets in a single batch request +// Roblox allows up to 100 assets per batch +func (c *Client) GetAssetThumbnails(assetIDs []uint64, size ThumbnailSize, format ThumbnailFormat) ([]ThumbnailData, error) { + if len(assetIDs) == 0 { + return []ThumbnailData{}, nil + } + if len(assetIDs) > 100 { + return nil, GetError("batch size cannot exceed 100 assets") + } + + // Build request payload - the API expects an array directly, not wrapped in an object + requests := make([]ThumbnailRequest, len(assetIDs)) + for i, assetID := range assetIDs { + requests[i] = ThumbnailRequest{ + Type: "Asset", + TargetID: assetID, + Size: string(size), + Format: string(format), + } + } + + jsonData, err := json.Marshal(requests) + if err != nil { + return nil, GetError("JSONMarshalError: " + err.Error()) + } + + req, err := http.NewRequest("POST", "https://thumbnails.roblox.com/v1/batch", bytes.NewBuffer(jsonData)) + if err != nil { + return nil, GetError("RequestCreationError: " + err.Error()) + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := c.HttpClient.Do(req) + if err != nil { + return nil, GetError("RequestError: " + err.Error()) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, GetError(fmt.Sprintf("ResponseError: status code %d, body: %s", resp.StatusCode, string(body))) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, GetError("ReadBodyError: " + err.Error()) + } + + var response BatchThumbnailsResponse + if err := json.Unmarshal(body, &response); err != nil { + return nil, GetError("JSONUnmarshalError: " + err.Error()) + } + + return response.Data, nil +} + +// GetUserAvatarThumbnails fetches avatar thumbnails for multiple users in a single batch request +func (c *Client) GetUserAvatarThumbnails(userIDs []uint64, size ThumbnailSize, format ThumbnailFormat) ([]ThumbnailData, error) { + if len(userIDs) == 0 { + return []ThumbnailData{}, nil + } + if len(userIDs) > 100 { + return nil, GetError("batch size cannot exceed 100 users") + } + + // Build request payload - the API expects an array directly, not wrapped in an object + requests := make([]ThumbnailRequest, len(userIDs)) + for i, userID := range userIDs { + requests[i] = ThumbnailRequest{ + Type: "AvatarHeadShot", + TargetID: userID, + Size: string(size), + Format: string(format), + } + } + + jsonData, err := json.Marshal(requests) + if err != nil { + return nil, GetError("JSONMarshalError: " + err.Error()) + } + + req, err := http.NewRequest("POST", "https://thumbnails.roblox.com/v1/batch", bytes.NewBuffer(jsonData)) + if err != nil { + return nil, GetError("RequestCreationError: " + err.Error()) + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := c.HttpClient.Do(req) + if err != nil { + return nil, GetError("RequestError: " + err.Error()) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return nil, GetError(fmt.Sprintf("ResponseError: status code %d, body: %s", resp.StatusCode, string(body))) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, GetError("ReadBodyError: " + err.Error()) + } + + var response BatchThumbnailsResponse + if err := json.Unmarshal(body, &response); err != nil { + return nil, GetError("JSONUnmarshalError: " + err.Error()) + } + + return response.Data, nil +} diff --git a/pkg/service/service.go b/pkg/service/service.go index 31198a5..4395fc9 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -1,17 +1,22 @@ package service import ( + "context" + "git.itzana.me/strafesnet/go-grpc/maps" "git.itzana.me/strafesnet/go-grpc/users" "git.itzana.me/strafesnet/maps-service/pkg/datastore" + "git.itzana.me/strafesnet/maps-service/pkg/roblox" "github.com/nats-io/nats.go" + "github.com/redis/go-redis/v9" ) type Service struct { - db datastore.Datastore - nats nats.JetStreamContext - maps maps.MapsServiceClient - users users.UsersServiceClient + db datastore.Datastore + nats nats.JetStreamContext + maps maps.MapsServiceClient + users users.UsersServiceClient + thumbnailService *ThumbnailService } func NewService( @@ -19,11 +24,34 @@ func NewService( nats nats.JetStreamContext, maps maps.MapsServiceClient, users users.UsersServiceClient, + robloxClient *roblox.Client, + redisClient *redis.Client, ) Service { return Service{ - db: db, - nats: nats, - maps: maps, - users: users, + db: db, + nats: nats, + maps: maps, + users: users, + thumbnailService: NewThumbnailService(robloxClient, redisClient), } } + +// GetAssetThumbnails proxies to the thumbnail service +func (s *Service) GetAssetThumbnails(ctx context.Context, assetIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) { + return s.thumbnailService.GetAssetThumbnails(ctx, assetIDs, size) +} + +// GetUserAvatarThumbnails proxies to the thumbnail service +func (s *Service) GetUserAvatarThumbnails(ctx context.Context, userIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) { + return s.thumbnailService.GetUserAvatarThumbnails(ctx, userIDs, size) +} + +// GetSingleAssetThumbnail proxies to the thumbnail service +func (s *Service) GetSingleAssetThumbnail(ctx context.Context, assetID uint64, size roblox.ThumbnailSize) (string, error) { + return s.thumbnailService.GetSingleAssetThumbnail(ctx, assetID, size) +} + +// GetSingleUserAvatarThumbnail proxies to the thumbnail service +func (s *Service) GetSingleUserAvatarThumbnail(ctx context.Context, userID uint64, size roblox.ThumbnailSize) (string, error) { + return s.thumbnailService.GetSingleUserAvatarThumbnail(ctx, userID, size) +} diff --git a/pkg/service/thumbnails.go b/pkg/service/thumbnails.go new file mode 100644 index 0000000..bb90d43 --- /dev/null +++ b/pkg/service/thumbnails.go @@ -0,0 +1,218 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "git.itzana.me/strafesnet/maps-service/pkg/roblox" + "github.com/redis/go-redis/v9" +) + +type ThumbnailService struct { + robloxClient *roblox.Client + redisClient *redis.Client + cacheTTL time.Duration +} + +func NewThumbnailService(robloxClient *roblox.Client, redisClient *redis.Client) *ThumbnailService { + return &ThumbnailService{ + robloxClient: robloxClient, + redisClient: redisClient, + cacheTTL: 24 * time.Hour, // Cache thumbnails for 24 hours + } +} + +// CachedThumbnail represents a cached thumbnail entry +type CachedThumbnail struct { + ImageURL string `json:"imageUrl"` + State string `json:"state"` + CachedAt time.Time `json:"cachedAt"` +} + +// GetAssetThumbnails fetches thumbnails with Redis caching and batching +func (s *ThumbnailService) GetAssetThumbnails(ctx context.Context, assetIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) { + if len(assetIDs) == 0 { + return map[uint64]string{}, nil + } + + result := make(map[uint64]string) + var missingIDs []uint64 + + // Try to get from cache first + for _, assetID := range assetIDs { + cacheKey := fmt.Sprintf("thumbnail:asset:%d:%s", assetID, size) + cached, err := s.redisClient.Get(ctx, cacheKey).Result() + + if err == redis.Nil { + // Cache miss + missingIDs = append(missingIDs, assetID) + } else if err != nil { + // Redis error - treat as cache miss + missingIDs = append(missingIDs, assetID) + } else { + // Cache hit + var thumbnail CachedThumbnail + if err := json.Unmarshal([]byte(cached), &thumbnail); err == nil && thumbnail.State == "Completed" { + result[assetID] = thumbnail.ImageURL + } else { + missingIDs = append(missingIDs, assetID) + } + } + } + + // If all were cached, return early + if len(missingIDs) == 0 { + return result, nil + } + + // Batch fetch missing thumbnails from Roblox API + // Split into batches of 100 (Roblox API limit) + for i := 0; i < len(missingIDs); i += 100 { + end := i + 100 + if end > len(missingIDs) { + end = len(missingIDs) + } + batch := missingIDs[i:end] + + thumbnails, err := s.robloxClient.GetAssetThumbnails(batch, size, roblox.FormatPng) + if err != nil { + return nil, fmt.Errorf("failed to fetch thumbnails: %w", err) + } + + // Process results and cache them + for _, thumb := range thumbnails { + cached := CachedThumbnail{ + ImageURL: thumb.ImageURL, + State: thumb.State, + CachedAt: time.Now(), + } + + if thumb.State == "Completed" && thumb.ImageURL != "" { + result[thumb.TargetID] = thumb.ImageURL + } + + // Cache the result (even if incomplete, to avoid repeated API calls) + cacheKey := fmt.Sprintf("thumbnail:asset:%d:%s", thumb.TargetID, size) + cachedJSON, _ := json.Marshal(cached) + + // Use shorter TTL for incomplete thumbnails + ttl := s.cacheTTL + if thumb.State != "Completed" { + ttl = 5 * time.Minute + } + + s.redisClient.Set(ctx, cacheKey, cachedJSON, ttl) + } + } + + return result, nil +} + +// GetUserAvatarThumbnails fetches user avatar thumbnails with Redis caching and batching +func (s *ThumbnailService) GetUserAvatarThumbnails(ctx context.Context, userIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) { + if len(userIDs) == 0 { + return map[uint64]string{}, nil + } + + result := make(map[uint64]string) + var missingIDs []uint64 + + // Try to get from cache first + for _, userID := range userIDs { + cacheKey := fmt.Sprintf("thumbnail:user:%d:%s", userID, size) + cached, err := s.redisClient.Get(ctx, cacheKey).Result() + + if err == redis.Nil { + // Cache miss + missingIDs = append(missingIDs, userID) + } else if err != nil { + // Redis error - treat as cache miss + missingIDs = append(missingIDs, userID) + } else { + // Cache hit + var thumbnail CachedThumbnail + if err := json.Unmarshal([]byte(cached), &thumbnail); err == nil && thumbnail.State == "Completed" { + result[userID] = thumbnail.ImageURL + } else { + missingIDs = append(missingIDs, userID) + } + } + } + + // If all were cached, return early + if len(missingIDs) == 0 { + return result, nil + } + + // Batch fetch missing thumbnails from Roblox API + // Split into batches of 100 (Roblox API limit) + for i := 0; i < len(missingIDs); i += 100 { + end := i + 100 + if end > len(missingIDs) { + end = len(missingIDs) + } + batch := missingIDs[i:end] + + thumbnails, err := s.robloxClient.GetUserAvatarThumbnails(batch, size, roblox.FormatPng) + if err != nil { + return nil, fmt.Errorf("failed to fetch user thumbnails: %w", err) + } + + // Process results and cache them + for _, thumb := range thumbnails { + cached := CachedThumbnail{ + ImageURL: thumb.ImageURL, + State: thumb.State, + CachedAt: time.Now(), + } + + if thumb.State == "Completed" && thumb.ImageURL != "" { + result[thumb.TargetID] = thumb.ImageURL + } + + // Cache the result + cacheKey := fmt.Sprintf("thumbnail:user:%d:%s", thumb.TargetID, size) + cachedJSON, _ := json.Marshal(cached) + + // Use shorter TTL for incomplete thumbnails + ttl := s.cacheTTL + if thumb.State != "Completed" { + ttl = 5 * time.Minute + } + + s.redisClient.Set(ctx, cacheKey, cachedJSON, ttl) + } + } + + return result, nil +} + +// GetSingleAssetThumbnail is a convenience method for fetching a single asset thumbnail +func (s *ThumbnailService) GetSingleAssetThumbnail(ctx context.Context, assetID uint64, size roblox.ThumbnailSize) (string, error) { + results, err := s.GetAssetThumbnails(ctx, []uint64{assetID}, size) + if err != nil { + return "", err + } + + if url, ok := results[assetID]; ok { + return url, nil + } + + return "", fmt.Errorf("thumbnail not available for asset %d", assetID) +} + +// GetSingleUserAvatarThumbnail is a convenience method for fetching a single user avatar thumbnail +func (s *ThumbnailService) GetSingleUserAvatarThumbnail(ctx context.Context, userID uint64, size roblox.ThumbnailSize) (string, error) { + results, err := s.GetUserAvatarThumbnails(ctx, []uint64{userID}, size) + if err != nil { + return "", err + } + + if url, ok := results[userID]; ok { + return url, nil + } + + return "", fmt.Errorf("thumbnail not available for user %d", userID) +} diff --git a/pkg/web_api/thumbnails.go b/pkg/web_api/thumbnails.go new file mode 100644 index 0000000..a8c54f5 --- /dev/null +++ b/pkg/web_api/thumbnails.go @@ -0,0 +1,135 @@ +package web_api + +import ( + "context" + "strconv" + + "git.itzana.me/strafesnet/maps-service/pkg/api" + "git.itzana.me/strafesnet/maps-service/pkg/roblox" +) + +// BatchAssetThumbnails handles batch fetching of asset thumbnails +func (svc *Service) BatchAssetThumbnails(ctx context.Context, req *api.BatchAssetThumbnailsReq) (*api.BatchAssetThumbnailsOK, error) { + if len(req.AssetIds) == 0 { + return &api.BatchAssetThumbnailsOK{ + Thumbnails: api.NewOptBatchAssetThumbnailsOKThumbnails(map[string]string{}), + }, nil + } + + // Convert size string to enum + size := roblox.Size420x420 + if req.Size.IsSet() { + sizeStr := req.Size.Value + switch api.BatchAssetThumbnailsReqSize(sizeStr) { + case api.BatchAssetThumbnailsReqSize150x150: + size = roblox.Size150x150 + case api.BatchAssetThumbnailsReqSize768x432: + size = roblox.Size768x432 + } + } + + // Fetch thumbnails from service + thumbnails, err := svc.inner.GetAssetThumbnails(ctx, req.AssetIds, size) + if err != nil { + return nil, err + } + + // Convert map[uint64]string to map[string]string for JSON + result := make(map[string]string, len(thumbnails)) + for assetID, url := range thumbnails { + result[strconv.FormatUint(assetID, 10)] = url + } + + return &api.BatchAssetThumbnailsOK{ + Thumbnails: api.NewOptBatchAssetThumbnailsOKThumbnails(result), + }, nil +} + +// GetAssetThumbnail handles single asset thumbnail fetch (with redirect) +func (svc *Service) GetAssetThumbnail(ctx context.Context, params api.GetAssetThumbnailParams) (*api.GetAssetThumbnailFound, error) { + // Convert size string to enum + size := roblox.Size420x420 + if params.Size.IsSet() { + sizeStr := params.Size.Value + switch api.GetAssetThumbnailSize(sizeStr) { + case api.GetAssetThumbnailSize150x150: + size = roblox.Size150x150 + case api.GetAssetThumbnailSize768x432: + size = roblox.Size768x432 + } + } + + // Fetch thumbnail + thumbnailURL, err := svc.inner.GetSingleAssetThumbnail(ctx, params.AssetID, size) + if err != nil { + return nil, err + } + + // Return redirect response + return &api.GetAssetThumbnailFound{ + Location: api.NewOptString(thumbnailURL), + }, nil +} + +// BatchUserThumbnails handles batch fetching of user avatar thumbnails +func (svc *Service) BatchUserThumbnails(ctx context.Context, req *api.BatchUserThumbnailsReq) (*api.BatchUserThumbnailsOK, error) { + if len(req.UserIds) == 0 { + return &api.BatchUserThumbnailsOK{ + Thumbnails: api.NewOptBatchUserThumbnailsOKThumbnails(map[string]string{}), + }, nil + } + + // Convert size string to enum + size := roblox.Size150x150 + if req.Size.IsSet() { + sizeStr := req.Size.Value + switch api.BatchUserThumbnailsReqSize(sizeStr) { + case api.BatchUserThumbnailsReqSize420x420: + size = roblox.Size420x420 + case api.BatchUserThumbnailsReqSize768x432: + size = roblox.Size768x432 + } + } + + // Fetch thumbnails from service + thumbnails, err := svc.inner.GetUserAvatarThumbnails(ctx, req.UserIds, size) + if err != nil { + return nil, err + } + + // Convert map[uint64]string to map[string]string for JSON + result := make(map[string]string, len(thumbnails)) + for userID, url := range thumbnails { + result[strconv.FormatUint(userID, 10)] = url + } + + return &api.BatchUserThumbnailsOK{ + Thumbnails: api.NewOptBatchUserThumbnailsOKThumbnails(result), + }, nil +} + +// GetUserThumbnail handles single user avatar thumbnail fetch (with redirect) +func (svc *Service) GetUserThumbnail(ctx context.Context, params api.GetUserThumbnailParams) (*api.GetUserThumbnailFound, error) { + // Convert size string to enum + size := roblox.Size150x150 + if params.Size.IsSet() { + sizeStr := params.Size.Value + switch api.GetUserThumbnailSize(sizeStr) { + case api.GetUserThumbnailSize420x420: + size = roblox.Size420x420 + case api.GetUserThumbnailSize768x432: + size = roblox.Size768x432 + } + } + + // Fetch thumbnail + thumbnailURL, err := svc.inner.GetSingleUserAvatarThumbnail(ctx, params.UserID, size) + if err != nil { + return nil, err + } + + // Return redirect response + return &api.GetUserThumbnailFound{ + Location: api.NewOptString(thumbnailURL), + }, nil +} -- 2.49.1 From 7d1c4d2b6c28cd79473328cef9982181ebccf862 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 18:58:07 -0500 Subject: [PATCH 06/23] Add stats endpoint --- openapi.yaml | 63 ++++++++++ pkg/api/oas_client_gen.go | 79 ++++++++++++ pkg/api/oas_handlers_gen.go | 133 ++++++++++++++++++++ pkg/api/oas_json_gen.go | 181 +++++++++++++++++++++++++++ pkg/api/oas_operations_gen.go | 1 + pkg/api/oas_response_decoders_gen.go | 101 +++++++++++++++ pkg/api/oas_response_encoders_gen.go | 14 +++ pkg/api/oas_router_gen.go | 45 +++++++ pkg/api/oas_schemas_gen.go | 77 ++++++++++++ pkg/api/oas_server_gen.go | 6 + pkg/api/oas_unimplemented_gen.go | 9 ++ pkg/api/oas_validators_gen.go | 138 ++++++++++++++++++++ pkg/web_api/stats.go | 105 ++++++++++++++++ 13 files changed, 952 insertions(+) create mode 100644 pkg/web_api/stats.go diff --git a/openapi.yaml b/openapi.yaml index cc02f0b..92b786d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -14,6 +14,8 @@ tags: description: Long-running operations - name: Session description: Session queries + - name: Stats + description: Statistics queries - name: Submissions description: Submission operations - name: Scripts @@ -23,6 +25,26 @@ tags: security: - cookieAuth: [] paths: + /stats: + get: + summary: Get aggregate statistics + operationId: getStats + tags: + - Stats + security: [] + responses: + "200": + description: Successful response + content: + application/json: + schema: + $ref: "#/components/schemas/Stats" + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /session/user: get: summary: Get information about the currently logged in user @@ -2235,6 +2257,47 @@ components: type: integer format: int32 minimum: 0 + Stats: + description: Aggregate statistics for submissions and mapfixes + type: object + properties: + TotalSubmissions: + type: integer + format: int64 + minimum: 0 + description: Total number of submissions + TotalMapfixes: + type: integer + format: int64 + minimum: 0 + description: Total number of mapfixes + ReleasedSubmissions: + type: integer + format: int64 + minimum: 0 + description: Number of released submissions + ReleasedMapfixes: + type: integer + format: int64 + minimum: 0 + description: Number of released mapfixes + SubmittedSubmissions: + type: integer + format: int64 + minimum: 0 + description: Number of submissions under review + SubmittedMapfixes: + type: integer + format: int64 + minimum: 0 + description: Number of mapfixes under review + required: + - TotalSubmissions + - TotalMapfixes + - ReleasedSubmissions + - ReleasedMapfixes + - SubmittedSubmissions + - SubmittedMapfixes Error: description: Represents error object type: object diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index 7716981..3d21353 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -283,6 +283,12 @@ type Invoker interface { // // GET /script-policy/{ScriptPolicyID} GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (*ScriptPolicy, error) + // GetStats invokes getStats operation. + // + // Get aggregate statistics. + // + // GET /stats + GetStats(ctx context.Context) (*Stats, error) // GetSubmission invokes getSubmission operation. // // Retrieve map with ID. @@ -5377,6 +5383,79 @@ func (c *Client) sendGetScriptPolicy(ctx context.Context, params GetScriptPolicy return result, nil } +// GetStats invokes getStats operation. +// +// Get aggregate statistics. +// +// GET /stats +func (c *Client) GetStats(ctx context.Context) (*Stats, error) { + res, err := c.sendGetStats(ctx) + return res, err +} + +func (c *Client) sendGetStats(ctx context.Context) (res *Stats, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getStats"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.URLTemplateKey.String("/stats"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, GetStatsOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/stats" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "GET", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeGetStatsResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // GetSubmission invokes getSubmission operation. // // Retrieve map with ID. diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 00ea170..f99e973 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -8064,6 +8064,139 @@ func (s *Server) handleGetScriptPolicyRequest(args [1]string, argsEscaped bool, } } +// handleGetStatsRequest handles getStats operation. +// +// Get aggregate statistics. +// +// GET /stats +func (s *Server) handleGetStatsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("getStats"), + semconv.HTTPRequestMethodKey.String("GET"), + semconv.HTTPRouteKey.String("/stats"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), GetStatsOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + ) + + var rawBody []byte + + var response *Stats + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: GetStatsOperation, + OperationSummary: "Get aggregate statistics", + OperationID: "getStats", + Body: nil, + RawBody: rawBody, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = *Stats + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.GetStats(ctx) + return response, err + }, + ) + } else { + response, err = s.h.GetStats(ctx) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeGetStatsResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleGetSubmissionRequest handles getSubmission operation. // // Retrieve map with ID. diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go index 7456cf8..807842d 100644 --- a/pkg/api/oas_json_gen.go +++ b/pkg/api/oas_json_gen.go @@ -3675,6 +3675,187 @@ func (s *ScriptUpdate) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode implements json.Marshaler. +func (s *Stats) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Stats) encodeFields(e *jx.Encoder) { + { + e.FieldStart("TotalSubmissions") + e.Int64(s.TotalSubmissions) + } + { + e.FieldStart("TotalMapfixes") + e.Int64(s.TotalMapfixes) + } + { + e.FieldStart("ReleasedSubmissions") + e.Int64(s.ReleasedSubmissions) + } + { + e.FieldStart("ReleasedMapfixes") + e.Int64(s.ReleasedMapfixes) + } + { + e.FieldStart("SubmittedSubmissions") + e.Int64(s.SubmittedSubmissions) + } + { + e.FieldStart("SubmittedMapfixes") + e.Int64(s.SubmittedMapfixes) + } +} + +var jsonFieldsNameOfStats = [6]string{ + 0: "TotalSubmissions", + 1: "TotalMapfixes", + 2: "ReleasedSubmissions", + 3: "ReleasedMapfixes", + 4: "SubmittedSubmissions", + 5: "SubmittedMapfixes", +} + +// Decode decodes Stats from json. +func (s *Stats) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Stats to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "TotalSubmissions": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int64() + s.TotalSubmissions = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"TotalSubmissions\"") + } + case "TotalMapfixes": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := d.Int64() + s.TotalMapfixes = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"TotalMapfixes\"") + } + case "ReleasedSubmissions": + requiredBitSet[0] |= 1 << 2 + if err := func() error { + v, err := d.Int64() + s.ReleasedSubmissions = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ReleasedSubmissions\"") + } + case "ReleasedMapfixes": + requiredBitSet[0] |= 1 << 3 + if err := func() error { + v, err := d.Int64() + s.ReleasedMapfixes = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ReleasedMapfixes\"") + } + case "SubmittedSubmissions": + requiredBitSet[0] |= 1 << 4 + if err := func() error { + v, err := d.Int64() + s.SubmittedSubmissions = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"SubmittedSubmissions\"") + } + case "SubmittedMapfixes": + requiredBitSet[0] |= 1 << 5 + if err := func() error { + v, err := d.Int64() + s.SubmittedMapfixes = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"SubmittedMapfixes\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Stats") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00111111, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfStats) { + name = jsonFieldsNameOfStats[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Stats) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Stats) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode implements json.Marshaler. func (s *Submission) Encode(e *jx.Encoder) { e.ObjStart() diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index b251bf1..f0a03aa 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -48,6 +48,7 @@ const ( GetOperationOperation OperationName = "GetOperation" GetScriptOperation OperationName = "GetScript" GetScriptPolicyOperation OperationName = "GetScriptPolicy" + GetStatsOperation OperationName = "GetStats" GetSubmissionOperation OperationName = "GetSubmission" GetUserThumbnailOperation OperationName = "GetUserThumbnail" ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents" diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index c5de549..da9b604 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -3066,6 +3066,107 @@ func decodeGetScriptPolicyResponse(resp *http.Response) (res *ScriptPolicy, _ er return res, errors.Wrap(defRes, "error") } +func decodeGetStatsResponse(resp *http.Response) (res *Stats, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Stats + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) { switch resp.StatusCode { case 200: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index 483cfe6..6aee6b9 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -421,6 +421,20 @@ func encodeGetScriptPolicyResponse(response *ScriptPolicy, w http.ResponseWriter return nil } +func encodeGetStatsResponse(response *Stats, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index cbba73d..0a4d281 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -939,6 +939,26 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } + case 't': // Prefix: "tats" + + if l := len("tats"); len(elem) >= l && elem[0:l] == "tats" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleGetStatsRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "GET") + } + + return + } + case 'u': // Prefix: "ubmissions" if l := len("ubmissions"); len(elem) >= l && elem[0:l] == "ubmissions" { @@ -2703,6 +2723,31 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } + case 't': // Prefix: "tats" + + if l := len("tats"); len(elem) >= l && elem[0:l] == "tats" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = GetStatsOperation + r.summary = "Get aggregate statistics" + r.operationID = "getStats" + r.operationGroup = "" + r.pathPattern = "/stats" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + case 'u': // Prefix: "ubmissions" if l := len("ubmissions"); len(elem) >= l && elem[0:l] == "ubmissions" { diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 8a5bb50..66bdb7b 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -1911,6 +1911,83 @@ type SetMapfixCompletedNoContent struct{} // SetSubmissionCompletedNoContent is response for SetSubmissionCompleted operation. type SetSubmissionCompletedNoContent struct{} +// Aggregate statistics for submissions and mapfixes. +// Ref: #/components/schemas/Stats +type Stats struct { + // Total number of submissions. + TotalSubmissions int64 `json:"TotalSubmissions"` + // Total number of mapfixes. + TotalMapfixes int64 `json:"TotalMapfixes"` + // Number of released submissions. + ReleasedSubmissions int64 `json:"ReleasedSubmissions"` + // Number of released mapfixes. + ReleasedMapfixes int64 `json:"ReleasedMapfixes"` + // Number of submissions under review. + SubmittedSubmissions int64 `json:"SubmittedSubmissions"` + // Number of mapfixes under review. + SubmittedMapfixes int64 `json:"SubmittedMapfixes"` +} + +// GetTotalSubmissions returns the value of TotalSubmissions. +func (s *Stats) GetTotalSubmissions() int64 { + return s.TotalSubmissions +} + +// GetTotalMapfixes returns the value of TotalMapfixes. +func (s *Stats) GetTotalMapfixes() int64 { + return s.TotalMapfixes +} + +// GetReleasedSubmissions returns the value of ReleasedSubmissions. +func (s *Stats) GetReleasedSubmissions() int64 { + return s.ReleasedSubmissions +} + +// GetReleasedMapfixes returns the value of ReleasedMapfixes. +func (s *Stats) GetReleasedMapfixes() int64 { + return s.ReleasedMapfixes +} + +// GetSubmittedSubmissions returns the value of SubmittedSubmissions. +func (s *Stats) GetSubmittedSubmissions() int64 { + return s.SubmittedSubmissions +} + +// GetSubmittedMapfixes returns the value of SubmittedMapfixes. +func (s *Stats) GetSubmittedMapfixes() int64 { + return s.SubmittedMapfixes +} + +// SetTotalSubmissions sets the value of TotalSubmissions. +func (s *Stats) SetTotalSubmissions(val int64) { + s.TotalSubmissions = val +} + +// SetTotalMapfixes sets the value of TotalMapfixes. +func (s *Stats) SetTotalMapfixes(val int64) { + s.TotalMapfixes = val +} + +// SetReleasedSubmissions sets the value of ReleasedSubmissions. +func (s *Stats) SetReleasedSubmissions(val int64) { + s.ReleasedSubmissions = val +} + +// SetReleasedMapfixes sets the value of ReleasedMapfixes. +func (s *Stats) SetReleasedMapfixes(val int64) { + s.ReleasedMapfixes = val +} + +// SetSubmittedSubmissions sets the value of SubmittedSubmissions. +func (s *Stats) SetSubmittedSubmissions(val int64) { + s.SubmittedSubmissions = val +} + +// SetSubmittedMapfixes sets the value of SubmittedMapfixes. +func (s *Stats) SetSubmittedMapfixes(val int64) { + s.SubmittedMapfixes = val +} + // Ref: #/components/schemas/Submission type Submission struct { ID int64 `json:"ID"` diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index 5e955fd..da25fa6 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -263,6 +263,12 @@ type Handler interface { // // GET /script-policy/{ScriptPolicyID} GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (*ScriptPolicy, error) + // GetStats implements getStats operation. + // + // Get aggregate statistics. + // + // GET /stats + GetStats(ctx context.Context) (*Stats, error) // GetSubmission implements getSubmission operation. // // Retrieve map with ID. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index d27f4a3..9a274db 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -394,6 +394,15 @@ func (UnimplementedHandler) GetScriptPolicy(ctx context.Context, params GetScrip return r, ht.ErrNotImplemented } +// GetStats implements getStats operation. +// +// Get aggregate statistics. +// +// GET /stats +func (UnimplementedHandler) GetStats(ctx context.Context) (r *Stats, _ error) { + return r, ht.ErrNotImplemented +} + // GetSubmission implements getSubmission operation. // // Retrieve map with ID. diff --git a/pkg/api/oas_validators_gen.go b/pkg/api/oas_validators_gen.go index 8f40139..700f752 100644 --- a/pkg/api/oas_validators_gen.go +++ b/pkg/api/oas_validators_gen.go @@ -1832,6 +1832,144 @@ func (s *ScriptUpdate) Validate() error { return nil } +func (s *Stats) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.TotalSubmissions)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "TotalSubmissions", + Error: err, + }) + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.TotalMapfixes)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "TotalMapfixes", + Error: err, + }) + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.ReleasedSubmissions)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "ReleasedSubmissions", + Error: err, + }) + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.ReleasedMapfixes)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "ReleasedMapfixes", + Error: err, + }) + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.SubmittedSubmissions)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "SubmittedSubmissions", + Error: err, + }) + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(s.SubmittedMapfixes)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "SubmittedMapfixes", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + func (s *Submission) Validate() error { if s == nil { return validate.ErrNilPointer diff --git a/pkg/web_api/stats.go b/pkg/web_api/stats.go new file mode 100644 index 0000000..fe1dce2 --- /dev/null +++ b/pkg/web_api/stats.go @@ -0,0 +1,105 @@ +package web_api + +import ( + "context" + + "git.itzana.me/strafesnet/maps-service/pkg/api" + "git.itzana.me/strafesnet/maps-service/pkg/datastore" + "git.itzana.me/strafesnet/maps-service/pkg/model" + "git.itzana.me/strafesnet/maps-service/pkg/service" +) + +// GET /stats +func (svc *Service) GetStats(ctx context.Context) (*api.Stats, error) { + // Get total submissions count + totalSubmissions, _, err := svc.inner.ListSubmissionsWithTotal(ctx, service.NewSubmissionFilter(), model.Page{ + Number: 1, + Size: 0, // We only want the count, not the items + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + // Get total mapfixes count + totalMapfixes, _, err := svc.inner.ListMapfixesWithTotal(ctx, service.NewMapfixFilter(), model.Page{ + Number: 1, + Size: 0, // We only want the count, not the items + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + // Get released submissions count + releasedSubmissionsFilter := service.NewSubmissionFilter() + releasedSubmissionsFilter.SetStatuses([]model.SubmissionStatus{model.SubmissionStatusReleased}) + releasedSubmissions, _, err := svc.inner.ListSubmissionsWithTotal(ctx, releasedSubmissionsFilter, model.Page{ + Number: 1, + Size: 0, + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + // Get released mapfixes count + releasedMapfixesFilter := service.NewMapfixFilter() + releasedMapfixesFilter.SetStatuses([]model.MapfixStatus{model.MapfixStatusReleased}) + releasedMapfixes, _, err := svc.inner.ListMapfixesWithTotal(ctx, releasedMapfixesFilter, model.Page{ + Number: 1, + Size: 0, + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + // Get submitted submissions count (under review) + submittedSubmissionsFilter := service.NewSubmissionFilter() + submittedSubmissionsFilter.SetStatuses([]model.SubmissionStatus{ + model.SubmissionStatusUnderConstruction, + model.SubmissionStatusChangesRequested, + model.SubmissionStatusSubmitting, + model.SubmissionStatusSubmitted, + model.SubmissionStatusAcceptedUnvalidated, + model.SubmissionStatusValidating, + model.SubmissionStatusValidated, + model.SubmissionStatusUploading, + model.SubmissionStatusUploaded, + }) + submittedSubmissions, _, err := svc.inner.ListSubmissionsWithTotal(ctx, submittedSubmissionsFilter, model.Page{ + Number: 1, + Size: 0, + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + // Get submitted mapfixes count (under review) + submittedMapfixesFilter := service.NewMapfixFilter() + submittedMapfixesFilter.SetStatuses([]model.MapfixStatus{ + model.MapfixStatusUnderConstruction, + model.MapfixStatusChangesRequested, + model.MapfixStatusSubmitting, + model.MapfixStatusSubmitted, + model.MapfixStatusAcceptedUnvalidated, + model.MapfixStatusValidating, + model.MapfixStatusValidated, + model.MapfixStatusUploading, + model.MapfixStatusUploaded, + model.MapfixStatusReleasing, + }) + submittedMapfixes, _, err := svc.inner.ListMapfixesWithTotal(ctx, submittedMapfixesFilter, model.Page{ + Number: 1, + Size: 0, + }, datastore.ListSortDisabled) + if err != nil { + return nil, err + } + + return &api.Stats{ + TotalSubmissions: totalSubmissions, + TotalMapfixes: totalMapfixes, + ReleasedSubmissions: releasedSubmissions, + ReleasedMapfixes: releasedMapfixes, + SubmittedSubmissions: submittedSubmissions, + SubmittedMapfixes: submittedMapfixes, + }, nil +} -- 2.49.1 From b2232f4177c00d0c6050324b60cd63c8ea177934 Mon Sep 17 00:00:00 2001 From: itzaname Date: Wed, 24 Dec 2025 20:40:01 -0500 Subject: [PATCH 07/23] Initial work to nuke nextjs --- web/.gitignore | 34 +- web/index.html | 13 + web/next.config.ts | 16 - web/package-lock.json | 4069 +++++++++++++++++ web/package.json | 16 +- web/{src/app => public}/favicon.ico | Bin web/src/App.tsx | 38 + web/src/app/_components/carousel.tsx | 4 +- .../_components/comments/AuditEventItem.tsx | 1 - .../comments/AuditEventsTabPanel.tsx | 1 - .../app/_components/comments/CommentItem.tsx | 1 - .../comments/CommentsAndAuditSection.tsx | 2 +- .../_components/comments/CommentsTabPanel.tsx | 1 - web/src/app/_components/header.tsx | 23 +- web/src/app/_components/mapCard.tsx | 1 - .../_components/review/ReviewItemHeader.tsx | 8 +- web/src/app/_components/statusChip.tsx | 4 +- web/src/app/_components/webpage.tsx | 2 - .../app/admin-submit/{(styles) => }/page.scss | 6 +- web/src/app/admin-submit/page.tsx | 4 +- web/src/app/hooks/useTitle.ts | 2 - web/src/app/layout.tsx | 17 - web/src/app/lib/errorImageResponse.ts | 35 - web/src/app/lib/theme.tsx | 81 +- web/src/app/lib/thumbnailLoader.ts | 3 - web/src/app/mapfixes/[mapfixId]/page.tsx | 16 +- web/src/app/mapfixes/page.tsx | 6 +- web/src/app/maps/[mapId]/fix/page.tsx | 12 +- web/src/app/maps/[mapId]/page.tsx | 20 +- web/src/app/maps/page.tsx | 27 +- web/src/app/operations/[operationId]/page.tsx | 8 +- web/src/app/page.tsx | 475 +- web/src/app/proxy/users/[userId]/route.ts | 31 - .../app/submissions/[submissionId]/page.tsx | 15 +- web/src/app/submissions/page.tsx | 6 +- web/src/app/submit/page.tsx | 8 +- .../app/thumbnails/asset/[assetId]/route.tsx | 57 - web/src/app/thumbnails/maps/[mapId]/route.tsx | 20 - .../app/thumbnails/user/[userId]/route.tsx | 43 - web/src/main.tsx | 13 + web/src/middleware.ts | 33 - web/tsconfig.json | 43 +- web/tsconfig.node.json | 10 + web/vite.config.ts | 25 + 44 files changed, 4732 insertions(+), 518 deletions(-) create mode 100644 web/index.html delete mode 100644 web/next.config.ts create mode 100644 web/package-lock.json rename web/{src/app => public}/favicon.ico (100%) create mode 100644 web/src/App.tsx rename web/src/app/admin-submit/{(styles) => }/page.scss (91%) delete mode 100644 web/src/app/layout.tsx delete mode 100644 web/src/app/lib/errorImageResponse.ts delete mode 100644 web/src/app/lib/thumbnailLoader.ts delete mode 100644 web/src/app/proxy/users/[userId]/route.ts delete mode 100644 web/src/app/thumbnails/asset/[assetId]/route.tsx delete mode 100644 web/src/app/thumbnails/maps/[mapId]/route.tsx delete mode 100644 web/src/app/thumbnails/user/[userId]/route.tsx create mode 100644 web/src/main.tsx delete mode 100644 web/src/middleware.ts create mode 100644 web/tsconfig.node.json create mode 100644 web/vite.config.ts diff --git a/web/.gitignore b/web/.gitignore index c06258e..9b71295 100644 --- a/web/.gitignore +++ b/web/.gitignore @@ -1,24 +1,12 @@ -bun.lockb - # dependencies /node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions # testing /coverage -# next.js -/.next/ -/out/ - # production /build +/dist # misc .DS_Store @@ -29,12 +17,22 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -# env files (can opt-in for committing if needed) +# env files .env* - -# vercel -.vercel +.env.local +.env.development.local +.env.test.local +.env.production.local # typescript *.tsbuildinfo -next-env.d.ts + +# editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..5ac2c90 --- /dev/null +++ b/web/index.html @@ -0,0 +1,13 @@ + + + + + + + Maps Service + + +
+ + + diff --git a/web/next.config.ts b/web/next.config.ts deleted file mode 100644 index 7c674d8..0000000 --- a/web/next.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - distDir: "build", - output: "standalone", - images: { - remotePatterns: [ - { - protocol: "https", - hostname: "**.rbxcdn.com", - }, - ], - }, -}; - -export default nextConfig; diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 0000000..ec970c7 --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,4069 @@ +{ + "name": "map-service-web", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "map-service-web", + "version": "0.1.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.6", + "@mui/material": "^7.3.6", + "date-fns": "^4.1.0", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "react-router-dom": "^7.1.3", + "sass": "^1.94.2" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.3.3", + "@types/node": "^24.10.1", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.39.1", + "typescript": "^5.9.3", + "vite": "^6.0.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "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.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "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.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "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" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@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", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.6.tgz", + "integrity": "sha512-QaYtTHlr8kDFN5mE1wbvVARRKH7Fdw1ZuOjBJcFdVpfNfRYKF3QLT4rt+WaB6CKJvpqxRsmEo0kpYinhH5GeHg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.6.tgz", + "integrity": "sha512-0FfkXEj22ysIq5pa41A2NbcAhJSvmcZQ/vcTIbjDsd6hlslG82k5BEBqqS0ZJprxwIL3B45qpJ+bPHwJPlF7uQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^7.3.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.6.tgz", + "integrity": "sha512-R4DaYF3dgCQCUAkr4wW1w26GHXcf5rCmBRHVBuuvJvaGLmZdD8EjatP80Nz5JCw0KxORAzwftnHzXVnjR8HnFw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/core-downloads-tracker": "^7.3.6", + "@mui/system": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^19.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^7.3.6", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.6.tgz", + "integrity": "sha512-Ws9wZpqM+FlnbZXaY/7yvyvWQo1+02Tbx50mVdNmzWEi51C51y56KAbaDCYyulOOBL6BJxuaqG8rNNuj7ivVyw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.6", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.6.tgz", + "integrity": "sha512-+wiYbtvj+zyUkmDB+ysH6zRjuQIJ+CM56w0fEXV+VDNdvOuSywG+/8kpjddvvlfMLsaWdQe5oTuYGBcodmqGzQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.6.tgz", + "integrity": "sha512-8fehAazkHNP1imMrdD2m2hbA9sl7Ur6jfuNweh5o4l9YPty4iaZzRXqYvBCWQNwFaSHmMEj2KPbyXGp7Bt73Rg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/private-theming": "^7.3.6", + "@mui/styled-engine": "^7.3.6", + "@mui/types": "^7.4.9", + "@mui/utils": "^7.3.6", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.9.tgz", + "integrity": "sha512-dNO8Z9T2cujkSIaCnWwprfeKmTWh97cnjkgmpFJ2sbfXLx8SMZijCYHOtP/y5nnUb/Rm2omxbDMmtUoSaUtKaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.6.tgz", + "integrity": "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.9", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "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.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", + "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", + "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001761", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz", + "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.267", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", + "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", + "dev": true, + "license": "ISC" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz", + "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-is": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz", + "integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.11.0.tgz", + "integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.11.0.tgz", + "integrity": "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==", + "license": "MIT", + "dependencies": { + "react-router": "7.11.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sass": { + "version": "1.97.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz", + "integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/scheduler": { + "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": { + "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/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "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.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "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" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "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" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "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" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/web/package.json b/web/package.json index 83f604d..e3394a8 100644 --- a/web/package.json +++ b/web/package.json @@ -2,11 +2,12 @@ "name": "map-service-web", "version": "0.1.0", "private": true, + "type": "module", "scripts": { - "dev": "next dev -p 3000 --turbopack", - "build": "next build", - "start": "next start -p 3000", - "lint": "next lint" + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint src --ext ts,tsx" }, "dependencies": { "@emotion/react": "^11.14.0", @@ -14,9 +15,9 @@ "@mui/icons-material": "^7.3.6", "@mui/material": "^7.3.6", "date-fns": "^4.1.0", - "next": "^16.0.7", "react": "^19.2.1", "react-dom": "^19.2.1", + "react-router-dom": "^7.1.3", "sass": "^1.94.2" }, "devDependencies": { @@ -24,8 +25,9 @@ "@types/node": "^24.10.1", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.39.1", - "eslint-config-next": "16.0.7", - "typescript": "^5.9.3" + "typescript": "^5.9.3", + "vite": "^6.0.7" } } diff --git a/web/src/app/favicon.ico b/web/public/favicon.ico similarity index 100% rename from web/src/app/favicon.ico rename to web/public/favicon.ico diff --git a/web/src/App.tsx b/web/src/App.tsx new file mode 100644 index 0000000..e927689 --- /dev/null +++ b/web/src/App.tsx @@ -0,0 +1,38 @@ +import { Routes, Route } from 'react-router-dom' +import { ThemeProvider } from '@mui/material' +import { theme } from '@/app/lib/theme' + +// Pages +import Home from '@/app/page' +import MapsPage from '@/app/maps/page' +import MapDetailPage from '@/app/maps/[mapId]/page' +import MapFixCreatePage from '@/app/maps/[mapId]/fix/page' +import MapfixesPage from '@/app/mapfixes/page' +import MapfixDetailPage from '@/app/mapfixes/[mapfixId]/page' +import SubmissionsPage from '@/app/submissions/page' +import SubmissionDetailPage from '@/app/submissions/[submissionId]/page' +import SubmitPage from '@/app/submit/page' +import AdminSubmitPage from '@/app/admin-submit/page' +import OperationPage from '@/app/operations/[operationId]/page' + +function App() { + return ( + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + ) +} + +export default App diff --git a/web/src/app/_components/carousel.tsx b/web/src/app/_components/carousel.tsx index c8c26d2..2495cd8 100644 --- a/web/src/app/_components/carousel.tsx +++ b/web/src/app/_components/carousel.tsx @@ -1,6 +1,6 @@ import {Box, IconButton, Typography} from "@mui/material"; import {useEffect, useRef, useState} from "react"; -import Link from "next/link"; +import { Link } from "react-router-dom"; import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos"; import {SubmissionInfo} from "@/app/ts/Submission"; @@ -69,7 +69,7 @@ export function Carousel({ title, items, renderItem, vie {title} - + View All → diff --git a/web/src/app/_components/comments/AuditEventItem.tsx b/web/src/app/_components/comments/AuditEventItem.tsx index f4a2989..552ba18 100644 --- a/web/src/app/_components/comments/AuditEventItem.tsx +++ b/web/src/app/_components/comments/AuditEventItem.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Box, Avatar, diff --git a/web/src/app/_components/comments/AuditEventsTabPanel.tsx b/web/src/app/_components/comments/AuditEventsTabPanel.tsx index d5b68cc..8a17699 100644 --- a/web/src/app/_components/comments/AuditEventsTabPanel.tsx +++ b/web/src/app/_components/comments/AuditEventsTabPanel.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Box, Stack, diff --git a/web/src/app/_components/comments/CommentItem.tsx b/web/src/app/_components/comments/CommentItem.tsx index a385244..fb9f8e7 100644 --- a/web/src/app/_components/comments/CommentItem.tsx +++ b/web/src/app/_components/comments/CommentItem.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Box, Avatar, diff --git a/web/src/app/_components/comments/CommentsAndAuditSection.tsx b/web/src/app/_components/comments/CommentsAndAuditSection.tsx index 274304b..abc3852 100644 --- a/web/src/app/_components/comments/CommentsAndAuditSection.tsx +++ b/web/src/app/_components/comments/CommentsAndAuditSection.tsx @@ -28,7 +28,7 @@ export default function CommentsAndAuditSection({ }: CommentsAndAuditSectionProps) { const [activeTab, setActiveTab] = useState(0); - const handleTabChange = (event: React.SyntheticEvent, newValue: number) => { + const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => { setActiveTab(newValue); }; diff --git a/web/src/app/_components/comments/CommentsTabPanel.tsx b/web/src/app/_components/comments/CommentsTabPanel.tsx index d8d9ace..159243e 100644 --- a/web/src/app/_components/comments/CommentsTabPanel.tsx +++ b/web/src/app/_components/comments/CommentsTabPanel.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Box, Stack, diff --git a/web/src/app/_components/header.tsx b/web/src/app/_components/header.tsx index 801e954..7eeeffc 100644 --- a/web/src/app/_components/header.tsx +++ b/web/src/app/_components/header.tsx @@ -1,7 +1,4 @@ -"use client" - -import Link from "next/link" -import Image from "next/image"; +import { Link } from "react-router-dom" import { UserInfo } from "@/app/ts/User"; import { useState, useEffect } from "react"; @@ -37,7 +34,7 @@ const navItems: HeaderButton[] = [ function HeaderButton(header: HeaderButton) { return ( - ); @@ -109,14 +106,14 @@ export default function Header() { {navItems.map((item) => ( - + ))} {valid && user && ( - + @@ -130,7 +127,7 @@ export default function Header() { )} {valid && user && ( - + @@ -211,7 +208,7 @@ export default function Header() { {/* Right side of nav */} {!isMobile && valid && user && ( - )} @@ -223,11 +220,10 @@ export default function Header() { size="small" style={{ textTransform: "none" }} > - {user.Username} - + Manage @@ -265,11 +261,10 @@ export default function Header() { color="inherit" size="small" > - {user.Username} diff --git a/web/src/app/_components/mapCard.tsx b/web/src/app/_components/mapCard.tsx index 1528465..e005643 100644 --- a/web/src/app/_components/mapCard.tsx +++ b/web/src/app/_components/mapCard.tsx @@ -1,4 +1,3 @@ -import React from "react"; import {Avatar, Box, Card, CardActionArea, CardContent, CardMedia, Divider, Grid, Typography} from "@mui/material"; import {Explore, Person2} from "@mui/icons-material"; import {StatusChip} from "@/app/_components/statusChip"; diff --git a/web/src/app/_components/review/ReviewItemHeader.tsx b/web/src/app/_components/review/ReviewItemHeader.tsx index 3fd975d..dd3ebd6 100644 --- a/web/src/app/_components/review/ReviewItemHeader.tsx +++ b/web/src/app/_components/review/ReviewItemHeader.tsx @@ -4,7 +4,7 @@ import { SubmissionStatus } from "@/app/ts/Submission"; import { MapfixStatus } from "@/app/ts/Mapfix"; import {Status, StatusMatches} from "@/app/ts/Status"; import { useState, useEffect } from "react"; -import Link from "next/link"; +import { Link } from "react-router-dom"; import LaunchIcon from '@mui/icons-material/Launch'; function SubmitterName({ submitterId }: { submitterId: number }) { @@ -30,14 +30,14 @@ function SubmitterName({ submitterId }: { submitterId: number }) { }, [submitterId]); if (loading) return Loading...; - return + return {name || submitterId} - + } interface ReviewItemHeaderProps { @@ -59,7 +59,7 @@ export const ReviewItemHeader = ({ displayName, assetId, statusId, creator, subm <> {assetId != null ? ( - + { +export const StatusChip = ({status}: { status: number }): JSX.Element => { let color: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' = 'default'; let icon: JSX.Element = ; let label: string = 'Unknown'; diff --git a/web/src/app/_components/webpage.tsx b/web/src/app/_components/webpage.tsx index fc386fd..3ee1d52 100644 --- a/web/src/app/_components/webpage.tsx +++ b/web/src/app/_components/webpage.tsx @@ -1,5 +1,3 @@ -"use client" - import Header from "./header"; export default function Webpage({children}: Readonly<{children?: React.ReactNode}>) { diff --git a/web/src/app/admin-submit/(styles)/page.scss b/web/src/app/admin-submit/page.scss similarity index 91% rename from web/src/app/admin-submit/(styles)/page.scss rename to web/src/app/admin-submit/page.scss index 23bf59a..5db80da 100644 --- a/web/src/app/admin-submit/(styles)/page.scss +++ b/web/src/app/admin-submit/page.scss @@ -1,4 +1,4 @@ -@use "../../globals.scss"; +@use "../globals.scss"; ::placeholder { color: var(--placeholder-text) @@ -47,8 +47,4 @@ header h1 { form { display: grid; gap: 25px; - - fieldset { - border: blue - } } diff --git a/web/src/app/admin-submit/page.tsx b/web/src/app/admin-submit/page.tsx index d76b11c..c13dec9 100644 --- a/web/src/app/admin-submit/page.tsx +++ b/web/src/app/admin-submit/page.tsx @@ -1,5 +1,3 @@ -"use client" - import { Button, TextField } from "@mui/material" import GameSelection from "./_game"; @@ -8,7 +6,7 @@ import Webpage from "@/app/_components/webpage" import React, { useState } from "react"; import {useTitle} from "@/app/hooks/useTitle"; -import "./(styles)/page.scss" +import "./page.scss" interface SubmissionPayload { AssetID: number; diff --git a/web/src/app/hooks/useTitle.ts b/web/src/app/hooks/useTitle.ts index ea5c4a6..c77fe50 100644 --- a/web/src/app/hooks/useTitle.ts +++ b/web/src/app/hooks/useTitle.ts @@ -1,5 +1,3 @@ -'use client'; - import { useEffect } from 'react'; export function useTitle(title: string) { diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx deleted file mode 100644 index 8d4e312..0000000 --- a/web/src/app/layout.tsx +++ /dev/null @@ -1,17 +0,0 @@ -"use client"; - -import "./globals.scss"; -import {theme} from "@/app/lib/theme"; -import {ThemeProvider} from "@mui/material"; - -export default function RootLayout({children}: Readonly<{children: React.ReactNode}>) { - return ( - - - - {children} - - - - ); -} \ No newline at end of file diff --git a/web/src/app/lib/errorImageResponse.ts b/web/src/app/lib/errorImageResponse.ts deleted file mode 100644 index 63b0ac0..0000000 --- a/web/src/app/lib/errorImageResponse.ts +++ /dev/null @@ -1,35 +0,0 @@ -import path from 'path'; -import { promises as fs } from 'fs'; -import { NextResponse } from 'next/server'; - -export async function errorImageResponse( - statusCode: number = 500, - options?: { message?: string } -): Promise { - const file = `${statusCode}.png`; - const filePath = path.join(process.cwd(), 'public/errors', file); - - const headers: Record = { - 'Content-Type': 'image/png', - }; - if (options?.message) { - headers['X-Error-Message'] = encodeURIComponent(options.message); - } - - try { - const buffer = await fs.readFile(filePath); - headers['Content-Length'] = buffer.length.toString(); - return new NextResponse(buffer, { - status: statusCode, - headers, - }); - } catch { - const fallback = path.join(process.cwd(), 'public/errors', '500.png'); - const buffer = await fs.readFile(fallback); - headers['Content-Length'] = buffer.length.toString(); - return new NextResponse(buffer, { - status: 500, - headers, - }); - } -} \ No newline at end of file diff --git a/web/src/app/lib/theme.tsx b/web/src/app/lib/theme.tsx index 07d46c7..80b04de 100644 --- a/web/src/app/lib/theme.tsx +++ b/web/src/app/lib/theme.tsx @@ -4,47 +4,85 @@ export const theme = createTheme({ palette: { mode: 'dark', primary: { - main: '#90caf9', + main: '#7c3aed', + dark: '#5b21b6', + light: '#a78bfa', }, secondary: { - main: '#f48fb1', + main: '#06b6d4', + dark: '#0891b2', + light: '#22d3ee', }, background: { - default: '#121212', - paper: '#1e1e1e', + default: '#0c0c0f', + paper: '#18181b', + }, + text: { + primary: '#ffffff', + secondary: '#a1a1aa', }, }, typography: { - fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif', + fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', + h1: { + fontWeight: 900, + letterSpacing: '-0.02em', + }, + h2: { + fontWeight: 800, + letterSpacing: '-0.01em', + }, + h3: { + fontWeight: 700, + letterSpacing: '-0.01em', + }, + h4: { + fontWeight: 700, + }, h5: { - fontWeight: 500, + fontWeight: 600, letterSpacing: '0.5px', }, + h6: { + fontWeight: 600, + }, subtitle1: { fontWeight: 500, fontSize: '0.95rem', }, + body1: { + fontSize: '1rem', + lineHeight: 1.6, + }, body2: { fontSize: '0.875rem', }, caption: { fontSize: '0.75rem', }, + button: { + fontWeight: 700, + textTransform: 'uppercase', + letterSpacing: '0.5px', + }, }, shape: { - borderRadius: 8, + borderRadius: 4, }, components: { MuiCard: { styleOverrides: { root: { - borderRadius: 8, + borderRadius: 4, overflow: 'hidden', - boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', - transition: 'transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out', + backgroundColor: '#18181b', + border: '1px solid rgba(124, 58, 237, 0.15)', + boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4)', + transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)', '&:hover': { transform: 'translateY(-4px)', - boxShadow: '0 8px 16px rgba(0, 0, 0, 0.2)', + border: '1px solid rgba(124, 58, 237, 0.4)', + boxShadow: '0 12px 32px rgba(124, 58, 237, 0.2)', }, }, }, @@ -52,7 +90,7 @@ export const theme = createTheme({ MuiCardMedia: { styleOverrides: { root: { - borderBottom: '1px solid rgba(255, 255, 255, 0.1)', + borderBottom: '1px solid rgba(124, 58, 237, 0.15)', }, }, }, @@ -69,14 +107,14 @@ export const theme = createTheme({ MuiChip: { styleOverrides: { root: { - fontWeight: 500, + fontWeight: 600, }, }, }, MuiDivider: { styleOverrides: { root: { - borderColor: 'rgba(255, 255, 255, 0.1)', + borderColor: 'rgba(124, 58, 237, 0.15)', }, }, }, @@ -84,6 +122,21 @@ export const theme = createTheme({ styleOverrides: { root: { backgroundImage: 'none', + backgroundColor: '#18181b', + }, + }, + }, + MuiButton: { + styleOverrides: { + root: { + borderRadius: 4, + fontWeight: 700, + }, + contained: { + boxShadow: '0 4px 12px rgba(124, 58, 237, 0.4)', + '&:hover': { + boxShadow: '0 6px 20px rgba(124, 58, 237, 0.5)', + }, }, }, }, diff --git a/web/src/app/lib/thumbnailLoader.ts b/web/src/app/lib/thumbnailLoader.ts deleted file mode 100644 index 6e45a87..0000000 --- a/web/src/app/lib/thumbnailLoader.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const thumbnailLoader = ({ src, width, quality }: { src: string, width: number, quality?: number }) => { - return `${src}?w=${width}&q=${quality || 75}`; -}; \ No newline at end of file diff --git a/web/src/app/mapfixes/[mapfixId]/page.tsx b/web/src/app/mapfixes/[mapfixId]/page.tsx index 8e3bab0..f5f2647 100644 --- a/web/src/app/mapfixes/[mapfixId]/page.tsx +++ b/web/src/app/mapfixes/[mapfixId]/page.tsx @@ -1,9 +1,7 @@ -"use client"; - import Webpage from "@/app/_components/webpage"; -import { useParams, useRouter } from "next/navigation"; +import { useParams, useNavigate } from "react-router-dom"; import {useState} from "react"; -import Link from "next/link"; +import { Link } from "react-router-dom"; // MUI Components import { @@ -36,7 +34,7 @@ interface SnackbarState { export default function MapfixDetailsPage() { const { mapfixId } = useParams<{ mapfixId: string }>(); - const router = useRouter(); + const navigate = useNavigate(); const [newComment, setNewComment] = useState(""); const [showBeforeImage, setShowBeforeImage] = useState(false); const [snackbar, setSnackbar] = useState({ @@ -70,7 +68,7 @@ export default function MapfixDetailsPage() { refreshData } = useReviewData({ itemType: 'mapfixes', - itemId: mapfixId + itemId: mapfixId! }); const mapfix = mapfixData as MapfixInfo; @@ -177,7 +175,7 @@ export default function MapfixDetailsPage() { title="Error Loading Mapfix" message={error || "Mapfix not found"} buttonText="Return to Mapfixes" - onButtonClick={() => router.push('/mapfixes')} + onButtonClick={() => navigate('/mapfixes')} /> ); } @@ -191,10 +189,10 @@ export default function MapfixDetailsPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home - + Mapfixes {mapfix.DisplayName} diff --git a/web/src/app/mapfixes/page.tsx b/web/src/app/mapfixes/page.tsx index b45446f..328864f 100644 --- a/web/src/app/mapfixes/page.tsx +++ b/web/src/app/mapfixes/page.tsx @@ -1,5 +1,3 @@ -'use client' - import { useState, useEffect } from "react"; import { MapfixList } from "../ts/Mapfix"; import { MapCard } from "../_components/mapCard"; @@ -13,7 +11,7 @@ import { Pagination, Typography } from "@mui/material"; -import Link from "next/link"; +import { Link } from "react-router-dom"; import NavigateNextIcon from "@mui/icons-material/NavigateNext"; import {useTitle} from "@/app/hooks/useTitle"; @@ -81,7 +79,7 @@ export default function MapfixInfoPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home Mapfixes diff --git a/web/src/app/maps/[mapId]/fix/page.tsx b/web/src/app/maps/[mapId]/fix/page.tsx index 3e99553..30167d1 100644 --- a/web/src/app/maps/[mapId]/fix/page.tsx +++ b/web/src/app/maps/[mapId]/fix/page.tsx @@ -1,5 +1,3 @@ -"use client" - import React, { useState, useEffect } from "react"; import { Button, @@ -16,8 +14,8 @@ import { import SendIcon from '@mui/icons-material/Send'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import Webpage from "@/app/_components/webpage"; -import { useParams } from "next/navigation"; -import Link from "next/link"; +import { useParams } from "react-router-dom"; +import { Link } from "react-router-dom"; import {MapInfo} from "@/app/ts/Map"; import {useTitle} from "@/app/hooks/useTitle"; @@ -134,14 +132,14 @@ export default function MapfixInfoPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home - + Maps {mapDetails && ( - + {mapDetails.DisplayName} )} diff --git a/web/src/app/maps/[mapId]/page.tsx b/web/src/app/maps/[mapId]/page.tsx index 7268b17..bc0edbd 100644 --- a/web/src/app/maps/[mapId]/page.tsx +++ b/web/src/app/maps/[mapId]/page.tsx @@ -1,10 +1,8 @@ -"use client"; - import { MapInfo } from "@/app/ts/Map"; import Webpage from "@/app/_components/webpage"; -import { useParams, useRouter } from "next/navigation"; -import React, { useState, useEffect } from "react"; -import Link from "next/link"; +import { useParams, useNavigate } from "react-router-dom"; +import { useState, useEffect } from "react"; +import { Link } from "react-router-dom"; import { Snackbar, Alert } from "@mui/material"; import { MapfixStatus, type MapfixInfo } from "@/app/ts/Mapfix"; import LaunchIcon from '@mui/icons-material/Launch'; @@ -39,7 +37,7 @@ import {useTitle} from "@/app/hooks/useTitle"; export default function MapDetails() { const { mapId } = useParams(); - const router = useRouter(); + const navigate = useNavigate(); const [map, setMap] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -150,7 +148,7 @@ export default function MapDetails() { }; const handleSubmitMapfix = () => { - router.push(`/maps/${mapId}/fix`); + navigate(`/maps/${mapId}/fix`); }; const handleCopyId = (idToCopy: string) => { @@ -180,7 +178,7 @@ export default function MapDetails() { {error} + + + + + {/* Right Side - Stats */} + + + {[ + { icon: , value: totalSubmissions, label: 'Submissions', color: 'primary.main' }, + { icon: , value: totalMapfixes, label: 'Fixes', color: 'secondary.main' }, + { icon: , value: totalSubmissions + totalMapfixes, label: 'Total', color: 'primary.main' }, + { icon: , value: 'Live', label: 'Status', color: 'secondary.main' }, + ].map((stat, index) => ( + + + {stat.icon} + + + {stat.value} + + + {stat.label} + + + ))} + + + + + + {/* Bottom Fade */} + + + + {/* Main Content */} + + {/* Latest Submissions */} + {submissions && ( + + + + Latest Submissions + + + + + title="" + items={submissions.Submissions} + renderItem={renderSubmissionCard} + viewAllLink="/submissions" + /> + + )} + + {/* Recent Fixes */} + {mapfixes && ( + + + + Recent Fixes + + + + + title="" + items={mapfixes.Mapfixes} + renderItem={renderMapfixCard} + viewAllLink="/mapfixes" + /> + + )} + + {/* Info Cards */} + - - Contribute to the community - - - Help improve maps by submitting fixes or creating new maps submissions for the community. - - - + {[ + { + icon: , + title: 'Submit Your Maps', + description: 'Upload your custom bhop and surf maps to the StrafesNET community.', + link: '/submit', + }, + { + icon: , + title: 'Report Issues', + description: 'Found a bug or glitch? Submit a fix to help improve maps.', + link: '/mapfixes', + }, + { + icon: , + title: 'Track Progress', + description: 'Monitor your submissions and get real-time feedback.', + link: '/submissions', + }, + ].map((card, index) => ( + - Submit Map + {card.icon} - - - - Create Map Fix - - - - - - {/* Submissions Carousel */} - {submissions && ( - - title="Recent Submissions" - items={submissions.Submissions} - renderItem={renderSubmissionCard} - viewAllLink="/submissions" - /> - )} - - {/* Map Fixes Carousel */} - {mapfixes && ( - - title="Recent Map Fixes" - items={mapfixes.Mapfixes} - renderItem={renderMapfixCard} - viewAllLink="/mapfixes" - /> - )} - - + {card.title} + + + {card.description} + + + ))} + + + ); -} \ No newline at end of file +} diff --git a/web/src/app/proxy/users/[userId]/route.ts b/web/src/app/proxy/users/[userId]/route.ts deleted file mode 100644 index b745db2..0000000 --- a/web/src/app/proxy/users/[userId]/route.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { NextResponse } from 'next/server'; - -export async function GET( - request: Request, - { params }: { params: Promise<{ userId: string }> } -) { - const { userId } = await params; - - if (!userId) { - return NextResponse.json({ error: 'User ID is required' }, { status: 400 }); - } - - try { - const apiResponse = await fetch(`https://users.roblox.com/v1/users/${userId}`); - - if (!apiResponse.ok) { - const errorData = await apiResponse.text(); - return NextResponse.json({ error: `Failed to fetch from Roblox API: ${errorData}` }, { status: apiResponse.status }); - } - - const data = await apiResponse.json(); - - // Add caching headers to the response - const headers = new Headers(); - headers.set('Cache-Control', 'public, max-age=3600, s-maxage=3600'); // Cache for 1 hour - - return NextResponse.json(data, { headers }); - } catch { - return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); - } -} diff --git a/web/src/app/submissions/[submissionId]/page.tsx b/web/src/app/submissions/[submissionId]/page.tsx index 8c22338..61c63d8 100644 --- a/web/src/app/submissions/[submissionId]/page.tsx +++ b/web/src/app/submissions/[submissionId]/page.tsx @@ -1,8 +1,7 @@ -"use client"; import Webpage from "@/app/_components/webpage"; -import { useParams, useRouter } from "next/navigation"; +import { useParams, useNavigate } from "react-router-dom"; import {useState} from "react"; -import Link from "next/link"; +import { Link } from "react-router-dom"; // MUI Components import { @@ -35,7 +34,7 @@ interface SnackbarState { export default function SubmissionDetailsPage() { const { submissionId } = useParams<{ submissionId: string }>(); - const router = useRouter(); + const navigate = useNavigate(); const [newComment, setNewComment] = useState(""); const [snackbar, setSnackbar] = useState({ open: false, @@ -70,7 +69,7 @@ export default function SubmissionDetailsPage() { refreshData } = useReviewData({ itemType: 'submissions', - itemId: submissionId + itemId: submissionId! }); const submission = submissionData as SubmissionInfo; @@ -177,7 +176,7 @@ export default function SubmissionDetailsPage() { title="Error Loading Submission" message={error || "Submission not found"} buttonText="Return to Submissions" - onButtonClick={() => router.push('/submissions')} + onButtonClick={() => navigate('/submissions')} /> ); } @@ -190,10 +189,10 @@ export default function SubmissionDetailsPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home - + Submissions {submission.DisplayName} diff --git a/web/src/app/submissions/page.tsx b/web/src/app/submissions/page.tsx index 877cb43..3a43883 100644 --- a/web/src/app/submissions/page.tsx +++ b/web/src/app/submissions/page.tsx @@ -1,5 +1,3 @@ -"use client" - import { useState, useEffect } from "react"; import { SubmissionList } from "../ts/Submission"; import { MapCard } from "../_components/mapCard"; @@ -13,7 +11,7 @@ import { Pagination, Typography } from "@mui/material"; -import Link from "next/link"; +import { Link } from "react-router-dom"; import NavigateNextIcon from "@mui/icons-material/NavigateNext"; import {useTitle} from "@/app/hooks/useTitle"; @@ -93,7 +91,7 @@ export default function SubmissionInfoPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home Submissions diff --git a/web/src/app/submit/page.tsx b/web/src/app/submit/page.tsx index bcd696d..957e27f 100644 --- a/web/src/app/submit/page.tsx +++ b/web/src/app/submit/page.tsx @@ -1,5 +1,3 @@ -"use client" - import React, { useState } from "react"; import { Button, @@ -17,7 +15,7 @@ import SendIcon from '@mui/icons-material/Send'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import Webpage from "@/app/_components/webpage"; import GameSelection from "./_game"; -import Link from "next/link"; +import { Link } from "react-router-dom"; import {useTitle} from "@/app/hooks/useTitle"; interface SubmissionPayload { @@ -89,10 +87,10 @@ export default function SubmitPage() { aria-label="breadcrumb" sx={{ mb: 3 }} > - + Home - + Maps Submit Map diff --git a/web/src/app/thumbnails/asset/[assetId]/route.tsx b/web/src/app/thumbnails/asset/[assetId]/route.tsx deleted file mode 100644 index b93823e..0000000 --- a/web/src/app/thumbnails/asset/[assetId]/route.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { errorImageResponse } from "@/app/lib/errorImageResponse"; - -export async function GET( - request: NextRequest, - context: { params: Promise<{ assetId: string | undefined }> }, -): Promise { - const { assetId } = await context.params; - - if (!assetId) { - return errorImageResponse(400, { - message: "Missing asset ID", - }); - } - - let finalAssetId = assetId; - - try { - const mediaResponse = await fetch( - `https://publish.roblox.com/v1/assets/${assetId}/media`, // NOTE: This allows users to add custom images(their own thumbnail if they'd like) to their maps - ); - if (mediaResponse.ok) { - const mediaData = await mediaResponse.json(); - if (mediaData.data && mediaData.data.length > 0) { - finalAssetId = mediaData.data[0].toString(); - } - } - } catch {} - - try { - const response = await fetch( - `https://thumbnails.roblox.com/v1/assets?format=png&size=512x512&assetIds=${finalAssetId}`, - ); - - if (!response.ok) { - throw new Error( - `Failed to fetch thumbnail JSON [${response.status}]`, - ); - } - - const data = await response.json(); - - const imageUrl = data.data[0]?.imageUrl; - if (!imageUrl) { - return errorImageResponse(404, { - message: "No image URL found in the response", - }); - } - - // Redirect to the actual image URL instead of proxying - return NextResponse.redirect(imageUrl); - } catch (err) { - return errorImageResponse(500, { - message: `Failed to fetch thumbnail URL: ${err}`, - }); - } -} diff --git a/web/src/app/thumbnails/maps/[mapId]/route.tsx b/web/src/app/thumbnails/maps/[mapId]/route.tsx deleted file mode 100644 index a6b21d3..0000000 --- a/web/src/app/thumbnails/maps/[mapId]/route.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { NextRequest, NextResponse } from "next/server" - -export async function GET( - request: NextRequest, - context: { params: Promise<{ mapId: string }> } -): Promise { - // TODO: implement this, we need a cdn for in-game map thumbnails... - - if (!process.env.API_HOST) { - throw new Error('env variable "API_HOST" is not set') - } - - const { mapId } = await context.params - - const apiHost = process.env.API_HOST.replace(/\/api\/?$/, "") - const redirectPath = `/thumbnails/asset/${mapId}` - const redirectUrl = `${apiHost}${redirectPath}` - - return NextResponse.redirect(redirectUrl) -} \ No newline at end of file diff --git a/web/src/app/thumbnails/user/[userId]/route.tsx b/web/src/app/thumbnails/user/[userId]/route.tsx deleted file mode 100644 index dd47a0a..0000000 --- a/web/src/app/thumbnails/user/[userId]/route.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -export async function GET( - request: NextRequest, - context: { params: Promise<{ userId: string | undefined }> }, -): Promise { - const { userId } = await context.params; // Await params to access userId - - if (!userId) { - return NextResponse.json( - { error: "Missing userId parameter" }, - { status: 400 }, - ); - } - - try { - const response = await fetch( - `https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${userId}&size=420x420&format=Png&isCircular=false`, - ); - - if (!response.ok) { - throw new Error("Failed to fetch avatar headshot JSON"); - } - - const data = await response.json(); - - const imageUrl = data.data[0]?.imageUrl; - if (!imageUrl) { - return NextResponse.json( - { error: "No image URL found in the response" }, - { status: 404 }, - ); - } - - // Redirect to the image URL instead of proxying - return NextResponse.redirect(imageUrl); - } catch { - return NextResponse.json( - { error: "Failed to fetch avatar headshot URL" }, - { status: 500 }, - ); - } -} diff --git a/web/src/main.tsx b/web/src/main.tsx new file mode 100644 index 0000000..f3d78a4 --- /dev/null +++ b/web/src/main.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' +import App from './App' +import './app/globals.scss' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + , +) diff --git a/web/src/middleware.ts b/web/src/middleware.ts deleted file mode 100644 index b6220b5..0000000 --- a/web/src/middleware.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NextRequest, NextResponse } from "next/server" - -export const config = { - matcher: ["/api/:path*", "/auth/:path*"], -} - -export function middleware(request: NextRequest) { - const { pathname, search } = request.nextUrl - - if (pathname.startsWith("/api")) { - if (!process.env.API_HOST) { - throw new Error('env variable "API_HOST" is not set') - } - - const baseUrl = process.env.API_HOST.replace(/\/$/, ""); - const path = pathname.replace(/^\/api/, ""); - const apiUrl = new URL(baseUrl + path + search); - - return NextResponse.rewrite(apiUrl, { request }); - } else if (pathname.startsWith("/auth")) { - if (!process.env.AUTH_HOST) { - throw new Error('env variable "AUTH_HOST" is not set') - } - - const authHost = process.env.AUTH_HOST.replace(/\/$/, ""); - const path = pathname.replace(/^\/auth/, ""); - const redirectUrl = new URL(authHost + path + search); - - return NextResponse.redirect(redirectUrl, 302); - } - - return NextResponse.next() -} diff --git a/web/tsconfig.json b/web/tsconfig.json index 1da8897..f0ef724 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -1,28 +1,27 @@ { "compilerOptions": { - "target": "ES2017", + "target": "ES2020", + "useDefineForClassFields": true, "lib": [ - "dom", - "dom.iterable", - "esnext" + "ES2020", + "DOM", + "DOM.Iterable" ], - "allowJs": true, + "module": "ESNext", "skipLibCheck": true, - "strict": true, - "noEmit": true, - "noImplicitAny": true, - "esModuleInterop": true, - "module": "esnext", "moduleResolution": "bundler", + "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, + "noEmit": true, "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "esModuleInterop": true, + "allowJs": true, "paths": { "@/*": [ "./src/*" @@ -30,14 +29,14 @@ } }, "include": [ - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - "next-env.d.ts", - "build/types/**/*.ts", - "build/dev/types/**/*.ts" + "src" ], "exclude": [ "node_modules" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } ] } diff --git a/web/tsconfig.node.json b/web/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/web/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 0000000..37c7e98 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,25 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import path from 'path' + +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, + server: { + port: 3000, + proxy: { + '/api': { + target: process.env.VITE_API_HOST || 'http://localhost:8080', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/api/, ''), + }, + }, + }, + build: { + outDir: 'build', + }, +}) -- 2.49.1 From 8989c08857e85875b450c52ebc0e8f0ebcc206ed Mon Sep 17 00:00:00 2001 From: itzaname Date: Wed, 24 Dec 2025 21:35:24 -0500 Subject: [PATCH 08/23] theme --- web/src/app/_components/carousel.tsx | 36 ++- web/src/app/_components/header.tsx | 295 ++++++++++++++++++++++-- web/src/app/_components/mapCard.tsx | 157 +++++-------- web/src/app/_components/statusChip.tsx | 6 - web/src/app/lib/theme.tsx | 230 ++++++++++++++++--- web/src/app/mapfixes/page.tsx | 19 +- web/src/app/page.tsx | 298 +++++++++++++------------ web/src/app/submissions/page.tsx | 7 +- 8 files changed, 716 insertions(+), 332 deletions(-) diff --git a/web/src/app/_components/carousel.tsx b/web/src/app/_components/carousel.tsx index 2495cd8..64ee693 100644 --- a/web/src/app/_components/carousel.tsx +++ b/web/src/app/_components/carousel.tsx @@ -1,4 +1,4 @@ -import {Box, IconButton, Typography} from "@mui/material"; +import {Box, Button, IconButton, Typography} from "@mui/material"; import {useEffect, useRef, useState} from "react"; import { Link } from "react-router-dom"; import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew"; @@ -65,14 +65,22 @@ export function Carousel({ title, items, renderItem, vie return ( - + {title} - - View All → - + @@ -85,9 +93,12 @@ export function Carousel({ title, items, renderItem, vie transform: 'translateY(-50%)', zIndex: 2, backgroundColor: 'background.paper', - boxShadow: 2, + border: '1px solid rgba(99, 102, 241, 0.2)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)', '&:hover': { - backgroundColor: 'action.hover', + backgroundColor: 'background.paper', + borderColor: 'rgba(99, 102, 241, 0.4)', + boxShadow: '0 8px 20px rgba(99, 102, 241, 0.3)', }, visibility: scrollPosition <= 5 ? 'hidden' : 'visible', }} @@ -106,7 +117,7 @@ export function Carousel({ title, items, renderItem, vie '&::-webkit-scrollbar': { display: 'none', }, - gap: '16px', // Fixed 16px gap - using string with px unit to ensure it's absolute + gap: '20px', padding: '8px 4px', }} > @@ -116,7 +127,7 @@ export function Carousel({ title, items, renderItem, vie sx={{ flex: '0 0 auto', width: { - xs: '260px', // Fixed width at different breakpoints + xs: '260px', sm: '280px', md: '300px' } @@ -135,9 +146,12 @@ export function Carousel({ title, items, renderItem, vie transform: 'translateY(-50%)', zIndex: 2, backgroundColor: 'background.paper', - boxShadow: 2, + border: '1px solid rgba(99, 102, 241, 0.2)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)', '&:hover': { - backgroundColor: 'action.hover', + backgroundColor: 'background.paper', + borderColor: 'rgba(99, 102, 241, 0.4)', + boxShadow: '0 8px 20px rgba(99, 102, 241, 0.3)', }, visibility: scrollPosition >= maxScroll - 5 ? 'hidden' : 'visible', }} diff --git a/web/src/app/_components/header.tsx b/web/src/app/_components/header.tsx index 7eeeffc..cb2e0e2 100644 --- a/web/src/app/_components/header.tsx +++ b/web/src/app/_components/header.tsx @@ -147,7 +147,7 @@ export default function Header() { return ( - + {isMobile && ( + + {/* Logo/Brand */} + + + + + + + StrafesNET + + {navItems.map((item) => ( - + ))} - {/* Push quick links to the right */} + {/* Quick Links Dropdown */} {quickLinks.map(link => ( - {link.name} + + {link.name} + ))} @@ -206,9 +404,20 @@ export default function Header() { {isMobile && } {/* Right side of nav */} - + {!isMobile && valid && user && ( - )} @@ -218,17 +427,31 @@ export default function Header() { onClick={handleMenuOpen} color="inherit" size="small" - style={{ textTransform: "none" }} + sx={{ + textTransform: "none", + borderRadius: 1, + px: 1.5, + border: '1px solid rgba(99, 102, 241, 0.2)', + '&:hover': { + backgroundColor: 'rgba(99, 102, 241, 0.15)', + borderColor: 'rgba(99, 102, 241, 0.4)', + }, + }} > {user.Username} - {user.Username} + + {user.Username} + - - Manage + + Manage Account ) : !isMobile && ( - )} @@ -263,10 +504,13 @@ export default function Header() { > {user.Username} )} @@ -279,10 +523,13 @@ export default function Header() { open={mobileOpen} onClose={handleDrawerToggle} ModalProps={{ - keepMounted: true, // Better open performance on mobile + keepMounted: true, }} sx={{ - '& .MuiDrawer-paper': { boxSizing: 'border-box', width: 240 }, + '& .MuiDrawer-paper': { + boxSizing: 'border-box', + width: 240, + }, }} > {drawer} diff --git a/web/src/app/_components/mapCard.tsx b/web/src/app/_components/mapCard.tsx index e005643..8e38e5b 100644 --- a/web/src/app/_components/mapCard.tsx +++ b/web/src/app/_components/mapCard.tsx @@ -1,4 +1,4 @@ -import {Avatar, Box, Card, CardActionArea, CardContent, CardMedia, Divider, Grid, Typography} from "@mui/material"; +import {Avatar, Box, Card, CardActionArea, CardContent, CardMedia, Divider, Typography} from "@mui/material"; import {Explore, Person2} from "@mui/icons-material"; import {StatusChip} from "@/app/_components/statusChip"; @@ -15,37 +15,23 @@ interface MapCardProps { type: 'mapfix' | 'submission'; } -const CARD_WIDTH = 270; - export function MapCard(props: MapCardProps) { return ( - - - - - + + + - + {props.displayName} - - - {props.gameID === 1 ? 'Bhop' : props.gameID === 2 ? 'Surf' : props.gameID === 5 ? 'Fly Trials' : props.gameID === 4 ? 'Deathrun' : 'Unknown'} - - - - - - {props.author} - + + + + {props.gameID === 1 ? 'Bhop' : props.gameID === 2 ? 'Surf' : props.gameID === 5 ? 'Fly Trials' : props.gameID === 4 ? 'Deathrun' : 'Unknown'} + + + + + + {props.author} + + - + - {/*In the future author should be the username of the submitter not the info from the map*/} - {props.author} - {new Date(props.created * 1000).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' + {new Date(props.created * 1000).toLocaleDateString('en-US', { + month: 'short', + day: 'numeric', + year: 'numeric' })} - - - - + + ) } diff --git a/web/src/app/_components/statusChip.tsx b/web/src/app/_components/statusChip.tsx index fd78fce..f374f28 100644 --- a/web/src/app/_components/statusChip.tsx +++ b/web/src/app/_components/statusChip.tsx @@ -81,12 +81,6 @@ export const StatusChip = ({status}: { status: number }): JSX.Element => { label={label} color={color} size="small" - sx={{ - height: 24, - fontSize: '0.75rem', - fontWeight: 600, - boxShadow: '0 2px 4px rgba(0,0,0,0.2)', - }} /> ); }; diff --git a/web/src/app/lib/theme.tsx b/web/src/app/lib/theme.tsx index 80b04de..43b88bb 100644 --- a/web/src/app/lib/theme.tsx +++ b/web/src/app/lib/theme.tsx @@ -4,85 +4,105 @@ export const theme = createTheme({ palette: { mode: 'dark', primary: { - main: '#7c3aed', - dark: '#5b21b6', - light: '#a78bfa', + main: '#6366f1', + dark: '#4f46e5', + light: '#818cf8', }, secondary: { - main: '#06b6d4', - dark: '#0891b2', - light: '#22d3ee', + main: '#8b5cf6', + dark: '#7c3aed', + light: '#a78bfa', }, background: { - default: '#0c0c0f', - paper: '#18181b', + default: '#0a0a0a', + paper: '#1a1a1a', }, text: { primary: '#ffffff', - secondary: '#a1a1aa', + secondary: '#808080', + }, + error: { + main: '#ef4444', + light: '#f87171', + dark: '#dc2626', + }, + warning: { + main: '#f59e0b', + light: '#fbbf24', + dark: '#d97706', + }, + success: { + main: '#10b981', + light: '#34d399', + dark: '#059669', + }, + info: { + main: '#3b82f6', + light: '#60a5fa', + dark: '#2563eb', }, }, typography: { - fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', + fontFamily: '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif', h1: { - fontWeight: 900, - letterSpacing: '-0.02em', + fontWeight: 800, + letterSpacing: '-0.025em', }, h2: { - fontWeight: 800, - letterSpacing: '-0.01em', + fontWeight: 700, + letterSpacing: '-0.02em', }, h3: { fontWeight: 700, letterSpacing: '-0.01em', }, h4: { - fontWeight: 700, + fontWeight: 600, }, h5: { fontWeight: 600, - letterSpacing: '0.5px', }, h6: { fontWeight: 600, }, subtitle1: { fontWeight: 500, - fontSize: '0.95rem', + fontSize: '1rem', }, body1: { fontSize: '1rem', - lineHeight: 1.6, + lineHeight: 1.7, }, body2: { fontSize: '0.875rem', + lineHeight: 1.6, }, caption: { fontSize: '0.75rem', }, button: { - fontWeight: 700, - textTransform: 'uppercase', - letterSpacing: '0.5px', + fontWeight: 600, + textTransform: 'none', + letterSpacing: '0.01em', }, }, shape: { - borderRadius: 4, + borderRadius: 12, }, components: { MuiCard: { styleOverrides: { root: { - borderRadius: 4, + borderRadius: 16, overflow: 'hidden', - backgroundColor: '#18181b', - border: '1px solid rgba(124, 58, 237, 0.15)', - boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4)', - transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)', + backgroundColor: '#1a1a1a', + border: '1px solid rgba(255, 255, 255, 0.1)', + boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)', + transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', '&:hover': { transform: 'translateY(-4px)', - border: '1px solid rgba(124, 58, 237, 0.4)', - boxShadow: '0 12px 32px rgba(124, 58, 237, 0.2)', + border: '1px solid rgba(255, 255, 255, 0.3)', + boxShadow: '0 20px 25px -5px rgba(255, 255, 255, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.3)', }, }, }, @@ -90,7 +110,7 @@ export const theme = createTheme({ MuiCardMedia: { styleOverrides: { root: { - borderBottom: '1px solid rgba(124, 58, 237, 0.15)', + transition: 'transform 0.3s', }, }, }, @@ -108,13 +128,52 @@ export const theme = createTheme({ styleOverrides: { root: { fontWeight: 600, + borderRadius: 8, + fontSize: '0.75rem', + boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)', + transition: 'all 0.2s ease-in-out', + '&:hover': { + transform: 'translateY(-1px)', + boxShadow: '0 4px 8px rgba(0, 0, 0, 0.3)', + }, + }, + icon: { + marginLeft: '8px', + }, + colorError: { + backgroundColor: '#ef4444', + color: '#ffffff', + '& .MuiChip-icon': { + color: '#ffffff', + }, + }, + colorWarning: { + backgroundColor: '#f59e0b', + color: '#ffffff', + '& .MuiChip-icon': { + color: '#ffffff', + }, + }, + colorSuccess: { + backgroundColor: '#10b981', + color: '#ffffff', + '& .MuiChip-icon': { + color: '#ffffff', + }, + }, + colorInfo: { + backgroundColor: '#3b82f6', + color: '#ffffff', + '& .MuiChip-icon': { + color: '#ffffff', + }, }, }, }, MuiDivider: { styleOverrides: { root: { - borderColor: 'rgba(124, 58, 237, 0.15)', + borderColor: 'rgba(148, 163, 184, 0.1)', }, }, }, @@ -122,20 +181,119 @@ export const theme = createTheme({ styleOverrides: { root: { backgroundImage: 'none', - backgroundColor: '#18181b', + backgroundColor: '#1a1a1a', }, }, }, MuiButton: { styleOverrides: { root: { - borderRadius: 4, - fontWeight: 700, + borderRadius: 10, + fontWeight: 600, + textTransform: 'none', + padding: '10px 20px', + transition: 'all 0.2s ease-in-out', }, contained: { - boxShadow: '0 4px 12px rgba(124, 58, 237, 0.4)', + boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)', '&:hover': { - boxShadow: '0 6px 20px rgba(124, 58, 237, 0.5)', + boxShadow: '0 8px 24px rgba(99, 102, 241, 0.4)', + transform: 'translateY(-2px)', + }, + }, + containedPrimary: { + background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', + '&:hover': { + background: 'linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%)', + }, + }, + outlined: { + borderWidth: '2px', + '&:hover': { + borderWidth: '2px', + backgroundColor: 'rgba(99, 102, 241, 0.1)', + }, + }, + outlinedPrimary: { + borderColor: '#6366f1', + '&:hover': { + borderColor: '#818cf8', + backgroundColor: 'rgba(99, 102, 241, 0.1)', + }, + }, + }, + }, + MuiAppBar: { + styleOverrides: { + root: { + background: 'linear-gradient(135deg, rgba(10, 10, 10, 0.98) 0%, rgba(99, 102, 241, 0.12) 50%, rgba(139, 92, 246, 0.12) 100%), rgba(10, 10, 10, 0.95)', + backdropFilter: 'blur(16px)', + borderBottom: '1px solid rgba(99, 102, 241, 0.3)', + boxShadow: '0 4px 20px rgba(99, 102, 241, 0.15), 0 1px 3px rgba(0, 0, 0, 0.3)', + }, + }, + }, + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: '#1a1a1a', + borderRight: '1px solid rgba(255, 255, 255, 0.1)', + }, + }, + }, + MuiCircularProgress: { + styleOverrides: { + root: { + color: '#6366f1', + }, + }, + }, + MuiIconButton: { + styleOverrides: { + root: { + transition: 'all 0.2s ease-in-out', + '&:hover': { + backgroundColor: 'rgba(99, 102, 241, 0.15)', + transform: 'scale(1.05)', + }, + }, + }, + }, + MuiLink: { + styleOverrides: { + root: { + color: '#818cf8', + textDecoration: 'none', + transition: 'color 0.2s ease-in-out', + '&:hover': { + color: '#a78bfa', + textDecoration: 'underline', + }, + }, + }, + }, + MuiMenu: { + styleOverrides: { + paper: { + background: 'rgba(26, 26, 26, 0.95)', + backdropFilter: 'blur(12px)', + border: '1px solid rgba(99, 102, 241, 0.3)', + boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(99, 102, 241, 0.1)', + }, + }, + }, + MuiMenuItem: { + styleOverrides: { + root: { + transition: 'all 0.2s ease-in-out', + '&:hover': { + backgroundColor: 'rgba(99, 102, 241, 0.15)', + }, + '&.Mui-selected': { + backgroundColor: 'rgba(99, 102, 241, 0.2)', + '&:hover': { + backgroundColor: 'rgba(99, 102, 241, 0.25)', + }, }, }, }, diff --git a/web/src/app/mapfixes/page.tsx b/web/src/app/mapfixes/page.tsx index 328864f..3d1db45 100644 --- a/web/src/app/mapfixes/page.tsx +++ b/web/src/app/mapfixes/page.tsx @@ -70,6 +70,18 @@ export default function MapfixInfoPage() { const totalPages = Math.ceil(mapfixes.Total / cardsPerPage); + if (mapfixes.Total === 0) { + return ( + + + + Mapfixes list is empty. + + + + ); + } + return ( @@ -97,7 +109,12 @@ export default function MapfixInfoPage() { className="grid" sx={{ display: 'grid', - gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', + gridTemplateColumns: { + xs: 'repeat(1, 1fr)', + sm: 'repeat(2, 1fr)', + md: 'repeat(3, 1fr)', + lg: 'repeat(4, 1fr)', + }, gap: 3, width: '100%', }} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 65e938a..a4ad872 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import {MapfixInfo, MapfixList} from "./ts/Mapfix"; +import {MapfixInfo, MapfixList, MapfixStatus} from "./ts/Mapfix"; import { MapCard } from "./_components/mapCard"; import Webpage from "./_components/webpage"; import { ListSortConstants } from "./ts/Sort"; @@ -11,12 +11,12 @@ import { Button, } from "@mui/material"; import { Link } from "react-router-dom"; -import {SubmissionInfo, SubmissionList} from "@/app/ts/Submission"; +import {SubmissionInfo, SubmissionList, SubmissionStatus} from "@/app/ts/Submission"; import {Carousel} from "@/app/_components/carousel"; import {useTitle} from "@/app/hooks/useTitle"; import UploadIcon from "@mui/icons-material/Upload"; import BuildIcon from "@mui/icons-material/Build"; -import SpeedIcon from "@mui/icons-material/Speed"; +import RateReviewIcon from "@mui/icons-material/RateReview"; import TrendingUpIcon from "@mui/icons-material/TrendingUp"; import CheckCircleIcon from "@mui/icons-material/CheckCircle"; @@ -133,63 +133,52 @@ export default function Home() { const totalSubmissions = submissions?.Total || 0; const totalMapfixes = mapfixes?.Total || 0; + // Calculate useful stats from the data + const releasedSubmissions = submissions?.Submissions.filter(s => s.StatusID === SubmissionStatus.Released).length || 0; + const releasedMapfixes = mapfixes?.Mapfixes.filter(m => m.StatusID === MapfixStatus.Released).length || 0; + const totalReleased = releasedSubmissions + releasedMapfixes; + + const underReviewSubmissions = submissions?.Submissions.filter(s => s.StatusID === SubmissionStatus.Submitted).length || 0; + const underReviewMapfixes = mapfixes?.Mapfixes.filter(m => m.StatusID === MapfixStatus.Submitted).length || 0; + const totalUnderReview = underReviewSubmissions + underReviewMapfixes; + return ( - {/* Split Hero Section */} + {/* Hero Section */} - {/* Diagonal Split Background */} + {/* Gradient Orbs */} - - {/* Grid Pattern Overlay */} @@ -204,35 +193,66 @@ export default function Home() { > {/* Left Side - Content */} - - StrafesNET - + + + Welcome to StrafesNET + + - Bhop & Surf -
- + + Bhop & Surf + + Maps Hub
@@ -242,33 +262,23 @@ export default function Home() { sx={{ color: 'text.secondary', mb: 6, - maxWidth: '500px', - lineHeight: 1.7, + maxWidth: '540px', + lineHeight: 1.8, fontWeight: 400, + fontSize: '1.125rem', }} > The central hub for StrafesNET map submissions and fixes. Submit your creations, report bugs, and track community content. - + @@ -278,21 +288,7 @@ export default function Home() { variant="outlined" size="large" startIcon={} - sx={{ - px: 4, - py: 1.5, - fontSize: '1rem', - borderWidth: 2, - borderColor: 'primary.main', - color: 'primary.main', - '&:hover': { - borderWidth: 2, - borderColor: 'primary.light', - bgcolor: 'rgba(124, 58, 237, 0.1)', - transform: 'translateY(-2px)', - }, - transition: 'all 0.2s', - }} + color="secondary" > Report Fix @@ -305,51 +301,59 @@ export default function Home() { sx={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', - gap: 2, + gap: 3, }} > {[ - { icon: , value: totalSubmissions, label: 'Submissions', color: 'primary.main' }, - { icon: , value: totalMapfixes, label: 'Fixes', color: 'secondary.main' }, - { icon: , value: totalSubmissions + totalMapfixes, label: 'Total', color: 'primary.main' }, - { icon: , value: 'Live', label: 'Status', color: 'secondary.main' }, + { icon: , value: totalSubmissions, label: 'Submissions', gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)' }, + { icon: , value: totalMapfixes, label: 'Fixes', gradient: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)' }, + { icon: , value: totalReleased, label: 'Released', gradient: 'linear-gradient(135deg, #10b981 0%, #34d399 100%)' }, + { icon: , value: totalUnderReview, label: 'Under Review', gradient: 'linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%)' }, ].map((stat, index) => ( - - {stat.icon} + + + {stat.icon} + {stat.value} {stat.label} @@ -360,36 +364,27 @@ export default function Home() {
- - {/* Bottom Fade */} - {/* Main Content */} - + {/* Latest Submissions */} {submissions && ( - + Latest Submissions - + + Browse the newest map submissions from the community + title="" @@ -402,18 +397,21 @@ export default function Home() { {/* Recent Fixes */} {mapfixes && ( - + Recent Fixes - + + View recent bug fixes and improvements submitted by players + title="" @@ -429,28 +427,30 @@ export default function Home() { sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: 'repeat(3, 1fr)' }, - gap: 3, - mt: 10, + gap: 4, }} > {[ { - icon: , + icon: , title: 'Submit Your Maps', description: 'Upload your custom bhop and surf maps to the StrafesNET community.', link: '/submit', + gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', }, { - icon: , + icon: , title: 'Report Issues', description: 'Found a bug or glitch? Submit a fix to help improve maps.', link: '/mapfixes', + gradient: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)', }, { - icon: , + icon: , title: 'Track Progress', description: 'Monitor your submissions and get real-time feedback.', link: '/submissions', + gradient: 'linear-gradient(135deg, #818cf8 0%, #a78bfa 100%)', }, ].map((card, index) => ( - {card.icon} + + {card.icon} + {card.title} diff --git a/web/src/app/submissions/page.tsx b/web/src/app/submissions/page.tsx index 3a43883..877dd3f 100644 --- a/web/src/app/submissions/page.tsx +++ b/web/src/app/submissions/page.tsx @@ -109,7 +109,12 @@ export default function SubmissionInfoPage() { className="grid" sx={{ display: 'grid', - gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', + gridTemplateColumns: { + xs: 'repeat(1, 1fr)', + sm: 'repeat(2, 1fr)', + md: 'repeat(3, 1fr)', + lg: 'repeat(4, 1fr)', + }, gap: 3, width: '100%', }} -- 2.49.1 From 75756917b122627537fabb0a191d0d932abf4005 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 14:39:30 -0500 Subject: [PATCH 09/23] some theming --- web/src/app/_components/mapCard.tsx | 4 +++- web/src/app/lib/theme.tsx | 4 ++-- web/src/app/page.tsx | 7 ++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/web/src/app/_components/mapCard.tsx b/web/src/app/_components/mapCard.tsx index 8e38e5b..24b0a6f 100644 --- a/web/src/app/_components/mapCard.tsx +++ b/web/src/app/_components/mapCard.tsx @@ -1,6 +1,7 @@ import {Avatar, Box, Card, CardActionArea, CardContent, CardMedia, Divider, Typography} from "@mui/material"; import {Explore, Person2} from "@mui/icons-material"; import {StatusChip} from "@/app/_components/statusChip"; +import {Link} from "react-router-dom"; interface MapCardProps { displayName: string; @@ -19,7 +20,8 @@ export function MapCard(props: MapCardProps) { return ( + component={Link} + to={`/${props.type === 'submission' ? 'submissions' : 'mapfixes'}/${props.id}`}> `linear-gradient(135deg, ${theme.palette.background.default} 0%, rgba(99, 102, 241, 0.08) 50%, rgba(139, 92, 246, 0.08) 100%)`, + bgcolor: 'background.default', }} > {/* Gradient Orbs */} @@ -335,7 +336,7 @@ export default function Home() { mb: 2, }} > - + {stat.icon} @@ -487,7 +488,7 @@ export default function Home() { transition: 'transform 0.3s', }} > - + {card.icon} -- 2.49.1 From c2b50ffab2f642493cf62bc9bb767009a5c91dc1 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 15:05:51 -0500 Subject: [PATCH 10/23] Cleanup home/nav --- web/src/app/_components/header.tsx | 190 +++------ web/src/app/lib/theme.tsx | 106 ++--- web/src/app/page.tsx | 630 +++++++++++++++++------------ 3 files changed, 481 insertions(+), 445 deletions(-) diff --git a/web/src/app/_components/header.tsx b/web/src/app/_components/header.tsx index cb2e0e2..0d366b8 100644 --- a/web/src/app/_components/header.tsx +++ b/web/src/app/_components/header.tsx @@ -1,6 +1,6 @@ import { Link } from "react-router-dom" import { UserInfo } from "@/app/ts/User"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import AppBar from "@mui/material/AppBar"; import Toolbar from "@mui/material/Toolbar"; @@ -45,6 +45,16 @@ export default function Header() { const isMobile = useMediaQuery(theme.breakpoints.down('md')); const [mobileOpen, setMobileOpen] = useState(false); + // Check if animation has already played in this session + const shouldAnimate = useMemo(() => { + const hasAnimated = sessionStorage.getItem('logo-animated'); + if (!hasAnimated) { + sessionStorage.setItem('logo-animated', 'true'); + return true; + } + return false; + }, []); + const handleLoginClick = () => { window.location.href = "/auth/oauth2/login?redirect=" + window.location.href; @@ -168,19 +178,19 @@ export default function Header() { component={Link} to="/" sx={{ - mr: 3, + mr: 4, textDecoration: 'none', display: 'flex', alignItems: 'center', position: 'relative', overflow: 'hidden', - '@keyframes speedLineCompact': { + '@keyframes speedLine': { '0%': { transform: 'translateX(-50px) scaleX(0.5)', opacity: 0, }, '40%': { - opacity: 0.9, + opacity: 0.8, transform: 'translateX(0px) scaleX(1)', }, '100%': { @@ -192,7 +202,7 @@ export default function Header() { '0%': { opacity: 0, transform: 'translateX(-10px)', - filter: 'blur(3px)', + filter: 'blur(2px)', }, '100%': { opacity: 1, @@ -206,91 +216,47 @@ export default function Header() { left: 0, width: '100%', height: '2px', - background: 'linear-gradient(90deg, transparent 10%, rgba(255, 255, 255, 0.9) 50%, transparent 90%)', + background: 'linear-gradient(90deg, transparent 10%, rgba(59, 130, 246, 0.8) 50%, transparent 90%)', pointerEvents: 'none', - animation: 'speedLineCompact 0.6s ease-out forwards', - opacity: 0, + animation: shouldAnimate ? 'speedLine 0.6s ease-out forwards' : 'none', + opacity: shouldAnimate ? 0 : undefined, }, '&::before': { top: '35%', - animationDelay: '0s', + animationDelay: shouldAnimate ? '0s' : undefined, }, '&::after': { top: '65%', - animationDelay: '0.08s', + animationDelay: shouldAnimate ? '0.08s' : undefined, }, }} > - - - StrafesNET @@ -305,24 +271,14 @@ export default function Header() { sx={{ px: 2, py: 1, - borderRadius: 1, - position: 'relative', + borderRadius: 1.5, + fontSize: '0.9rem', + fontWeight: 500, + color: 'text.secondary', + transition: 'all 0.2s', '&:hover': { - backgroundColor: 'transparent', - '&::after': { - width: '70%', - }, - }, - '&::after': { - content: '""', - position: 'absolute', - bottom: 4, - left: '50%', - transform: 'translateX(-50%)', - width: 0, - height: '2px', - background: 'linear-gradient(90deg, #6366f1 0%, #8b5cf6 100%)', - transition: 'width 0.3s ease', + backgroundColor: 'rgba(59, 130, 246, 0.08)', + color: 'text.primary', }, }} > @@ -339,24 +295,14 @@ export default function Header() { sx={{ px: 2, mr: 1, - borderRadius: 1, - position: 'relative', + borderRadius: 1.5, + fontSize: '0.9rem', + fontWeight: 500, + color: 'text.secondary', + transition: 'all 0.2s', '&:hover': { - backgroundColor: 'transparent', - '&::after': { - width: '70%', - }, - }, - '&::after': { - content: '""', - position: 'absolute', - bottom: 4, - left: '50%', - transform: 'translateX(-50%)', - width: 0, - height: '2px', - background: 'linear-gradient(90deg, #6366f1 0%, #8b5cf6 100%)', - transition: 'width 0.3s ease', + backgroundColor: 'rgba(59, 130, 246, 0.08)', + color: 'text.primary', }, }} > @@ -370,8 +316,7 @@ export default function Header() { transformOrigin={{ vertical: 'top', horizontal: 'right' }} sx={{ '& .MuiMenu-paper': { - mt: 1, - borderRadius: 3, + mt: 1.5, }, }} > @@ -381,18 +326,14 @@ export default function Header() { onClick={handleQuickLinksClose} sx={{ minWidth: 200, - borderRadius: 1, - mx: 0.5, - my: 0.25, + fontSize: '0.9rem', }} component="a" href={link.href} target="_blank" rel="noopener noreferrer" > - - {link.name} - + {link.name} ))} @@ -404,7 +345,7 @@ export default function Header() { {isMobile && } {/* Right side of nav */} - + {!isMobile && valid && user && ( @@ -467,8 +407,7 @@ export default function Header() { }} sx={{ '& .MuiMenu-paper': { - mt: 1, - borderRadius: 3, + mt: 1.5, }, }} > @@ -476,9 +415,7 @@ export default function Header() { component="a" href="/auth" sx={{ - borderRadius: 1, - mx: 0.5, - my: 0.25, + fontSize: '0.9rem', }} > Manage Account @@ -490,6 +427,9 @@ export default function Header() { variant="outlined" color="primary" onClick={handleLoginClick} + sx={{ + px: 3, + }} > Login diff --git a/web/src/app/lib/theme.tsx b/web/src/app/lib/theme.tsx index 999a441..f4f16e6 100644 --- a/web/src/app/lib/theme.tsx +++ b/web/src/app/lib/theme.tsx @@ -4,9 +4,9 @@ export const theme = createTheme({ palette: { mode: 'dark', primary: { - main: '#6366f1', - dark: '#4f46e5', - light: '#818cf8', + main: '#3b82f6', + dark: '#2563eb', + light: '#60a5fa', }, secondary: { main: '#8b5cf6', @@ -14,12 +14,12 @@ export const theme = createTheme({ light: '#a78bfa', }, background: { - default: '#0f0f14', - paper: '#1a1a24', + default: '#0a0a0a', + paper: '#171717', }, text: { primary: '#ffffff', - secondary: '#808080', + secondary: '#9ca3af', }, error: { main: '#ef4444', @@ -45,7 +45,7 @@ export const theme = createTheme({ typography: { fontFamily: '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", sans-serif', h1: { - fontWeight: 800, + fontWeight: 700, letterSpacing: '-0.025em', }, h2: { @@ -53,11 +53,12 @@ export const theme = createTheme({ letterSpacing: '-0.02em', }, h3: { - fontWeight: 700, - letterSpacing: '-0.01em', + fontWeight: 600, + letterSpacing: '-0.015em', }, h4: { fontWeight: 600, + letterSpacing: '-0.01em', }, h5: { fontWeight: 600, @@ -93,16 +94,16 @@ export const theme = createTheme({ MuiCard: { styleOverrides: { root: { - borderRadius: 16, + borderRadius: 12, overflow: 'hidden', - backgroundColor: '#1a1a1a', - border: '1px solid rgba(255, 255, 255, 0.1)', - boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)', + backgroundColor: '#171717', + border: '1px solid rgba(255, 255, 255, 0.08)', + boxShadow: '0 1px 3px rgba(0, 0, 0, 0.3)', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', '&:hover': { transform: 'translateY(-4px)', - border: '1px solid rgba(255, 255, 255, 0.3)', - boxShadow: '0 20px 25px -5px rgba(255, 255, 255, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.3)', + border: '1px solid rgba(59, 130, 246, 0.4)', + boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(59, 130, 246, 0.2)', }, }, }, @@ -128,14 +129,9 @@ export const theme = createTheme({ styleOverrides: { root: { fontWeight: 600, - borderRadius: 8, + borderRadius: 6, fontSize: '0.75rem', - boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)', transition: 'all 0.2s ease-in-out', - '&:hover': { - transform: 'translateY(-1px)', - boxShadow: '0 4px 8px rgba(0, 0, 0, 0.3)', - }, }, icon: { marginLeft: '8px', @@ -181,44 +177,51 @@ export const theme = createTheme({ styleOverrides: { root: { backgroundImage: 'none', - backgroundColor: '#1a1a1a', + backgroundColor: '#171717', }, }, }, MuiButton: { styleOverrides: { root: { - borderRadius: 10, + borderRadius: 8, fontWeight: 600, textTransform: 'none', - padding: '10px 20px', + padding: '10px 24px', transition: 'all 0.2s ease-in-out', }, contained: { - boxShadow: '0 4px 12px rgba(99, 102, 241, 0.3)', + boxShadow: 'none', '&:hover': { - boxShadow: '0 8px 24px rgba(99, 102, 241, 0.4)', - transform: 'translateY(-2px)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)', + transform: 'translateY(-1px)', }, }, containedPrimary: { - background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', + background: '#3b82f6', '&:hover': { - background: 'linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%)', + background: '#2563eb', }, }, outlined: { - borderWidth: '2px', + borderWidth: '1.5px', '&:hover': { - borderWidth: '2px', - backgroundColor: 'rgba(99, 102, 241, 0.1)', + borderWidth: '1.5px', + backgroundColor: 'rgba(59, 130, 246, 0.08)', }, }, outlinedPrimary: { - borderColor: '#6366f1', + borderColor: 'rgba(59, 130, 246, 0.5)', '&:hover': { - borderColor: '#818cf8', - backgroundColor: 'rgba(99, 102, 241, 0.1)', + borderColor: '#3b82f6', + backgroundColor: 'rgba(59, 130, 246, 0.08)', + }, + }, + outlinedSecondary: { + borderColor: 'rgba(139, 92, 246, 0.5)', + '&:hover': { + borderColor: '#8b5cf6', + backgroundColor: 'rgba(139, 92, 246, 0.08)', }, }, }, @@ -226,25 +229,25 @@ export const theme = createTheme({ MuiAppBar: { styleOverrides: { root: { - background: 'linear-gradient(135deg, rgba(10, 10, 10, 0.98) 0%, rgba(99, 102, 241, 0.12) 50%, rgba(139, 92, 246, 0.12) 100%), rgba(10, 10, 10, 0.95)', - backdropFilter: 'blur(16px)', - borderBottom: '1px solid rgba(99, 102, 241, 0.3)', - boxShadow: '0 4px 20px rgba(99, 102, 241, 0.15), 0 1px 3px rgba(0, 0, 0, 0.3)', + background: 'rgba(10, 10, 10, 0.8)', + backdropFilter: 'blur(12px)', + borderBottom: '1px solid rgba(255, 255, 255, 0.08)', + boxShadow: 'none', }, }, }, MuiDrawer: { styleOverrides: { paper: { - backgroundColor: '#1a1a1a', - borderRight: '1px solid rgba(255, 255, 255, 0.1)', + backgroundColor: '#0a0a0a', + borderRight: '1px solid rgba(255, 255, 255, 0.08)', }, }, }, MuiCircularProgress: { styleOverrides: { root: { - color: '#6366f1', + color: '#3b82f6', }, }, }, @@ -253,8 +256,7 @@ export const theme = createTheme({ root: { transition: 'all 0.2s ease-in-out', '&:hover': { - backgroundColor: 'rgba(99, 102, 241, 0.15)', - transform: 'scale(1.05)', + backgroundColor: 'rgba(59, 130, 246, 0.1)', }, }, }, @@ -262,11 +264,11 @@ export const theme = createTheme({ MuiLink: { styleOverrides: { root: { - color: '#818cf8', + color: '#60a5fa', textDecoration: 'none', transition: 'color 0.2s ease-in-out', '&:hover': { - color: '#a78bfa', + color: '#3b82f6', textDecoration: 'underline', }, }, @@ -275,10 +277,10 @@ export const theme = createTheme({ MuiMenu: { styleOverrides: { paper: { - background: 'rgba(26, 26, 26, 0.95)', + background: '#171717', backdropFilter: 'blur(12px)', - border: '1px solid rgba(99, 102, 241, 0.3)', - boxShadow: '0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(99, 102, 241, 0.1)', + border: '1px solid rgba(255, 255, 255, 0.08)', + boxShadow: '0 4px 12px rgba(0, 0, 0, 0.4)', }, }, }, @@ -287,12 +289,12 @@ export const theme = createTheme({ root: { transition: 'all 0.2s ease-in-out', '&:hover': { - backgroundColor: 'rgba(99, 102, 241, 0.15)', + backgroundColor: 'rgba(59, 130, 246, 0.1)', }, '&.Mui-selected': { - backgroundColor: 'rgba(99, 102, 241, 0.2)', + backgroundColor: 'rgba(59, 130, 246, 0.15)', '&:hover': { - backgroundColor: 'rgba(99, 102, 241, 0.25)', + backgroundColor: 'rgba(59, 130, 246, 0.2)', }, }, }, diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 2418ca8..d0af27a 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -14,11 +14,12 @@ import { Link } from "react-router-dom"; import {SubmissionInfo, SubmissionList, SubmissionStatus} from "@/app/ts/Submission"; import {Carousel} from "@/app/_components/carousel"; import {useTitle} from "@/app/hooks/useTitle"; -import UploadIcon from "@mui/icons-material/Upload"; import BuildIcon from "@mui/icons-material/Build"; import RateReviewIcon from "@mui/icons-material/RateReview"; -import TrendingUpIcon from "@mui/icons-material/TrendingUp"; -import CheckCircleIcon from "@mui/icons-material/CheckCircle"; +import SpeedIcon from "@mui/icons-material/Speed"; +import MapIcon from "@mui/icons-material/Map"; +import RocketLaunchIcon from "@mui/icons-material/RocketLaunch"; +import EmojiEventsIcon from "@mui/icons-material/EmojiEvents"; export default function Home() { useTitle("Home"); @@ -149,23 +150,22 @@ export default function Home() { `linear-gradient(135deg, ${theme.palette.background.default} 0%, rgba(99, 102, 241, 0.08) 50%, rgba(139, 92, 246, 0.08) 100%)`, - bgcolor: 'background.default', + background: 'linear-gradient(to bottom, #0a0a0a 0%, #0f0f0f 100%)', }} > - {/* Gradient Orbs */} + {/* Subtle Gradient Background */} - - - {/* Left Side - Content */} - + + + {/* Main Headline */} + - - - Welcome to StrafesNET - + StrafesNET - - - - Bhop & Surf - - - Maps Hub - - - - - The central hub for StrafesNET map submissions and fixes. - Submit your creations, report bugs, and track community content. - - - - - + Community Maps + + + {/* Subheadline */} + + Submit your custom maps, map fixes, and shape the future of StrafesNET maps + + + {/* CTA Buttons */} + + + - {/* Right Side - Stats */} - - - {[ - { icon: , value: totalSubmissions, label: 'Submissions', gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)' }, - { icon: , value: totalMapfixes, label: 'Fixes', gradient: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)' }, - { icon: , value: totalReleased, label: 'Released', gradient: 'linear-gradient(135deg, #10b981 0%, #34d399 100%)' }, - { icon: , value: totalUnderReview, label: 'Under Review', gradient: 'linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%)' }, - ].map((stat, index) => ( + {/* Stats Cards */} + + {[ + { + icon: , + value: totalSubmissions, + label: 'Total Maps', + color: '#3b82f6', + }, + { + icon: , + value: totalMapfixes, + label: 'Bug Fixes', + color: '#8b5cf6', + }, + { + icon: , + value: totalReleased, + label: 'Released', + color: '#10b981', + }, + { + icon: , + value: totalUnderReview, + label: 'In Review', + color: '#f59e0b', + }, + ].map((stat, index) => ( + - - - {stat.icon} - - - - {stat.value} - - - {stat.label} - + {stat.icon} - ))} - + + {stat.value} + + + {stat.label} + + + ))} @@ -372,19 +370,24 @@ export default function Home() { {/* Latest Submissions */} {submissions && ( - + Latest Submissions - - Browse the newest map submissions from the community + + Discover the newest custom maps created by the community @@ -399,19 +402,24 @@ export default function Home() { {/* Recent Fixes */} {mapfixes && ( - + Recent Fixes - - View recent bug fixes and improvements submitted by players + + Community-created map fixes and improvements @@ -423,98 +431,184 @@ export default function Home() { )} - {/* Info Cards */} - - {[ - { - icon: , - title: 'Submit Your Maps', - description: 'Upload your custom bhop and surf maps to the StrafesNET community.', - link: '/submit', - gradient: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', - }, - { - icon: , - title: 'Report Issues', - description: 'Found a bug or glitch? Submit a fix to help improve maps.', - link: '/mapfixes', - gradient: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)', - }, - { - icon: , - title: 'Track Progress', - description: 'Monitor your submissions and get real-time feedback.', - link: '/submissions', - gradient: 'linear-gradient(135deg, #818cf8 0%, #a78bfa 100%)', - }, - ].map((card, index) => ( - + + + How It Works + + + Join the community and start contributing today + + + + + {[ + { + icon: , + title: 'Submit Maps', + description: 'Upload your custom bhop and surf maps for review. Maps are evaluated by moderators before being added to the game.', + link: '/submit', + color: '#3b82f6', + }, + { + icon: , + title: 'Submit Fixes', + description: 'Found bugs or issues in existing maps? Submit fixed versions to improve map quality for all players.', + link: '/mapfixes', + color: '#8b5cf6', + }, + { + icon: , + title: 'View Submissions', + description: 'Browse all pending and approved submissions currently in the review queue. Track submission status and feedback.', + link: '/submissions', + color: '#10b981', + }, + ].map((card, index) => ( - + {card.icon} + + {card.title} + + + {card.description} + - - {card.title} - - - {card.description} - - - ))} + ))} + + + {/* Bottom CTA Section */} + + + + Get Started + + + Submit your maps or browse existing submissions to see what's currently in review. + + + + + + +
); -- 2.49.1 From 36547555408cd54596c4605bfe9bf1087b5531b7 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 18:32:31 -0500 Subject: [PATCH 11/23] Thumbnail/nav cleanup --- web/package-lock.json | 45 ++-- web/package.json | 1 + web/src/app/_components/header.tsx | 79 ++---- web/src/app/_components/mapCard.tsx | 41 +++- web/src/app/hooks/useThumbnails.ts | 224 ++++++++++++++++++ web/src/app/hooks/useUser.ts | 39 +++ web/src/app/mapfixes/[mapfixId]/page.tsx | 51 +++- web/src/app/maps/[mapId]/page.tsx | 39 ++- web/src/app/maps/page.tsx | 168 ++++++++----- web/src/app/page.tsx | 14 +- .../app/submissions/[submissionId]/page.tsx | 40 +++- web/src/main.tsx | 20 +- 12 files changed, 598 insertions(+), 163 deletions(-) create mode 100644 web/src/app/hooks/useThumbnails.ts create mode 100644 web/src/app/hooks/useUser.ts diff --git a/web/package-lock.json b/web/package-lock.json index ec970c7..cd59153 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -12,6 +12,7 @@ "@emotion/styled": "^11.14.1", "@mui/icons-material": "^7.3.6", "@mui/material": "^7.3.6", + "@tanstack/react-query": "^5.90.12", "date-fns": "^4.1.0", "react": "^19.2.1", "react-dom": "^19.2.1", @@ -2001,6 +2002,32 @@ "win32" ] }, + "node_modules/@tanstack/query-core": { + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.12.tgz", + "integrity": "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.90.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.12.tgz", + "integrity": "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.90.12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4034,24 +4061,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/web/package.json b/web/package.json index e3394a8..d8c4fcf 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "@emotion/styled": "^11.14.1", "@mui/icons-material": "^7.3.6", "@mui/material": "^7.3.6", + "@tanstack/react-query": "^5.90.12", "date-fns": "^4.1.0", "react": "^19.2.1", "react-dom": "^19.2.1", diff --git a/web/src/app/_components/header.tsx b/web/src/app/_components/header.tsx index 0d366b8..d272343 100644 --- a/web/src/app/_components/header.tsx +++ b/web/src/app/_components/header.tsx @@ -1,6 +1,6 @@ import { Link } from "react-router-dom" -import { UserInfo } from "@/app/ts/User"; -import { useState, useEffect, useMemo } from "react"; +import { useState, useRef } from "react"; +import { useUser } from "@/app/hooks/useUser"; import AppBar from "@mui/material/AppBar"; import Toolbar from "@mui/material/Toolbar"; @@ -44,24 +44,14 @@ export default function Header() { const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('md')); const [mobileOpen, setMobileOpen] = useState(false); - - // Check if animation has already played in this session - const shouldAnimate = useMemo(() => { - const hasAnimated = sessionStorage.getItem('logo-animated'); - if (!hasAnimated) { - sessionStorage.setItem('logo-animated', 'true'); - return true; - } - return false; - }, []); + const hasAnimated = useRef(false); const handleLoginClick = () => { window.location.href = "/auth/oauth2/login?redirect=" + window.location.href; }; - const [valid, setValid] = useState(false); - const [user, setUser] = useState(null); + const { user, isLoggedIn } = useUser(); const [anchorEl, setAnchorEl] = useState(null); const [quickLinksAnchor, setQuickLinksAnchor] = useState(null); @@ -84,32 +74,6 @@ export default function Header() { setQuickLinksAnchor(null); }; - useEffect(() => { - async function getLoginInfo() { - try { - const response = await fetch("/api/session/user"); - - if (!response.ok) { - setValid(false); - setUser(null); - return; - } - - const userData = await response.json(); - const isLoggedIn = userData && 'UserID' in userData; - - setValid(isLoggedIn); - setUser(isLoggedIn ? userData : null); - } catch (error) { - console.error("Error fetching user data:", error); - setValid(false); - setUser(null); - } - } - - getLoginInfo(); - }, []); - // Mobile navigation drawer content const drawer = ( @@ -121,21 +85,21 @@ export default function Header() { ))} - {valid && user && ( + {isLoggedIn && user && ( )} - {!valid && ( + {!isLoggedIn && ( )} - {valid && user && ( + {isLoggedIn && user && ( @@ -218,16 +182,16 @@ export default function Header() { height: '2px', background: 'linear-gradient(90deg, transparent 10%, rgba(59, 130, 246, 0.8) 50%, transparent 90%)', pointerEvents: 'none', - animation: shouldAnimate ? 'speedLine 0.6s ease-out forwards' : 'none', - opacity: shouldAnimate ? 0 : undefined, + animation: !hasAnimated.current ? 'speedLine 0.6s ease-out forwards' : 'none', + opacity: !hasAnimated.current ? 0 : undefined, }, '&::before': { top: '35%', - animationDelay: shouldAnimate ? '0s' : undefined, + animationDelay: !hasAnimated.current ? '0s' : undefined, }, '&::after': { top: '65%', - animationDelay: shouldAnimate ? '0.08s' : undefined, + animationDelay: !hasAnimated.current ? '0.08s' : undefined, }, }} > @@ -239,9 +203,9 @@ export default function Header() { width: '100%', height: '1px', background: 'linear-gradient(90deg, transparent 10%, rgba(139, 92, 246, 0.6) 50%, transparent 90%)', - animation: shouldAnimate ? 'speedLine 0.6s ease-out forwards' : 'none', - animationDelay: shouldAnimate ? '0.04s' : '0s', - opacity: shouldAnimate ? 0 : undefined, + animation: !hasAnimated.current ? 'speedLine 0.6s ease-out forwards' : 'none', + animationDelay: !hasAnimated.current ? '0.04s' : '0s', + opacity: !hasAnimated.current ? 0 : undefined, pointerEvents: 'none', }} /> @@ -254,9 +218,12 @@ export default function Header() { fontSize: '1.125rem', position: 'relative', zIndex: 1, - opacity: shouldAnimate ? 0 : 1, - animation: shouldAnimate ? 'logoReveal 0.5s ease-out forwards' : 'none', - animationDelay: shouldAnimate ? '0.5s' : '0s', + opacity: !hasAnimated.current ? 0 : 1, + animation: !hasAnimated.current ? 'logoReveal 0.5s ease-out forwards' : 'none', + animationDelay: !hasAnimated.current ? '0.5s' : '0s', + }} + onAnimationEnd={() => { + hasAnimated.current = true; }} > StrafesNET @@ -346,7 +313,7 @@ export default function Header() { {/* Right side of nav */} - {!isMobile && valid && user && ( + {!isMobile && isLoggedIn && user && ( @@ -294,7 +302,7 @@ export default function Home() { { icon: , value: totalMapfixes, - label: 'Bug Fixes', + label: 'Map Fixes', color: '#8b5cf6', }, { diff --git a/web/src/app/submissions/[submissionId]/page.tsx b/web/src/app/submissions/[submissionId]/page.tsx index 61c63d8..aee9d6c 100644 --- a/web/src/app/submissions/[submissionId]/page.tsx +++ b/web/src/app/submissions/[submissionId]/page.tsx @@ -2,6 +2,7 @@ import Webpage from "@/app/_components/webpage"; import { useParams, useNavigate } from "react-router-dom"; import {useState} from "react"; import { Link } from "react-router-dom"; +import { useAssetThumbnail } from "@/app/hooks/useThumbnails"; // MUI Components import { @@ -75,6 +76,12 @@ export default function SubmissionDetailsPage() { useTitle(submission ? `${submission.DisplayName} Submission` : 'Loading Submission...'); + // Use thumbnail hook for the submission image + const { thumbnailUrl, isLoading: thumbnailLoading } = useAssetThumbnail( + submission?.AssetID, + '420x420' + ); + // Handle review button actions async function handleReviewAction(action: string, submissionId: number) { try { @@ -203,12 +210,33 @@ export default function SubmissionDetailsPage() { {submission.AssetID ? ( - + + + + ) : ( - - - + + + + + , ) -- 2.49.1 From a26b228ebe1927c541821073948dab6a3c092a1c Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 18:41:40 -0500 Subject: [PATCH 12/23] Add 404 page --- web/src/App.tsx | 2 + web/src/app/not-found/page.tsx | 191 +++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 web/src/app/not-found/page.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index e927689..10d3676 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -14,6 +14,7 @@ import SubmissionDetailPage from '@/app/submissions/[submissionId]/page' import SubmitPage from '@/app/submit/page' import AdminSubmitPage from '@/app/admin-submit/page' import OperationPage from '@/app/operations/[operationId]/page' +import NotFound from '@/app/not-found/page' function App() { return ( @@ -30,6 +31,7 @@ function App() { } /> } /> } /> + } /> ) diff --git a/web/src/app/not-found/page.tsx b/web/src/app/not-found/page.tsx new file mode 100644 index 0000000..02eea1c --- /dev/null +++ b/web/src/app/not-found/page.tsx @@ -0,0 +1,191 @@ +import { Box, Container, Typography, Button } from "@mui/material"; +import { Link } from "react-router-dom"; +import Webpage from "@/app/_components/webpage"; +import { useTitle } from "@/app/hooks/useTitle"; +import HomeIcon from "@mui/icons-material/Home"; +import MapIcon from "@mui/icons-material/Map"; + +export default function NotFound() { + useTitle("404 - Page Not Found"); + + return ( + + + {/* 404 Hero Section */} + + {/* Subtle Gradient Background */} + + + + + + {/* 404 Number */} + + 404 + + + {/* Main Message */} + + Page Not Found + + + {/* Subtext */} + + Looks like this page doesn't exist. The page you're looking for might have been removed, renamed, or never existed in the first place. + + + {/* Action Buttons */} + + + + + + {/* Quick Links */} + + + Quick Links + + + {[ + { label: 'Submissions', path: '/submissions' }, + { label: 'Map Fixes', path: '/mapfixes' }, + { label: 'Submit Map', path: '/submit' }, + ].map((link) => ( + + ))} + + + + + + + + ); +} -- 2.49.1 From 8ab8c441b05707c892a421d4d988c8d532ffb780 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 19:44:51 -0500 Subject: [PATCH 13/23] Home page and header fixes --- web/src/app/_components/header.tsx | 20 +- web/src/app/hooks/useThumbnails.ts | 10 +- web/src/app/maps/[mapId]/fix/page.tsx | 6 +- web/src/app/operations/[operationId]/page.tsx | 202 +++++-- web/src/app/page.tsx | 544 +++++++++++++----- web/src/app/submit/page.tsx | 5 +- web/src/app/ts/Stats.ts | 10 + 7 files changed, 581 insertions(+), 216 deletions(-) create mode 100644 web/src/app/ts/Stats.ts diff --git a/web/src/app/_components/header.tsx b/web/src/app/_components/header.tsx index d272343..e739a0b 100644 --- a/web/src/app/_components/header.tsx +++ b/web/src/app/_components/header.tsx @@ -46,9 +46,21 @@ export default function Header() { const [mobileOpen, setMobileOpen] = useState(false); const hasAnimated = useRef(false); + const getAuthUrl = () => { + const hostname = window.location.hostname; + + // Production only + if (hostname === 'maps.strafes.net') { + return 'https://auth.strafes.net'; + } + + // Default to staging (works for staging.strafes.net and localhost) + return 'https://auth.staging.strafes.net'; + }; + const handleLoginClick = () => { - window.location.href = - "/auth/oauth2/login?redirect=" + window.location.href; + const authUrl = getAuthUrl(); + window.location.href = `${authUrl}/oauth2/login?redirect=${window.location.href}`; }; const { user, isLoggedIn } = useUser(); @@ -101,7 +113,7 @@ export default function Header() { )} {isLoggedIn && user && ( - + @@ -380,7 +392,7 @@ export default function Header() { > ; } diff --git a/web/src/app/maps/[mapId]/fix/page.tsx b/web/src/app/maps/[mapId]/fix/page.tsx index 30167d1..d423303 100644 --- a/web/src/app/maps/[mapId]/fix/page.tsx +++ b/web/src/app/maps/[mapId]/fix/page.tsx @@ -14,8 +14,7 @@ import { import SendIcon from '@mui/icons-material/Send'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import Webpage from "@/app/_components/webpage"; -import { useParams } from "react-router-dom"; -import { Link } from "react-router-dom"; +import { useParams, Link, useNavigate } from "react-router-dom"; import {MapInfo} from "@/app/ts/Map"; import {useTitle} from "@/app/hooks/useTitle"; @@ -34,6 +33,7 @@ const gameTypes: Record = { export default function MapfixInfoPage() { const { mapId } = useParams<{ mapId: string }>(); + const navigate = useNavigate(); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const [mapDetails, setMapDetails] = useState(null); @@ -116,7 +116,7 @@ export default function MapfixInfoPage() { } const { OperationID } = await response.json(); - window.location.assign(`/operations/${OperationID}`); + navigate(`/operations/${OperationID}`); } catch (error) { console.error("Error submitting data:", error); setError(error instanceof Error ? error.message : "An unknown error occurred"); diff --git a/web/src/app/operations/[operationId]/page.tsx b/web/src/app/operations/[operationId]/page.tsx index ec1b98e..346142a 100644 --- a/web/src/app/operations/[operationId]/page.tsx +++ b/web/src/app/operations/[operationId]/page.tsx @@ -11,7 +11,11 @@ import { Divider, Alert, Collapse, - IconButton + IconButton, + Fade, + Grow, + Slide, + keyframes } from "@mui/material"; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; @@ -21,6 +25,67 @@ import PendingIcon from '@mui/icons-material/Pending'; import Webpage from "@/app/_components/webpage"; import {useTitle} from "@/app/hooks/useTitle"; +const pulse = keyframes` + 0% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.05); + opacity: 0.8; + } + 100% { + transform: scale(1); + opacity: 1; + } +`; + +const spin = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +`; + +const slideInUp = keyframes` + from { + transform: translateY(20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +`; + +const successPop = keyframes` + 0% { + transform: scale(0.8); + opacity: 0; + } + 50% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +`; + +const errorShake = keyframes` + 0%, 100% { + transform: translateX(0); + } + 10%, 30%, 50%, 70%, 90% { + transform: translateX(-5px); + } + 20%, 40%, 60%, 80% { + transform: translateX(5px); + } +`; + interface Operation { OperationID: number; Status: number; @@ -70,13 +135,12 @@ export default function OperationStatusPage() { }; fetchOperation(); - if (!intervalRef.current) { - intervalRef.current = setInterval(fetchOperation, 1000); - } + intervalRef.current = setInterval(fetchOperation, 1000); return () => { if (intervalRef.current) { clearInterval(intervalRef.current); + intervalRef.current = null; } }; }, [operationId]); @@ -132,12 +196,27 @@ export default function OperationStatusPage() { } }; + const getStatusAnimation = (status: number) => { + switch (status) { + case 0: + return pulse; + case 1: + return successPop; + case 2: + return errorShake; + default: + return undefined; + } + }; + return ( - - Operation Status - + + + Operation Status + + {loading ? ( @@ -147,33 +226,47 @@ export default function OperationStatusPage() { ) : error ? ( - - {error} - + + + {error} + + ) : operation ? ( - - - - Operation #{operation.OperationID} - - - + + + + + + Operation #{operation.OperationID} + + + - + @@ -231,24 +324,35 @@ export default function OperationStatusPage() { )} - {operation.Status === 1 && ( - - - - )} - + {operation.Status === 1 && ( + + + + )} + + + ) : ( - - No operation found with ID: {operationId} - + + + No operation found with ID: {operationId} + + )} diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index f5fa394..9208ff3 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -1,5 +1,5 @@ -import { useState, useEffect } from "react"; -import {MapfixInfo, MapfixList, MapfixStatus} from "./ts/Mapfix"; +import React, { useState, useEffect } from "react"; +import {MapfixInfo, MapfixList} from "./ts/Mapfix"; import { MapCard } from "./_components/mapCard"; import Webpage from "./_components/webpage"; import { ListSortConstants } from "./ts/Sort"; @@ -11,10 +11,11 @@ import { Button, } from "@mui/material"; import { Link } from "react-router-dom"; -import {SubmissionInfo, SubmissionList, SubmissionStatus} from "@/app/ts/Submission"; +import {SubmissionInfo, SubmissionList} from "@/app/ts/Submission"; import {Carousel} from "@/app/_components/carousel"; import {useTitle} from "@/app/hooks/useTitle"; import {usePrefetchThumbnails} from "@/app/hooks/useThumbnails"; +import {Stats} from "@/app/ts/Stats"; import BuildIcon from "@mui/icons-material/Build"; import RateReviewIcon from "@mui/icons-material/RateReview"; import SpeedIcon from "@mui/icons-material/Speed"; @@ -27,13 +28,17 @@ export default function Home() { const [mapfixes, setMapfixes] = useState(null); const [submissions, setSubmissions] = useState(null); + const [stats, setStats] = useState(null); const [isLoadingMapfixes, setIsLoadingMapfixes] = useState(false); const [isLoadingSubmissions, setIsLoadingSubmissions] = useState(false); + const [isLoadingStats, setIsLoadingStats] = useState(false); + const [currentStatIndex, setCurrentStatIndex] = useState(0); const itemsPerSection: number = 8; useEffect(() => { const mapfixController = new AbortController(); const submissionsController = new AbortController(); + const statsController = new AbortController(); async function fetchMapFixes(): Promise { setIsLoadingMapfixes(true); @@ -69,15 +74,42 @@ export default function Home() { } } + async function fetchStats(): Promise { + setIsLoadingStats(true); + try { + const res = await fetch(`/api/stats`, { + signal: statsController.signal, + }); + if (res.ok) { + const data: Stats = await res.json(); + setStats(data); + } + } catch (error) { + console.error("Failed to fetch stats:", error); + } finally { + setIsLoadingStats(false); + } + } + fetchMapFixes(); fetchSubmissions(); + fetchStats(); return () => { mapfixController.abort(); submissionsController.abort(); + statsController.abort(); }; }, []); + // Cycle through featured stats every 3 seconds + useEffect(() => { + const interval = setInterval(() => { + setCurrentStatIndex((prev) => (prev + 1) % 6); + }, 3000); + return () => clearInterval(interval); + }, []); + // Prefetch thumbnails for all items to batch them together const allItems = [ ...(mapfixes?.Mapfixes || []).map((m: MapfixInfo) => ({ assetId: m.AssetID, userId: m.Submitter })), @@ -85,9 +117,9 @@ export default function Home() { ]; usePrefetchThumbnails(allItems); - const isLoading: boolean = isLoadingMapfixes || isLoadingSubmissions; + const isLoading: boolean = isLoadingMapfixes || isLoadingSubmissions || isLoadingStats; - if (isLoading && (!mapfixes || !submissions)) { + if (isLoading && (!mapfixes || !submissions || !stats)) { return ); - const totalSubmissions = submissions?.Total || 0; - const totalMapfixes = mapfixes?.Total || 0; + // Get stats from API + const totalSubmissions = stats?.TotalSubmissions || 0; + const totalMapfixes = stats?.TotalMapfixes || 0; + const releasedSubmissions = stats?.ReleasedSubmissions || 0; + const releasedMapfixes = stats?.ReleasedMapfixes || 0; + const submittedSubmissions = stats?.SubmittedSubmissions || 0; + const submittedMapfixes = stats?.SubmittedMapfixes || 0; - // Calculate useful stats from the data - const releasedSubmissions = submissions?.Submissions.filter(s => s.StatusID === SubmissionStatus.Released).length || 0; - const releasedMapfixes = mapfixes?.Mapfixes.filter(m => m.StatusID === MapfixStatus.Released).length || 0; - const totalReleased = releasedSubmissions + releasedMapfixes; + // Define all stats for cycling + const allStats = [ + { + icon: , + value: totalSubmissions, + label: 'Total Submissions', + sublabel: 'Total maps submitted by the community', + color: '#3b82f6', + gradient: 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)', + }, + { + icon: , + value: totalMapfixes, + label: 'Total Map Fixes', + sublabel: 'Total map fixes submitted by the community', + color: '#8b5cf6', + gradient: 'linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)', + }, + { + icon: , + value: releasedSubmissions + releasedMapfixes, + label: 'Total Released', + sublabel: 'Maps & fixes that have been released to the game', + color: '#10b981', + gradient: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', + }, + { + icon: , + value: releasedSubmissions, + label: 'Released Submissions', + sublabel: 'Approved maps that have been published to the game', + color: '#10b981', + gradient: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', + }, + { + icon: , + value: releasedMapfixes, + label: 'Released Fixes', + sublabel: 'Approved fixes that have been released to the game', + color: '#059669', + gradient: 'linear-gradient(135deg, #059669 0%, #047857 100%)', + }, + { + icon: , + value: submittedSubmissions + submittedMapfixes, + label: 'Under Review', + sublabel: 'Pending approval fixes & submissions', + color: '#f59e0b', + gradient: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', + }, + ]; - const underReviewSubmissions = submissions?.Submissions.filter(s => s.StatusID === SubmissionStatus.Submitted).length || 0; - const underReviewMapfixes = mapfixes?.Mapfixes.filter(m => m.StatusID === MapfixStatus.Submitted).length || 0; - const totalUnderReview = underReviewSubmissions + underReviewMapfixes; + const currentStat = allStats[currentStatIndex]; return ( @@ -162,96 +244,173 @@ export default function Home() { display: 'flex', alignItems: 'center', overflow: 'hidden', - background: 'linear-gradient(to bottom, #0a0a0a 0%, #0f0f0f 100%)', + background: 'radial-gradient(ellipse at top, #0f1419 0%, #0a0a0a 50%, #000000 100%)', }} > - {/* Subtle Gradient Background */} + {/* Animated Background Elements */} - - + {/* Subtle Grid Overlay */} + + + {/* Accent Lines */} + + + + + {/* Main Headline */} - - + Welcome to the Community + + + StrafesNET - - + + - Community Maps - - + Community Maps Hub + - {/* Subheadline */} - - Submit your custom maps, map fixes, and shape the future of StrafesNET maps - + + Create, test, and improve maps for the StrafesNET community. + Submit your creations or help fix existing maps. + + - {/* CTA Buttons */} + {/* CTA Buttons - Moved up for better hierarchy */} - {/* Stats Cards */} + {/* Stats Section - Completely Redesigned */} - {[ - { - icon: , - value: totalSubmissions, - label: 'Total Maps', - color: '#3b82f6', - }, - { - icon: , - value: totalMapfixes, - label: 'Map Fixes', - color: '#8b5cf6', - }, - { - icon: , - value: totalReleased, - label: 'Released', - color: '#10b981', - }, - { - icon: , - value: totalUnderReview, - label: 'In Review', - color: '#f59e0b', - }, - ].map((stat, index) => ( - + {allStats.map((stat, index) => ( + setCurrentStatIndex(index)} + sx={{ + position: 'relative', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + gap: 1.5, + p: { xs: 2.5, md: 3 }, + cursor: 'pointer', + background: currentStatIndex === index + ? `linear-gradient(135deg, ${stat.color}15 0%, ${stat.color}08 100%)` + : 'rgba(17, 17, 17, 0.4)', + backdropFilter: 'blur(10px)', + border: currentStatIndex === index + ? `1px solid ${stat.color}40` + : '1px solid rgba(255, 255, 255, 0.05)', + borderRadius: 3, + transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)', + '&::before': currentStatIndex === index ? { + content: '""', + position: 'absolute', + inset: -1, + background: stat.gradient, + borderRadius: 3, + opacity: 0.1, + zIndex: -1, + } : {}, + '&:hover': { + transform: 'translateY(-8px) scale(1.02)', + background: `linear-gradient(135deg, ${stat.color}20 0%, ${stat.color}10 100%)`, + borderColor: `${stat.color}60`, + boxShadow: `0 20px 40px ${stat.color}30`, + }, + }} + > + {/* Icon */} + + {React.cloneElement(stat.icon, { + sx: { fontSize: { xs: 28, md: 32 } } + })} + + + {/* Value */} + + {stat.value} + + + {/* Label */} + + {stat.label} + + + ))} + + + {/* Featured Stat Description */} + + - - {stat.icon} - - - {stat.value} - - - {stat.label} - - - ))} + {currentStat.sublabel} + + diff --git a/web/src/app/submit/page.tsx b/web/src/app/submit/page.tsx index 957e27f..6f2608c 100644 --- a/web/src/app/submit/page.tsx +++ b/web/src/app/submit/page.tsx @@ -15,7 +15,7 @@ import SendIcon from '@mui/icons-material/Send'; import NavigateNextIcon from '@mui/icons-material/NavigateNext'; import Webpage from "@/app/_components/webpage"; import GameSelection from "./_game"; -import { Link } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import {useTitle} from "@/app/hooks/useTitle"; interface SubmissionPayload { @@ -27,6 +27,7 @@ interface SubmissionPayload { export default function SubmitPage() { useTitle("Submit"); + const navigate = useNavigate(); const [game, setGame] = useState(1); const [isSubmitting, setIsSubmitting] = useState(false); @@ -71,7 +72,7 @@ export default function SubmitPage() { } const { OperationID } = await response.json(); - window.location.assign(`/operations/${OperationID}`); + navigate(`/operations/${OperationID}`); } catch (error) { console.error("Error submitting data:", error); setError(error instanceof Error ? error.message : "An unknown error occurred"); diff --git a/web/src/app/ts/Stats.ts b/web/src/app/ts/Stats.ts new file mode 100644 index 0000000..33d6baf --- /dev/null +++ b/web/src/app/ts/Stats.ts @@ -0,0 +1,10 @@ +interface Stats { + readonly TotalSubmissions: number; + readonly TotalMapfixes: number; + readonly ReleasedSubmissions: number; + readonly ReleasedMapfixes: number; + readonly SubmittedSubmissions: number; + readonly SubmittedMapfixes: number; +} + +export type { Stats }; -- 2.49.1 From 7589ef7df6c8c4c6dc8219d5e4d94d79ff26293d Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 19:49:06 -0500 Subject: [PATCH 14/23] Fix dockerfile for spa --- web/Containerfile | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/web/Containerfile b/web/Containerfile index 8cf5dd7..824e2bb 100644 --- a/web/Containerfile +++ b/web/Containerfile @@ -1,13 +1,29 @@ -FROM registry.itzana.me/docker-proxy/oven/bun:1.3.3 +# Build stage +FROM registry.itzana.me/docker-proxy/oven/bun:1.3.3 AS builder WORKDIR /app +COPY package.json bun.lockb* ./ +RUN bun install --frozen-lockfile + COPY . . - -EXPOSE 3000 - -ENV NEXT_TELEMETRY_DISABLED=1 - -RUN bun install RUN bun run build -ENTRYPOINT ["bun", "run", "start"] + +# Release +FROM registry.itzana.me/docker-proxy/nginx:alpine + +COPY --from=builder /app/dist /usr/share/nginx/html + +# Add nginx configuration for SPA routing +RUN echo 'server { \ + listen 80; \ + location / { \ + root /usr/share/nginx/html; \ + index index.html; \ + try_files $uri $uri/ /index.html; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] -- 2.49.1 From b50c84f8cf55175950a775a7e5f3b55d9ae40da0 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 19:49:52 -0500 Subject: [PATCH 15/23] Use port 3000 --- web/Containerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/Containerfile b/web/Containerfile index 824e2bb..d444c44 100644 --- a/web/Containerfile +++ b/web/Containerfile @@ -16,7 +16,7 @@ COPY --from=builder /app/dist /usr/share/nginx/html # Add nginx configuration for SPA routing RUN echo 'server { \ - listen 80; \ + listen 3000; \ location / { \ root /usr/share/nginx/html; \ index index.html; \ @@ -24,6 +24,6 @@ RUN echo 'server { \ } \ }' > /etc/nginx/conf.d/default.conf -EXPOSE 80 +EXPOSE 3000 CMD ["nginx", "-g", "daemon off;"] -- 2.49.1 From 30db1cc3757d7aef795ca57e7e757554b051f849 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 19:52:01 -0500 Subject: [PATCH 16/23] Fix the build issues --- web/Containerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/Containerfile b/web/Containerfile index d444c44..211544a 100644 --- a/web/Containerfile +++ b/web/Containerfile @@ -12,7 +12,7 @@ RUN bun run build # Release FROM registry.itzana.me/docker-proxy/nginx:alpine -COPY --from=builder /app/dist /usr/share/nginx/html +COPY --from=builder /app/build /usr/share/nginx/html # Add nginx configuration for SPA routing RUN echo 'server { \ -- 2.49.1 From e4af76cfd4248a55cef8bafbc2bf22bd7222000b Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 20:22:24 -0500 Subject: [PATCH 17/23] Fix api endpoint --- web/src/app/admin-submit/page.tsx | 2 +- web/src/app/hooks/useReviewData.ts | 8 ++++---- web/src/app/hooks/useThumbnails.ts | 4 ++-- web/src/app/hooks/useUser.ts | 2 +- web/src/app/mapfixes/[mapfixId]/page.tsx | 4 ++-- web/src/app/mapfixes/page.tsx | 2 +- web/src/app/maps/[mapId]/fix/page.tsx | 4 ++-- web/src/app/maps/[mapId]/page.tsx | 8 ++++---- web/src/app/maps/page.tsx | 2 +- web/src/app/operations/[operationId]/page.tsx | 2 +- web/src/app/page.tsx | 6 +++--- web/src/app/submissions/[submissionId]/page.tsx | 4 ++-- web/src/app/submissions/page.tsx | 2 +- web/src/app/submit/page.tsx | 2 +- web/vite.config.ts | 4 ++-- 15 files changed, 28 insertions(+), 28 deletions(-) diff --git a/web/src/app/admin-submit/page.tsx b/web/src/app/admin-submit/page.tsx index c13dec9..67d36ab 100644 --- a/web/src/app/admin-submit/page.tsx +++ b/web/src/app/admin-submit/page.tsx @@ -41,7 +41,7 @@ export default function SubmissionInfoPage() { try { // Send the POST request - const response = await fetch("/api/submissions-admin", { + const response = await fetch("/v1/submissions-admin", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), diff --git a/web/src/app/hooks/useReviewData.ts b/web/src/app/hooks/useReviewData.ts index 1e1895b..41ad71e 100644 --- a/web/src/app/hooks/useReviewData.ts +++ b/web/src/app/hooks/useReviewData.ts @@ -40,11 +40,11 @@ export function useReviewData({itemType, itemId}: UseReviewDataProps): UseReview try { const [reviewData, auditData] = await Promise.all([ - fetch(`/api/${itemType}/${itemId}`).then(res => { + fetch(`/v1/${itemType}/${itemId}`).then(res => { if (!res.ok) throw new Error(`Failed to fetch ${itemType.slice(0, -1)}: ${res.status}`); return res.json(); }), - fetch(`/api/${itemType}/${itemId}/audit-events?Page=1&Limit=100`).then(res => { + fetch(`/v1/${itemType}/${itemId}/audit-events?Page=1&Limit=100`).then(res => { if (!res.ok) throw new Error(`Failed to fetch audit events: ${res.status}`); return res.json(); }) @@ -58,7 +58,7 @@ export function useReviewData({itemType, itemId}: UseReviewDataProps): UseReview } try { - const rolesResponse = await fetch("/api/session/roles"); + const rolesResponse = await fetch("/v1/session/roles"); if (rolesResponse.ok) { const rolesData = await rolesResponse.json(); setRoles(rolesData.Roles); @@ -72,7 +72,7 @@ export function useReviewData({itemType, itemId}: UseReviewDataProps): UseReview } try { - const userResponse = await fetch("/api/session/user"); + const userResponse = await fetch("/v1/session/user"); if (userResponse.ok) { const userData = await userResponse.json(); setUser(userData.UserID); diff --git a/web/src/app/hooks/useThumbnails.ts b/web/src/app/hooks/useThumbnails.ts index a3f3314..a367d69 100644 --- a/web/src/app/hooks/useThumbnails.ts +++ b/web/src/app/hooks/useThumbnails.ts @@ -16,7 +16,7 @@ class ThumbnailBatcher { async fetchAssetBatch(ids: number[], size: ThumbnailSize): Promise> { try { - const response = await fetch('/api/thumbnails/assets', { + const response = await fetch('/v1/thumbnails/assets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ assetIds: ids, size }), @@ -43,7 +43,7 @@ class ThumbnailBatcher { async fetchUserBatch(ids: number[], size: ThumbnailSize): Promise> { try { - const response = await fetch('/api/thumbnails/users', { + const response = await fetch('/v1/thumbnails/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userIds: ids, size }), diff --git a/web/src/app/hooks/useUser.ts b/web/src/app/hooks/useUser.ts index 405e0ea..5733d18 100644 --- a/web/src/app/hooks/useUser.ts +++ b/web/src/app/hooks/useUser.ts @@ -3,7 +3,7 @@ import { UserInfo } from '@/app/ts/User'; async function fetchUser(): Promise { try { - const response = await fetch('/api/session/user'); + const response = await fetch('/v1/session/user'); if (!response.ok) { return null; diff --git a/web/src/app/mapfixes/[mapfixId]/page.tsx b/web/src/app/mapfixes/[mapfixId]/page.tsx index 945fb19..b295be8 100644 --- a/web/src/app/mapfixes/[mapfixId]/page.tsx +++ b/web/src/app/mapfixes/[mapfixId]/page.tsx @@ -88,7 +88,7 @@ export default function MapfixDetailsPage() { // Handle review button actions async function handleReviewAction(action: string, mapfixId: number) { try { - const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, { + const response = await fetch(`/v1/mapfixes/${mapfixId}/status/${action}`, { method: "POST", headers: { "Content-type": "application/json", @@ -127,7 +127,7 @@ export default function MapfixDetailsPage() { } try { - const response = await fetch(`/api/mapfixes/${mapfixId}/comment`, { + const response = await fetch(`/v1/mapfixes/${mapfixId}/comment`, { method: 'POST', headers: { 'Content-Type': 'text/plain', diff --git a/web/src/app/mapfixes/page.tsx b/web/src/app/mapfixes/page.tsx index 3d1db45..9a51281 100644 --- a/web/src/app/mapfixes/page.tsx +++ b/web/src/app/mapfixes/page.tsx @@ -30,7 +30,7 @@ export default function MapfixInfoPage() { setIsLoading(true); try { const res = await fetch( - `/api/mapfixes?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`, + `/v1/mapfixes?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`, { signal: controller.signal } ); diff --git a/web/src/app/maps/[mapId]/fix/page.tsx b/web/src/app/maps/[mapId]/fix/page.tsx index d423303..3d85f6a 100644 --- a/web/src/app/maps/[mapId]/fix/page.tsx +++ b/web/src/app/maps/[mapId]/fix/page.tsx @@ -46,7 +46,7 @@ export default function MapfixInfoPage() { const fetchMapDetails = async () => { try { setIsLoading(true); - const response = await fetch(`/api/maps/${mapId}`); + const response = await fetch(`/v1/maps/${mapId}`); if (!response.ok) { throw new Error(`Failed to fetch map details: ${response.statusText}`); @@ -104,7 +104,7 @@ export default function MapfixInfoPage() { }; try { - const response = await fetch("/api/mapfixes", { + const response = await fetch("/v1/mapfixes", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), diff --git a/web/src/app/maps/[mapId]/page.tsx b/web/src/app/maps/[mapId]/page.tsx index d94e03d..d39c483 100644 --- a/web/src/app/maps/[mapId]/page.tsx +++ b/web/src/app/maps/[mapId]/page.tsx @@ -59,7 +59,7 @@ export default function MapDetails() { try { setLoading(true); setError(null); - const res = await fetch(`/api/maps/${mapId}`); + const res = await fetch(`/v1/maps/${mapId}`); if (!res.ok) { throw new Error(`Failed to fetch map: ${res.status}`); } @@ -78,7 +78,7 @@ export default function MapDetails() { useEffect(() => { async function getRoles() { try { - const rolesResponse = await fetch("/api/session/roles"); + const rolesResponse = await fetch("/v1/session/roles"); if (rolesResponse.ok) { const rolesData = await rolesResponse.json(); setRoles(rolesData.Roles); @@ -104,7 +104,7 @@ export default function MapDetails() { let allMapfixes: MapfixInfo[] = []; let total = 0; do { - const res = await fetch(`/api/mapfixes?Page=${page}&Limit=${limit}&TargetAssetID=${targetAssetId}`); + const res = await fetch(`/v1/mapfixes?Page=${page}&Limit=${limit}&TargetAssetID=${targetAssetId}`); if (!res.ok) break; const data = await res.json(); if (page === 1) total = data.Total; @@ -304,7 +304,7 @@ export default function MapDetails() { diff --git a/web/src/app/maps/page.tsx b/web/src/app/maps/page.tsx index b47f1e6..44ff5cf 100644 --- a/web/src/app/maps/page.tsx +++ b/web/src/app/maps/page.tsx @@ -147,7 +147,7 @@ export default function MapsPage() { let hasMore = true; while (hasMore) { - const res = await fetch(`/api/maps?Page=${page}&Limit=${requestPageSize}`); + const res = await fetch(`/v1/maps?Page=${page}&Limit=${requestPageSize}`); const data: Map[] = await res.json(); allMaps = [...allMaps, ...data]; hasMore = data.length === requestPageSize; diff --git a/web/src/app/operations/[operationId]/page.tsx b/web/src/app/operations/[operationId]/page.tsx index 346142a..d19d570 100644 --- a/web/src/app/operations/[operationId]/page.tsx +++ b/web/src/app/operations/[operationId]/page.tsx @@ -112,7 +112,7 @@ export default function OperationStatusPage() { const fetchOperation = async () => { try { - const response = await fetch(`/api/operations/${operationId}`); + const response = await fetch(`/v1/operations/${operationId}`); if (!response.ok) throw new Error("Failed to fetch operation"); diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 9208ff3..a5a9acc 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -43,7 +43,7 @@ export default function Home() { async function fetchMapFixes(): Promise { setIsLoadingMapfixes(true); try { - const res = await fetch(`/api/mapfixes?Page=1&Limit=${itemsPerSection}&Sort=${ListSortConstants.ListSortDateDescending}`, { + const res = await fetch(`/v1/mapfixes?Page=1&Limit=${itemsPerSection}&Sort=${ListSortConstants.ListSortDateDescending}`, { signal: mapfixController.signal, }); if (res.ok) { @@ -60,7 +60,7 @@ export default function Home() { async function fetchSubmissions(): Promise { setIsLoadingSubmissions(true); try { - const res = await fetch(`/api/submissions?Page=1&Limit=${itemsPerSection}&Sort=${ListSortConstants.ListSortDateDescending}`, { + const res = await fetch(`/v1/submissions?Page=1&Limit=${itemsPerSection}&Sort=${ListSortConstants.ListSortDateDescending}`, { signal: submissionsController.signal, }); if (res.ok) { @@ -77,7 +77,7 @@ export default function Home() { async function fetchStats(): Promise { setIsLoadingStats(true); try { - const res = await fetch(`/api/stats`, { + const res = await fetch(`/v1/stats`, { signal: statsController.signal, }); if (res.ok) { diff --git a/web/src/app/submissions/[submissionId]/page.tsx b/web/src/app/submissions/[submissionId]/page.tsx index aee9d6c..84c6c76 100644 --- a/web/src/app/submissions/[submissionId]/page.tsx +++ b/web/src/app/submissions/[submissionId]/page.tsx @@ -85,7 +85,7 @@ export default function SubmissionDetailsPage() { // Handle review button actions async function handleReviewAction(action: string, submissionId: number) { try { - const response = await fetch(`/api/submissions/${submissionId}/status/${action}`, { + const response = await fetch(`/v1/submissions/${submissionId}/status/${action}`, { method: "POST", headers: { "Content-type": "application/json", @@ -124,7 +124,7 @@ export default function SubmissionDetailsPage() { } try { - const response = await fetch(`/api/submissions/${submissionId}/comment`, { + const response = await fetch(`/v1/submissions/${submissionId}/comment`, { method: 'POST', headers: { 'Content-Type': 'text/plain', diff --git a/web/src/app/submissions/page.tsx b/web/src/app/submissions/page.tsx index 877dd3f..dcb756f 100644 --- a/web/src/app/submissions/page.tsx +++ b/web/src/app/submissions/page.tsx @@ -30,7 +30,7 @@ export default function SubmissionInfoPage() { setIsLoading(true); try { const res = await fetch( - `/api/submissions?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`, + `/v1/submissions?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`, { signal: controller.signal } ); diff --git a/web/src/app/submit/page.tsx b/web/src/app/submit/page.tsx index 6f2608c..35df582 100644 --- a/web/src/app/submit/page.tsx +++ b/web/src/app/submit/page.tsx @@ -60,7 +60,7 @@ export default function SubmitPage() { }; try { - const response = await fetch("/api/submissions", { + const response = await fetch("/v1/submissions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), diff --git a/web/vite.config.ts b/web/vite.config.ts index 37c7e98..07fc010 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -12,10 +12,10 @@ export default defineConfig({ server: { port: 3000, proxy: { - '/api': { + '/v1': { target: process.env.VITE_API_HOST || 'http://localhost:8080', changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ''), + rewrite: (path) => path.replace(/^\/v1/, ''), }, }, }, -- 2.49.1 From e5277c05a1e5b105528f68b6a9c520a4fbcb6fe3 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 20:38:17 -0500 Subject: [PATCH 18/23] Avatar image loading --- .../_components/comments/AuditEventItem.tsx | 38 ++++++-- .../comments/AuditEventsTabPanel.tsx | 27 +++--- .../app/_components/comments/CommentItem.tsx | 38 ++++++-- .../_components/comments/CommentsTabPanel.tsx | 86 ++++++++++++------- .../_components/review/ReviewItemHeader.tsx | 30 +++++-- web/vite.config.ts | 1 - 6 files changed, 157 insertions(+), 63 deletions(-) diff --git a/web/src/app/_components/comments/AuditEventItem.tsx b/web/src/app/_components/comments/AuditEventItem.tsx index 552ba18..052549f 100644 --- a/web/src/app/_components/comments/AuditEventItem.tsx +++ b/web/src/app/_components/comments/AuditEventItem.tsx @@ -2,11 +2,13 @@ import { Box, Avatar, Typography, - Tooltip + Tooltip, + Skeleton } from "@mui/material"; import PersonIcon from '@mui/icons-material/Person'; import { formatDistanceToNow, format } from "date-fns"; import { AuditEvent, decodeAuditEvent as auditEventMessage } from "@/app/ts/AuditEvent"; +import { useUserThumbnail } from "@/app/hooks/useThumbnails"; interface AuditEventItemProps { event: AuditEvent; @@ -14,17 +16,39 @@ interface AuditEventItemProps { } export default function AuditEventItem({ event, validatorUser }: AuditEventItemProps) { + const isValidator = event.User === validatorUser; + const { thumbnailUrl, isLoading } = useUserThumbnail(isValidator ? undefined : event.User, '150x150'); + return ( - - - + + + + + + - {event.User === validatorUser ? "Validator" : event.Username || "Unknown"} + {isValidator ? "Validator" : event.Username || "Unknown"} diff --git a/web/src/app/_components/comments/AuditEventsTabPanel.tsx b/web/src/app/_components/comments/AuditEventsTabPanel.tsx index 8a17699..8bd49b0 100644 --- a/web/src/app/_components/comments/AuditEventsTabPanel.tsx +++ b/web/src/app/_components/comments/AuditEventsTabPanel.tsx @@ -21,18 +21,21 @@ export default function AuditEventsTabPanel({ ); return ( - ); } \ No newline at end of file diff --git a/web/src/app/maps/page.tsx b/web/src/app/maps/page.tsx index 44ff5cf..266f0e0 100644 --- a/web/src/app/maps/page.tsx +++ b/web/src/app/maps/page.tsx @@ -13,7 +13,6 @@ import { TextField, InputAdornment, Pagination, - CircularProgress, FormControl, InputLabel, Select, @@ -291,9 +290,27 @@ export default function MapsPage() { /> {loading ? ( - - - + + {Array.from({ length: mapsPerPage }).map((_, index) => ( + + + + + + + + + + + ))} + ) : ( <> diff --git a/web/src/app/submissions/page.tsx b/web/src/app/submissions/page.tsx index dcb756f..ff91722 100644 --- a/web/src/app/submissions/page.tsx +++ b/web/src/app/submissions/page.tsx @@ -6,9 +6,11 @@ import { ListSortConstants } from "../ts/Sort"; import { Box, Breadcrumbs, - CircularProgress, + Card, + CardContent, Container, Pagination, + Skeleton, Typography } from "@mui/material"; import { Link } from "react-router-dom"; @@ -53,24 +55,10 @@ export default function SubmissionInfoPage() { return () => controller.abort(); }, [currentPage]); - if (isLoading || !submissions) { - return ( - - - - - - Loading submissions... - - - - - ); - } + const skeletonCards = Array.from({ length: cardsPerPage }, (_, i) => i); + const totalPages = submissions ? Math.ceil(submissions.Total / cardsPerPage) : 0; - const totalPages = Math.ceil(submissions.Total / cardsPerPage); - - if (submissions.Total === 0) { + if (submissions && submissions.Total === 0) { return ( @@ -84,8 +72,14 @@ export default function SubmissionInfoPage() { return ( - - + + } aria-label="breadcrumb" @@ -119,21 +113,41 @@ export default function SubmissionInfoPage() { width: '100%', }} > - {submissions.Submissions.map((submission) => ( - - ))} + {!submissions || isLoading ? ( + skeletonCards.map((i) => ( + + + + + + + + + + + + + + + + )) + ) : ( + submissions.Submissions.map((submission) => ( + + )) + )} {totalPages > 1 && ( @@ -148,7 +162,7 @@ export default function SubmissionInfoPage() { )} - + ); } \ No newline at end of file -- 2.49.1 From 7db89fd99b381aa911037c11495adea9a9455824 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 25 Dec 2025 22:10:29 -0500 Subject: [PATCH 23/23] Fix bun lock file --- web/bun.lock | 672 +++++++++++---------------------------------------- 1 file changed, 144 insertions(+), 528 deletions(-) diff --git a/web/bun.lock b/web/bun.lock index 428f430..7aa1b58 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -9,10 +9,11 @@ "@emotion/styled": "^11.14.1", "@mui/icons-material": "^7.3.6", "@mui/material": "^7.3.6", + "@tanstack/react-query": "^5.90.12", "date-fns": "^4.1.0", - "next": "^16.0.7", "react": "^19.2.1", "react-dom": "^19.2.1", + "react-router-dom": "^7.1.3", "sass": "^1.94.2", }, "devDependencies": { @@ -20,9 +21,10 @@ "@types/node": "^24.10.1", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^4.3.4", "eslint": "^9.39.1", - "eslint-config-next": "16.0.7", "typescript": "^5.9.3", + "vite": "^6.0.7", }, }, }, @@ -43,6 +45,8 @@ "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], @@ -51,7 +55,11 @@ "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.27.0", "", { "dependencies": { "@babel/types": "^7.27.0" }, "bin": "./bin/babel-parser.js" }, "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], "@babel/runtime": ["@babel/runtime@7.27.0", "", { "dependencies": { "regenerator-runtime": "^0.14.0" } }, "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw=="], @@ -61,12 +69,6 @@ "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], - "@emnapi/core": ["@emnapi/core@1.4.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.1", "tslib": "^2.4.0" } }, "sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg=="], - - "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], - - "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw=="], - "@emotion/babel-plugin": ["@emotion/babel-plugin@11.13.5", "", { "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ=="], "@emotion/cache": ["@emotion/cache@11.14.0", "", { "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA=="], @@ -93,6 +95,58 @@ "@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], @@ -119,56 +173,6 @@ "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.2", "", {}, "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ=="], - "@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="], - - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], - - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], - - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], - - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], - - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], - - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], - - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], - - "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], - - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], - - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], - - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], - - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], - - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], - - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], - - "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], - - "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], - - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], - - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], - - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], - - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], - - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], - - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], - - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], - - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], - "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], @@ -197,36 +201,6 @@ "@mui/utils": ["@mui/utils@7.3.6", "", { "dependencies": { "@babel/runtime": "^7.28.4", "@mui/types": "^7.4.9", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^19.2.0" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-jn+Ba02O6PiFs7nKva8R2aJJ9kJC+3kQ2R0BbKNY3KQQ36Qng98GnPRFTlbwYTdMD6hLEBKaMLUktyg/rTfd2w=="], - "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.8", "", { "dependencies": { "@emnapi/core": "^1.4.0", "@emnapi/runtime": "^1.4.0", "@tybys/wasm-util": "^0.9.0" } }, "sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg=="], - - "@next/env": ["@next/env@16.0.7", "", {}, "sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw=="], - - "@next/eslint-plugin-next": ["@next/eslint-plugin-next@16.0.7", "", { "dependencies": { "fast-glob": "3.3.1" } }, "sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA=="], - - "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.0.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg=="], - - "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.0.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA=="], - - "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww=="], - - "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.0.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g=="], - - "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA=="], - - "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.0.7", "", { "os": "linux", "cpu": "x64" }, "sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w=="], - - "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.0.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q=="], - - "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.0.7", "", { "os": "win32", "cpu": "x64" }, "sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug=="], - - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - - "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], - "@parcel/watcher": ["@parcel/watcher@2.5.1", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-android-arm64": "2.5.1", "@parcel/watcher-darwin-arm64": "2.5.1", "@parcel/watcher-darwin-x64": "2.5.1", "@parcel/watcher-freebsd-x64": "2.5.1", "@parcel/watcher-linux-arm-glibc": "2.5.1", "@parcel/watcher-linux-arm-musl": "2.5.1", "@parcel/watcher-linux-arm64-glibc": "2.5.1", "@parcel/watcher-linux-arm64-musl": "2.5.1", "@parcel/watcher-linux-x64-glibc": "2.5.1", "@parcel/watcher-linux-x64-musl": "2.5.1", "@parcel/watcher-win32-arm64": "2.5.1", "@parcel/watcher-win32-ia32": "2.5.1", "@parcel/watcher-win32-x64": "2.5.1" } }, "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg=="], "@parcel/watcher-android-arm64": ["@parcel/watcher-android-arm64@2.5.1", "", { "os": "android", "cpu": "arm64" }, "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA=="], @@ -257,18 +231,68 @@ "@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="], - "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.27", "", {}, "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA=="], - "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.54.0", "", { "os": "android", "cpu": "arm" }, "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng=="], - "@tybys/wasm-util": ["@tybys/wasm-util@0.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw=="], + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.54.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.54.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.54.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.54.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.54.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.54.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.54.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.54.0", "", { "os": "none", "cpu": "arm64" }, "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.54.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.54.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg=="], + + "@tanstack/query-core": ["@tanstack/query-core@5.90.12", "", {}, "sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg=="], + + "@tanstack/react-query": ["@tanstack/react-query@5.90.12", "", { "dependencies": { "@tanstack/query-core": "5.90.12" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], - "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], - "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], @@ -281,55 +305,7 @@ "@types/react-transition-group": ["@types/react-transition-group@4.4.12", "", { "peerDependencies": { "@types/react": "*" } }, "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.48.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/type-utils": "8.48.1", "@typescript-eslint/utils": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.48.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.48.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.48.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.48.1", "@typescript-eslint/types": "^8.48.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1" } }, "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.48.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/utils": "8.48.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.48.1", "", {}, "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.48.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.48.1", "@typescript-eslint/tsconfig-utils": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.48.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q=="], - - "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-EpRILdWr3/xDa/7MoyfO7JuBIJqpBMphtu4+80BK1bRfFcniVT74h3Z7q1+WOc92FuIAYatB1vn9TJR67sORGw=="], - - "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-ntj/g7lPyqwinMJWZ+DKHBse8HhVxswGTmNgFKJtdgGub3M3zp5BSZ3bvMP+kBT6dnYJLSVlDqdwOq1P8i0+/g=="], - - "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.3.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-l6BT8f2CU821EW7U8hSUK8XPq4bmyTlt9Mn4ERrfjJNoCw0/JoHAh9amZZtV3cwC3bwwIat+GUnrcHTG9+qixw=="], - - "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-8ScEc5a4y7oE2BonRvzJ+2GSkBaYWyh0/Ko4Q25e/ix6ANpJNhwEPZvCR6GVRmsQAYMIfQvYLdM6YEN+qRjnAQ=="], - - "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-8qQ6l1VTzLNd3xb2IEXISOKwMGXDCzY/UNy/7SovFW2Sp0K3YbL7Ao7R18v6SQkLqQlhhqSBIFRk+u6+qu5R5A=="], - - "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-v81R2wjqcWXJlQY23byqYHt9221h4anQ6wwN64oMD/WAE+FmxPHFZee5bhRkNVtzqO/q7wki33VFWlhiADwUeQ=="], - - "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-cAOx/j0u5coMg4oct/BwMzvWJdVciVauUvsd+GQB/1FZYKQZmqPy0EjJzJGbVzFc6gbnfEcSqvQE6gvbGf2N8Q=="], - - "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.3.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-mq2blqwErgDJD4gtFDlTX/HZ7lNP8YCHYFij2gkXPtMzrXxPW1hOtxL6xg4NWxvnj4bppppb0W3s/buvM55yfg=="], - - "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.3.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-u0VRzfFYysarYHnztj2k2xr+eu9rmgoTUUgCCIT37Nr+j0A05Xk2c3RY8Mh5+DhCl2aYibihnaAEJHeR0UOFIQ=="], - - "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-OrVo5ZsG29kBF0Ug95a2KidS16PqAMmQNozM6InbquOfW/udouk063e25JVLqIBhHLB2WyBnixOQ19tmeC/hIg=="], - - "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-PYnmrwZ4HMp9SkrOhqPghY/aoL+Rtd4CQbr93GlrRTjK6kDzfMfgz3UH3jt6elrQAfupa1qyr1uXzeVmoEAxUA=="], - - "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.3.3", "", { "dependencies": { "@napi-rs/wasm-runtime": "^0.2.7" }, "cpu": "none" }, "sha512-81AnQY6fShmktQw4hWDUIilsKSdvr/acdJ5azAreu2IWNlaJOKphJSsUVWE+yCk6kBMoQyG9ZHCb/krb5K0PEA=="], - - "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-X/42BMNw7cW6xrB9syuP5RusRnWGoq+IqvJO8IDpp/BZg64J1uuIW6qA/1Cl13Y4LyLXbJVYbYNSKwR/FiHEng=="], - - "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.3.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-EGNnNGQxMU5aTN7js3ETYvuw882zcO+dsVjs+DwO2j/fRVKth87C8e2GzxW1L3+iWAXMyJhvFBKRavk9Og1Z6A=="], - - "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-GraLbYqOJcmW1qY3osB+2YIiD62nVf2/bVLHZmrb4t/YSUwE03l7TwcDJl08T/Tm3SVhepX8RQkpzWbag/Sb4w=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], @@ -341,34 +317,6 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], - - "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], - - "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], - - "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], - - "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], - - "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], - - "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], - - "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], - - "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - - "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], - - "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - - "axe-core": ["axe-core@4.10.3", "", {}, "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg=="], - - "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], - "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -381,12 +329,6 @@ "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], - - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - - "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "caniuse-lite": ["caniuse-lite@1.0.30001759", "", {}, "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw=="], @@ -395,8 +337,6 @@ "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], - "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -405,7 +345,9 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], - "convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], "cosmiconfig": ["cosmiconfig@7.1.0", "", { "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" } }, "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA=="], @@ -413,53 +355,21 @@ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], - "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], - - "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], - - "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], - - "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - "date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="], "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], - - "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - - "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + "detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="], - "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "electron-to-chromium": ["electron-to-chromium@1.5.266", "", {}, "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg=="], - "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], - "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], - - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], - - "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - - "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], - - "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], - - "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - - "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], - - "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -467,22 +377,6 @@ "eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="], - "eslint-config-next": ["eslint-config-next@16.0.7", "", { "dependencies": { "@next/eslint-plugin-next": "16.0.7", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsx-a11y": "^6.10.0", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^7.0.0", "globals": "16.4.0", "typescript-eslint": "^8.46.0" }, "peerDependencies": { "eslint": ">=9.0.0", "typescript": ">=3.3.1" }, "optionalPeers": ["typescript"] }, "sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ=="], - - "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", "resolve": "^1.22.4" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], - - "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.0", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "^4.4.0", "get-tsconfig": "^4.10.0", "is-bun-module": "^2.0.0", "stable-hash": "^0.0.5", "tinyglobby": "^0.2.12", "unrs-resolver": "^1.3.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-aV3/dVsT0/H9BtpNwbaqvl+0xGMRGzncLyhm793NFGvbwGGvzyAykqWZ8oZlZuGwuHkwJjhWJkG1cM3ynvd2pQ=="], - - "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "^3.2.7" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], - - "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", "array.prototype.findlastindex": "^1.2.6", "array.prototype.flat": "^1.3.3", "array.prototype.flatmap": "^1.3.3", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", "eslint-module-utils": "^2.12.1", "hasown": "^2.0.2", "is-core-module": "^2.16.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "object.groupby": "^1.0.3", "object.values": "^1.2.1", "semver": "^6.3.1", "string.prototype.trimend": "^1.0.9", "tsconfig-paths": "^3.15.0" }, "peerDependencies": { "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], - - "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], - - "eslint-plugin-react": ["eslint-plugin-react@7.37.4", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ=="], - - "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.0.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "hermes-parser": "^0.25.1", "zod": "^3.25.0 || ^4.0.0", "zod-validation-error": "^3.5.0 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA=="], - "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], @@ -499,15 +393,11 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - - "fdir": ["fdir@6.4.3", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], @@ -521,52 +411,20 @@ "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], - - "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], - "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], - "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], - - "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - - "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - - "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], - - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - - "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], - - "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], - - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], - - "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], - "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - "hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], - - "hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], - "hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -577,68 +435,18 @@ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], - "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - - "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], - - "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], - - "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], - - "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "^7.7.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], - - "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], - - "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - - "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], - - "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], - - "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - - "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], - - "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], - - "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], - - "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], - - "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], - - "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], @@ -653,16 +461,10 @@ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], - "json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], - - "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - "language-subtag-registry": ["language-subtag-registry@0.3.23", "", {}, "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ=="], - - "language-tags": ["language-tags@1.0.9", "", { "dependencies": { "language-subtag-registry": "^0.3.20" } }, "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA=="], - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], @@ -675,48 +477,24 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], - "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], - - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], - "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], - "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - "next": ["next@16.0.7", "", { "dependencies": { "@next/env": "16.0.7", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.0.7", "@next/swc-darwin-x64": "16.0.7", "@next/swc-linux-arm64-gnu": "16.0.7", "@next/swc-linux-arm64-musl": "16.0.7", "@next/swc-linux-x64-gnu": "16.0.7", "@next/swc-linux-x64-musl": "16.0.7", "@next/swc-win32-arm64-msvc": "16.0.7", "@next/swc-win32-x64-msvc": "16.0.7", "sharp": "^0.34.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A=="], - "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], - "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - - "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - - "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - - "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], - - "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], - - "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], - - "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -735,11 +513,9 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - - "postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], @@ -747,39 +523,29 @@ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "react": ["react@19.2.1", "", {}, "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw=="], "react-dom": ["react-dom@19.2.1", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.1" } }, "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg=="], "react-is": ["react-is@19.2.1", "", {}, "sha512-L7BnWgRbMwzMAubQcS7sXdPdNLmKlucPlopgAzx7FtYbksWZgEWiuYM5x9T6UqS2Ne0rsgQTq5kY2SGqpzUkYA=="], + "react-refresh": ["react-refresh@0.17.0", "", {}, "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ=="], + + "react-router": ["react-router@7.11.0", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ=="], + + "react-router-dom": ["react-router-dom@7.11.0", "", { "dependencies": { "react-router": "7.11.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g=="], + "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], - "regenerator-runtime": ["regenerator-runtime@0.14.1", "", {}, "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="], - "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], - - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - - "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], - - "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], - - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + "rollup": ["rollup@4.54.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.54.0", "@rollup/rollup-android-arm64": "4.54.0", "@rollup/rollup-darwin-arm64": "4.54.0", "@rollup/rollup-darwin-x64": "4.54.0", "@rollup/rollup-freebsd-arm64": "4.54.0", "@rollup/rollup-freebsd-x64": "4.54.0", "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", "@rollup/rollup-linux-arm-musleabihf": "4.54.0", "@rollup/rollup-linux-arm64-gnu": "4.54.0", "@rollup/rollup-linux-arm64-musl": "4.54.0", "@rollup/rollup-linux-loong64-gnu": "4.54.0", "@rollup/rollup-linux-ppc64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-musl": "4.54.0", "@rollup/rollup-linux-s390x-gnu": "4.54.0", "@rollup/rollup-linux-x64-gnu": "4.54.0", "@rollup/rollup-linux-x64-musl": "4.54.0", "@rollup/rollup-openharmony-arm64": "4.54.0", "@rollup/rollup-win32-arm64-msvc": "4.54.0", "@rollup/rollup-win32-ia32-msvc": "4.54.0", "@rollup/rollup-win32-x64-gnu": "4.54.0", "@rollup/rollup-win32-x64-msvc": "4.54.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw=="], "sass": ["sass@1.94.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A=="], @@ -787,102 +553,42 @@ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - - "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], - - "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], - - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], - "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], - - "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], - - "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], - - "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], - "source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], - - "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], - - "string.prototype.includes": ["string.prototype.includes@2.0.1", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3" } }, "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg=="], - - "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], - - "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], - - "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], - - "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], - - "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], - - "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], - "stylis": ["stylis@4.2.0", "", {}, "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="], "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "tinyglobby": ["tinyglobby@0.2.12", "", { "dependencies": { "fdir": "^6.4.3", "picomatch": "^4.0.2" } }, "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww=="], + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - - "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], - - "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], - - "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], - - "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], - - "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "typescript-eslint": ["typescript-eslint@8.48.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.48.1", "@typescript-eslint/parser": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/utils": "8.48.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A=="], - - "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], - "unrs-resolver": ["unrs-resolver@1.3.3", "", { "optionalDependencies": { "@unrs/resolver-binding-darwin-arm64": "1.3.3", "@unrs/resolver-binding-darwin-x64": "1.3.3", "@unrs/resolver-binding-freebsd-x64": "1.3.3", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.3.3", "@unrs/resolver-binding-linux-arm-musleabihf": "1.3.3", "@unrs/resolver-binding-linux-arm64-gnu": "1.3.3", "@unrs/resolver-binding-linux-arm64-musl": "1.3.3", "@unrs/resolver-binding-linux-ppc64-gnu": "1.3.3", "@unrs/resolver-binding-linux-s390x-gnu": "1.3.3", "@unrs/resolver-binding-linux-x64-gnu": "1.3.3", "@unrs/resolver-binding-linux-x64-musl": "1.3.3", "@unrs/resolver-binding-wasm32-wasi": "1.3.3", "@unrs/resolver-binding-win32-arm64-msvc": "1.3.3", "@unrs/resolver-binding-win32-ia32-msvc": "1.3.3", "@unrs/resolver-binding-win32-x64-msvc": "1.3.3" } }, "sha512-PFLAGQzYlyjniXdbmQ3dnGMZJXX5yrl2YS4DLRfR3BhgUsE1zpRIrccp9XMOGRfIHpdFvCn/nr5N1KMVda4x3A=="], - "update-browserslist-db": ["update-browserslist-db@1.2.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "vite": ["vite@6.4.1", "", { "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" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], - - "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], - - "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - - "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], @@ -891,29 +597,13 @@ "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "zod": ["zod@4.1.13", "", {}, "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig=="], - - "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], - - "@babel/core/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], - - "@babel/core/convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], - - "@babel/core/json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], - - "@babel/generator/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], - "@babel/helper-module-imports/@babel/traverse": ["@babel/traverse@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", "@babel/parser": "^7.27.0", "@babel/template": "^7.27.0", "@babel/types": "^7.27.0", "debug": "^4.3.1", "globals": "^11.1.0" } }, "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA=="], "@babel/helper-module-imports/@babel/types": ["@babel/types@7.27.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg=="], "@babel/helper-module-transforms/@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], - "@babel/parser/@babel/types": ["@babel/types@7.27.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" } }, "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg=="], - - "@babel/template/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], - - "@babel/traverse/@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], + "@emotion/babel-plugin/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], "@emotion/serialize/csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], @@ -939,86 +629,28 @@ "@mui/utils/@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], - "@napi-rs/wasm-runtime/@emnapi/runtime": ["@emnapi/runtime@1.4.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw=="], - - "@parcel/watcher/detect-libc": ["detect-libc@1.0.3", "", { "bin": { "detect-libc": "./bin/detect-libc.js" } }, "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg=="], - - "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - - "@typescript-eslint/typescript-estree/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - - "array.prototype.findlast/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "array.prototype.findlastindex/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "array.prototype.flat/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "array.prototype.flatmap/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "array.prototype.tosorted/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "arraybuffer.prototype.slice/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - "dom-helpers/csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], - "es-iterator-helpers/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - "eslint/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], - "eslint-config-next/globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], - - "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - - "eslint-plugin-jsx-a11y/array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], - - "eslint-plugin-react/array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], - - "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], - "espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], - "is-bun-module/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], - - "jsx-ast-utils/array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], - "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "object.fromentries/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "object.groupby/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - "parse-json/@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], - "reflect.getprototypeof/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - - "string.prototype.includes/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "string.prototype.matchall/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "string.prototype.repeat/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "string.prototype.trim/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], + "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@babel/helper-module-imports/@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.26.2", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ=="], "@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.0", "", { "dependencies": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw=="], + "@babel/helper-module-imports/@babel/traverse/@babel/parser": ["@babel/parser@7.27.0", "", { "dependencies": { "@babel/types": "^7.27.0" }, "bin": "./bin/babel-parser.js" }, "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg=="], + "@babel/helper-module-imports/@babel/traverse/@babel/template": ["@babel/template@7.27.0", "", { "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0" } }, "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA=="], "@babel/helper-module-imports/@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], @@ -1027,24 +659,8 @@ "@babel/helper-module-imports/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], - "@babel/parser/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.25.9", "", {}, "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="], - - "@babel/parser/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], - - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], - - "@typescript-eslint/typescript-estree/tinyglobby/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], - - "@typescript-eslint/typescript-estree/tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "eslint-plugin-jsx-a11y/array-includes/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - - "eslint-plugin-react/array-includes/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - "eslint/espree/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], - "jsx-ast-utils/array-includes/es-abstract": ["es-abstract@1.23.9", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.3", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.0", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-regex": "^1.2.1", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.0", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.18" } }, "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA=="], - "parse-json/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], "@babel/helper-module-imports/@babel/traverse/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.25.9", "", {}, "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ=="], -- 2.49.1