diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 00b5b9ea5..f96fb746f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,14 +20,6 @@ repos: args: - --fix=lf - id: requirements-txt-fixer - # only api - - repo: local - hooks: - - id: openapi-format - name: openapi-format - entry: openapi-format ./data/output/openapi.yaml --output - language: system - files: "data/output/openapi.yaml" # only server - repo: local hooks: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94073cf07..cb37da646 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,5 @@ Please note we have a [Code of Conduct](CODE_OF_CONDUCT.md), please follow it in build. 2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. -3. Update openapi.yaml with any breaking API-changes -4. You may merge the Pull Request in once you have the sign-off of one other developer, or if you +3. You may merge the Pull Request in once you have the sign-off of one other developer, or if you do not have permission to do that, you may request the reviewer to merge it for you. diff --git a/README.md b/README.md index a00ae0019..6eaab228d 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,10 @@ You can consume our API Documentation in two ways: - Head over to [our Website](https://nav.tum.de/api) and look at the interactive documentation - We also describe our API in an [OpenAPI 3.0](https://de.wikipedia.org/wiki/OpenAPI) compliant file. - You can find it [here](openapi.yaml). + You can find it [here](https://nav.tum.de/api/openapi.json). Using this Specification you can generate your own client to access the API in the language of your choice. To do this head over to - the [Swagger Editor](https://editor.swagger.io/?url=https://raw.githubusercontent.com/TUM-Dev/navigatum/main/openapi.yaml) + the [Swagger Editor](https://editor.swagger.io/?url=https://nav.tum.de/api/openapi.json) or other similar [OpenAPI tools](https://openapi.tools/). > [!NOTE] diff --git a/data/Dockerfile b/data/Dockerfile index 09a6a632d..37b54b7d0 100644 --- a/data/Dockerfile +++ b/data/Dockerfile @@ -18,7 +18,6 @@ COPY translations.yaml translations.yaml COPY output output RUN python3 compile.py \ - && test -f "./output/openapi.yaml" \ && test -f "./output/status_data.json" \ && test -f "./output/status_data.parquet" \ && test -f "./output/search_data.json" \ diff --git a/docker-compose.yml b/docker-compose.yml index 4b721efc0..3ed9a4788 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -92,7 +92,7 @@ services: - "traefik.enable=true" - "traefik.http.routers.navigatum-server.entrypoints=webs" - "traefik.http.routers.navigatum-server.tls.certresolver=leacme" - - "traefik.http.routers.navigatum-server.rule=Host(`nav.tum.de`) && (PathPrefix(`/api/locations/`) || PathPrefix(`/api/get/`) || PathPrefix(`/api/preview/`) || Path(`/api/search`) || PathPrefix(`/api/feedback/`) || Path(`/api/calendar`) || Path(`/api/status`)|| Path(`/api/metrics`) || PathPrefix(`/api/maps/indoor`))" + - "traefik.http.routers.navigatum-server.rule=Host(`nav.tum.de`) && Path(`/api`)" - "traefik.http.services.navigatum-server.loadbalancer.server.port=3003" networks: - traefik_traefik diff --git a/server/Cargo.lock b/server/Cargo.lock index 66ce2a2fb..a2d937fc6 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -135,6 +135,7 @@ dependencies = [ "bytestring", "cfg-if", "http 0.2.12", + "regex", "regex-lite", "serde", "tracing", @@ -219,6 +220,7 @@ dependencies = [ "mime", "once_cell", "pin-project-lite", + "regex", "regex-lite", "serde", "serde_json", @@ -2690,7 +2692,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3101,6 +3103,10 @@ dependencies = [ "tracing-subscriber", "tracing-test", "unicode-truncate", + "url", + "utoipa", + "utoipa-actix-web", + "utoipa-redoc", ] [[package]] @@ -6532,9 +6538,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna 1.0.3", @@ -6554,6 +6560,55 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utoipa" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514a48569e4e21c86d0b84b5612b5e73c0b2cf09db63260134ba426d4e8ea714" +dependencies = [ + "indexmap 2.6.0", + "serde", + "serde_json", + "serde_yaml", + "utoipa-gen", +] + +[[package]] +name = "utoipa-actix-web" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7eda9c23c05af0fb812f6a177514047331dac4851a2c8e9c4b895d6d826967f" +dependencies = [ + "actix-service", + "actix-web", + "utoipa", +] + +[[package]] +name = "utoipa-gen" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5629efe65599d0ccd5d493688cbf6e03aa7c1da07fe59ff97cf5977ed0637f66" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.87", + "url", +] + +[[package]] +name = "utoipa-redoc" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9218304bba9a0ea5e92085b0a427ccce5fd56eaaf6436d245b7578e6a95787e1" +dependencies = [ + "actix-web", + "serde", + "serde_json", + "utoipa", +] + [[package]] name = "uuid" version = "1.11.0" diff --git a/server/Cargo.toml b/server/Cargo.toml index 475dd1b4f..310e201cc 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -78,6 +78,12 @@ geozero = { version = "0.14.0", features = ["with-postgis-sqlx", "with-geo"], de geo-types = { version = "0.7.13", default-features = false } actix-middleware-etag = "0.4.2" +# docs +utoipa-actix-web = "0.1.2" +utoipa = { version = "5.2.0", features = ["yaml", "chrono", "actix_extras", "url"] } +utoipa-redoc = { version = "5.0.0", features = ["actix-web"] } +url = "2.5.4" + [dev-dependencies] insta = { version = "1.39.0", features = ["json", "redactions", "yaml"] } pretty_assertions = "1.4.1" diff --git a/server/README.md b/server/README.md index cfe5d05e3..bbf0c6f33 100644 --- a/server/README.md +++ b/server/README.md @@ -99,7 +99,7 @@ If you have made changes to the API, you need to update the API documentation. There are two editors for the API documentation (both are imperfect): -- [Swagger Editor](https://editor.swagger.io/?url=https://raw.githubusercontent.com/TUM-Dev/navigatum/main/openapi.yaml) +- [Swagger Editor](https://editor.swagger.io/?url=https://nav.tum.de/api/openapi.json) - [stoplight](https://stoplight.io/) #### Testing @@ -113,7 +113,7 @@ To do so, run the following commands against the API Server: python -m venv venv source venv/bin/activate pip install schemathesis -st run --workers=auto --base-url=http://localhost:3003 --checks=all ../openapi.yaml +st run --workers=auto --base-url=http://localhost:3003 --checks=all https://nav.tum.de/api/openapi.json ``` Some fuzzing-goals may not be available for you locally, as they require prefix-routing (f.ex.`/cdn` to the CDN) and diff --git a/server/src/calendar/mod.rs b/server/src/calendar/mod.rs index b468ce799..225ec376f 100644 --- a/server/src/calendar/mod.rs +++ b/server/src/calendar/mod.rs @@ -14,13 +14,23 @@ use actix_web::http::header::{CacheControl, CacheDirective}; mod connectum; mod models; pub mod refresh; - -#[derive(Serialize, Deserialize, Clone, Debug)] +#[expect( + unused_imports, + reason = "has to be imported as otherwise utoipa generates incorrect code" +)] +use serde_json::json; +#[derive(Serialize, Deserialize, Clone, Debug, utoipa::IntoParams, utoipa::ToSchema)] pub struct Arguments { + /// ids you want the calendars for + /// + /// Limit of max. 10 ids is arbitraryly chosen, if you need this limit increased, please contact us + #[schema(max_items=10,min_items=1,example=json!(["5605.EG.011","5510.02.001","5606.EG.036","5304"]))] ids: Vec, - /// eg. 2039-01-19T03:14:07+1 + /// The first allowed time the calendar would like to display + #[schema(examples("2039-01-19T03:14:07+01:00", "2042-01-07T00:00:00 UTC"))] start_after: DateTime, - /// eg. 2042-01-07T00:00:00 UTC + /// The last allowed time the calendar would like to display + #[schema(examples("2039-01-19T03:14:07+01:00", "2042-01-07T00:00:00 UTC"))] end_before: DateTime, } @@ -46,6 +56,22 @@ impl Arguments { } } +/// Retrieve Calendar Entries +/// +/// Retrieves calendar entries for specific `ids` within the requested time span. +/// The time span is defined by the `start_after` and `end_before` query parameters. +/// Ensure to provide valid date-time formats for these parameters. +/// +/// If successful, returns additional entries in the requested time span. +#[utoipa::path( + tags=["calendar"], + responses( + (status = 200, description = "**Entries of the calendar** in the requested time span", body = HashMap, content_type = "application/json"), + (status = 400, description= "**Bad Request.** Not all fields in the body are present as defined above", body = String, example = "Too many ids to query. We suspect that users don't need this. If you need this limit increased, please send us a message"), + (status = 404, description = "**Not found.** The requested location does not have a calendar", body = String, content_type = "text/plain", example = "Not found"), + (status = 503, description = "**Not Ready.** please retry later", body = String, content_type = "text/plain", example = "Waiting for first sync with TUMonline"), + ) +)] #[post("/api/calendar")] pub async fn calendar_handler( web::Json(args): web::Json, @@ -113,7 +139,14 @@ async fn get_locations( pool: &PgPool, ids: &[String], ) -> Result, HttpResponse> { - match sqlx::query_as!(CalendarLocation, "SELECT key,name,last_calendar_scrape_at,calendar_url,type,type_common_name FROM de WHERE key = ANY($1::text[])", ids).fetch_all(pool).await { + match sqlx::query_as!( + CalendarLocation, + "SELECT key,name,last_calendar_scrape_at,calendar_url,type,type_common_name FROM de WHERE key = ANY($1::text[])", + ids + ) + .fetch_all(pool) + .await + { Err(e) => { error!("could not refetch due to {e:?}"); Err(HttpResponse::InternalServerError() @@ -133,10 +166,17 @@ async fn get_from_db( ) -> anyhow::Result> { let mut located_events: HashMap = HashMap::new(); for location in locations { - let events = sqlx::query_as!(Event, r#"SELECT id,room_code,start_at,end_at,title_de,title_en,stp_type,entry_type,detailed_entry_type + let events = sqlx::query_as!( + Event, + r#"SELECT id,room_code,start_at,end_at,title_de,title_en,stp_type,entry_type,detailed_entry_type FROM calendar WHERE room_code = $1 AND start_at >= $2 AND end_at <= $3"#, - location.key, start_after, end_before).fetch_all(pool).await?; + location.key, + start_after, + end_before + ) + .fetch_all(pool) + .await?; located_events.insert( location.key.clone(), LocationEvents { @@ -266,7 +306,9 @@ mod db_tests { let (locations, events) = sample_data(); for (key, data) in locations { for lang in ["de", "en"] { - let query = format!("INSERT INTO {lang}(key,data,last_calendar_scrape_at) VALUES ('{key}','{data}','{now_rfc3339}')"); + let query = format!( + "INSERT INTO {lang}(key,data,last_calendar_scrape_at) VALUES ('{key}','{data}','{now_rfc3339}')" + ); sqlx::query(&query).execute(&mut *tx).await.unwrap(); } } diff --git a/server/src/calendar/models.rs b/server/src/calendar/models.rs index 3794acdd0..d82f5d324 100644 --- a/server/src/calendar/models.rs +++ b/server/src/calendar/models.rs @@ -3,13 +3,43 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::fmt::{Debug, Display, Formatter}; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)] pub(super) struct CalendarLocation { + /// Structured, globaly unique room code + /// + /// Included to enable multi-room calendars. + /// Format: BUILDING.LEVEL.NUMBER + #[schema(examples("5602.EG.001", "5121.EG.003"))] pub key: String, + /// name of the entry in a human-readable form + #[schema(examples( + "5602.EG.001 (MI HS 1, Friedrich L. Bauer Hörsaal)", + "5121.EG.003 (Computerraum)" + ))] pub name: String, + /// last time the calendar was scraped for this room + #[schema(examples("2039-01-19T03:14:07+01:00", "2042-01-07T00:00:00 UTC"))] pub last_calendar_scrape_at: Option>, + /// Link to the calendar of the room + #[schema(examples( + "https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12543&cReadonly=J", + "https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12559&cReadonly=J" + ))] pub calendar_url: Option, + /// Type of the entry in a human-readable form + #[schema(examples("Serverraum", "Büro"))] pub type_common_name: String, + /// type of the entry + /// + /// TODO document as a n enum with the following choices: + /// - `room` + /// - `building` + /// - `joined_building` + /// - `area` + /// - `site` + /// - `campus` + /// - `poi` + #[schema(examples("room", "building", "joined_building", "area", "site", "campus", "poi"))] pub r#type: String, } @@ -24,31 +54,51 @@ impl Debug for CalendarLocation { } } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)] pub(super) struct LocationEvents { pub(super) events: LimitedVec, pub(super) location: CalendarLocation, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, utoipa::ToSchema)] pub(super) struct Event { + /// ID of the calendar entry used in TUMonline internally + #[schema(examples(6424))] pub(super) id: i32, - /// e.g. 5121.EG.003 + /// Structured, globaly unique room code + /// + /// Included to enable multi-room calendars. + /// Format: BUILDING.LEVEL.NUMBER + #[schema(examples("5602.EG.001", "5121.EG.003"))] pub(super) room_code: String, - /// e.g. 2018-01-01T00:00:00 + /// start of the entry + #[schema(examples("2018-01-01T00:00:00"))] pub(super) start_at: DateTime, - /// e.g. 2019-01-01T00:00:00 + /// end of the entry + #[schema(examples("2019-01-01T00:00:00"))] pub(super) end_at: DateTime, - /// e.g. Quantenteleportation + /// German title of the Entry + #[schema(examples("Quantenteleportation"))] pub(super) title_de: String, - /// e.g. Quantum teleportation + /// English title of the Entry + #[schema(examples("Quantum teleportation"))] pub(super) title_en: String, - /// e.g. Vorlesung mit Zentralübung + /// Lecture-type + #[schema(examples("Vorlesung mit Zentralübung"))] pub(super) stp_type: Option, - /// e.g. lecture - /// in reality this is a [EventType] + /// What this calendar entry means. + /// + /// Each of these should be displayed in a different color + /// TODO document as an enum with these values via EventType: + /// - `lecture` + /// - `exercise` + /// - `exam` + /// - `barred` + /// - `other` + #[schema(examples("lecture", "exercise", "exam"))] pub(super) entry_type: String, - /// e.g. Abhaltung + /// For some Entrys, we do have more information (what kind of a `lecture` is it? What kind of an other `entry` is it?) + #[schema(examples("Abhaltung"))] pub(super) detailed_entry_type: String, } impl Debug for Event { @@ -96,7 +146,7 @@ impl Event { } } -#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type)] +#[derive(Serialize, Deserialize, Clone, Debug, sqlx::Type, utoipa::ToSchema)] #[sqlx(type_name = "EventType")] #[sqlx(rename_all = "lowercase")] #[serde(rename_all = "lowercase")] diff --git a/server/src/docs.rs b/server/src/docs.rs new file mode 100644 index 000000000..eaf4dc3ef --- /dev/null +++ b/server/src/docs.rs @@ -0,0 +1,117 @@ +use actix_web::{ + dev::{ServiceFactory, ServiceRequest}, + web, App, +}; +use utoipa_actix_web::UtoipaApp; +use utoipa_redoc::{Redoc, Servable}; + +#[derive(serde::Serialize, Default)] +struct OpenApiLogo { + /// The URL pointing to the logo. + /// + /// MUST be in the format of a URL. + /// It SHOULD be an absolute URL so your API definition is usable from any location. + url: String, + /// background color to use with the logo image. + /// + /// MUST be RGB color in hexadecimal format. + #[serde(rename = "backgroundColor")] + background_color: Option, + /// text to use for the alt HTML tag on the logo image. + /// + /// Defaults to `logo` if nothing is provided. + #[serde(rename = "altText")] + alt_text: Option, + /// URL pointing to the contact page. + /// + /// Defaults to `info.contact.url` field from the API definition. + href: Option, +} + +pub fn add_openapi_docs(app: UtoipaApp) -> App +where + T: ServiceFactory, +{ + let (app, mut openapi) = app.split_for_parts(); + + add_static_openapi_docs(&mut openapi); + app.app_data(web::Data::new(openapi.clone())) + .service(Redoc::with_url("/api", openapi.clone())) +} + +fn add_static_openapi_docs(openapi: &mut utoipa::openapi::OpenApi) { + use utoipa::openapi::extensions::ExtensionsBuilder; + use utoipa::openapi::external_docs::ExternalDocsBuilder; + use utoipa::openapi::tag::TagBuilder; + use utoipa::openapi::{ContactBuilder, InfoBuilder, LicenseBuilder, ServerBuilder}; + let description = r#"Navigating around TUM with excellence – An API to search for rooms, +buildings and other places + +NavigaTUM is a tool developed by students for students, to help you get around at [TUM](https://tum.de). Feel free to contribute. + +- [x] Interactive/static maps to look up the position of rooms or buildings +- [x] Fast and typo-tolerant search +- [x] Support for different room code formats as well as generic names +- [x] All functionality is also available via an open and well documented API +- [x] Automatically update the data from upstream datasources +- [ ] Allow students/staff to easily submit feedback and data patches +- [ ] Generate maps from CAD data sources +- [ ] Generate turn by turn navigation advice for navigating end to end + +If you'd like to help out or join us in this adventure, we would love to talk to you."#; + openapi.info = InfoBuilder::new() + .title("NavigaTUM") + .description(Some(description)) + .terms_of_service(Some("https://nav.tum.de/en/about/privacy")) + .contact(Some( + ContactBuilder::new() + .name(Some("OpenSource @ TUM e.V.")) + .url(Some("https://tum.dev/")) + .email(Some("navigatum@tum.de")) + .build() + )) + .license(Some( + LicenseBuilder::new() + .name("GPL v3") + .url(Some("https://www.gnu.org/licenses/")) + .build())) + .version(env!("CARGO_PKG_VERSION")) + .extensions(Some(ExtensionsBuilder::new() + .add("logo", serde_json::to_value(OpenApiLogo{ + url: "https://raw.githubusercontent.com/TUM-Dev/NavigaTUM/refs/heads/main/webclient/app/assets/logos/navigatum.svg".to_string(), + ..OpenApiLogo::default() + }).unwrap()) + .build())) + .build(); + openapi.servers = Some(vec![ServerBuilder::new() + .url("https://nav.tum.de") + .description(Some("production")) + .build()]); + openapi.tags = Some(vec![ + TagBuilder::new() + .name("locations".to_string()) + .description(Some("API to access/search for location information")) + .build(), + TagBuilder::new() + .name("calendar".to_string()) + .description(Some("APIs to access calendar-data")) + .build(), + TagBuilder::new() + .name("feedback".to_string()) + .description(Some("APIs to give feedback")) + .build(), + TagBuilder::new() + .name("maps".to_string()) + .description(Some("API to access for map-data")) + .build(), + ]); + openapi.external_docs = Some( + ExternalDocsBuilder::new() + .url("https://github.com/TUM-Dev/navigatum") + .description(Some( + "Visit our GitHub Page for more in-depth documentation", + )) + .into(), + ); + openapi.schema = "http://json-schema.org/draft-07/schema".to_string(); +} diff --git a/server/src/feedback/github.rs b/server/src/feedback/github.rs index 0a884d684..698b9524b 100644 --- a/server/src/feedback/github.rs +++ b/server/src/feedback/github.rs @@ -26,14 +26,14 @@ pub async fn open_issue(title: &str, description: &str, labels: Vec) -> let Ok(personal_token) = github_token() else { return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create issue"); + .body("Failed to create issue, please try again later"); }; let octocrab = match Octocrab::builder().personal_token(personal_token).build() { Err(e) => { error!("Could not create Octocrab instance: {e:?}"); return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create issue"); + .body("Failed to create issue, please try again later"); } Ok(octocrab) => octocrab, }; @@ -54,7 +54,7 @@ pub async fn open_issue(title: &str, description: &str, labels: Vec) -> error!("Error creating issue: {e:?}"); HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create issue") + .body("Failed to create issue, please try again later") } }; } @@ -69,14 +69,14 @@ pub async fn open_pr( let Ok(personal_token) = github_token() else { return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create a pull request"); + .body("Failed to create a pull request, please try again later"); }; let octocrab = match Octocrab::builder().personal_token(personal_token).build() { Err(e) => { error!("Could not create Octocrab instance: {e:?}"); return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create a pull request"); + .body("Failed to create a pull request, please try again later"); } Ok(octocrab) => octocrab, }; @@ -95,7 +95,7 @@ pub async fn open_pr( error!("Error creating pull request: {e:?}"); return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create a pull request"); + .body("Failed to create a pull request, please try again later"); } }; @@ -116,7 +116,7 @@ pub async fn open_pr( error!("Error updating PR: {e:?}"); HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to create a pull request") + .body("Failed to create a pull request, please try again later") } }; } diff --git a/server/src/feedback/mod.rs b/server/src/feedback/mod.rs index 80a3760aa..c99e6e39d 100644 --- a/server/src/feedback/mod.rs +++ b/server/src/feedback/mod.rs @@ -1,28 +1,4 @@ -use actix_governor::{GlobalKeyExtractor, Governor, GovernorConfigBuilder}; -use actix_web::web; - mod github; -mod post_feedback; -mod proposed_edits; -mod tokens; - -const SECONDS_PER_DAY: u64 = 60 * 60 * 24; - -pub fn configure(cfg: &mut web::ServiceConfig) { - let feedback_ratelimit = GovernorConfigBuilder::default() - .key_extractor(GlobalKeyExtractor) - .seconds_per_request(SECONDS_PER_DAY / 300) // replenish new token every .. seconds - .burst_size(50) - .finish() - .expect("Invalid configuration of the governor"); - - let recorded_tokens = web::Data::new(tokens::RecordedTokens::default()); - cfg.app_data(recorded_tokens.clone()) - .service(post_feedback::send_feedback) - .service(proposed_edits::propose_edits) - .service( - web::scope("/get_token") - .wrap(Governor::new(&feedback_ratelimit)) - .route("", web::post().to(tokens::get_token)), - ); -} +pub mod post_feedback; +pub mod proposed_edits; +pub mod tokens; diff --git a/server/src/feedback/post_feedback.rs b/server/src/feedback/post_feedback.rs index 51e69e57f..599993dc0 100644 --- a/server/src/feedback/post_feedback.rs +++ b/server/src/feedback/post_feedback.rs @@ -1,22 +1,105 @@ use actix_web::post; use actix_web::web::{Data, Json}; use actix_web::HttpResponse; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use super::github; use super::tokens::RecordedTokens; +#[expect( + unused_imports, + reason = "has to be imported as otherwise utoipa generates incorrect code" +)] +use url::Url; -#[derive(Deserialize)] +#[derive(Deserialize, Serialize, Default, utoipa::ToSchema)] +#[serde(rename_all = "lowercase")] +enum FeedbackCategory { + Bug, + Feature, + Search, + Navigation, + Entry, + General, + #[default] + Other, +} +impl std::fmt::Display for FeedbackCategory { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let val = serde_json::to_string(self).expect("FeedbackCategory is always serialisable"); + f.write_str(&val) + } +} + +#[derive(Deserialize, utoipa::IntoParams, utoipa::ToSchema)] pub struct FeedbackPostData { + /// The JWT token, that can be used to generate feedback + #[schema( + example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Njk2MzczODEsImlhdCI6MTY2OTU5NDE4MSwibmJmIjoxNjY5NTk0MTkxLCJraWQiOjE1ODU0MTUyODk5MzI0MjU0Mzg2fQ.sN0WwXzsGhjOVaqWPe-Fl5x-gwZvh28MMUM-74MoNj4" + )] token: String, - category: String, + /// The category of the feedback. + #[schema(example=FeedbackCategory::Bug)] + #[serde(default)] + category: FeedbackCategory, + /// The subject/title of the feedback + /// + /// Controll characters will be stripped, too long input truncated and newlines made to render in markdown + #[schema(example = "A catchy title", max_length = 512, min_length = 4)] subject: String, + /// The body/description of the feedback + /// + /// Controll characters will be stripped, too long input truncated and newlines made to render in markdown + #[schema( + example = "A clear description what happened where and how we should improve it", + max_length = 1048576, + min_length = 10 + )] body: String, + /// Whether the user has checked the privacy-checkbox. + /// + /// We are posting the feedback publicly on GitHub (not a EU-Company). + /// **You MUST also include such a checkmark.** privacy_checked: bool, + /// Whether the user has requested to delete the issue. + /// + /// This flag means: + /// - If the user has requested to delete the issue, we will delete it from GitHub after processing it + /// - If the user has not requested to delete the issue, we will not delete it from GitHub and it will remain as a closed issue. deletion_requested: bool, } -#[post("/feedback")] +/// Post feedback +/// +/// ***Do not abuse this endpoint.*** +/// +/// This posts the actual feedback to GitHub and returns the GitHub link. +/// This API will create issues instead of pull-requests +/// => all feedback is allowed, but [`/api/feedback/propose_edits`](#tag/feedback/operation/propose_edits) is preferred, if it can be posted there. +/// +/// For this Endpoint to work, you need to generate a token via the [`/api/feedback/get_token`](#tag/feedback/operation/get_token) endpoint. +/// +/// # Note +/// +/// Tokens are only used if we return a 201 Created response. +/// Otherwise, they are still valid +#[utoipa::path( + tags=["feedback"], + responses( + (status = 201, description = "The feedback has been **successfully posted to GitHub**. We return the link to the GitHub issue.", body = Url, content_type = "text/plain", example = "https://github.com/TUM-Dev/navigatum/issues/9"), + (status = 400, description = "**Bad Request.** Not all fields in the body are present as defined above"), + (status = 403, description = r#"**Forbidden.** Causes are (delivered via the body): + +- `Invalid token`: You have not supplied a token generated via the `gen_token`-Endpoint. +- `Token not old enough, please wait`: Tokens are only valid after 10s. +- `Token expired`: Tokens are only valid for 12h. +- `Token already used`: Tokens are non reusable/refreshable single-use items."#, body = String, content_type = "text/plain"), + (status = 422, description = "**Unprocessable Entity.** Subject or body missing or too short."), + (status = 451, description = "**Unavailable for legal reasons.** Using this endpoint without accepting the privacy policy is not allowed. For us to post to GitHub, this has to be `true`"), + (status = 500, description = "**Internal Server Error.** We have a problem communicating with GitHubs servers. Please try again later"), + (status = 503, description = "**Service unavailable.** We have not configured a GitHub Access Token. This could be because we are experiencing technical difficulties or intentional. Please try again later."), + ) +)] +#[post("/api/feedback/feedback")] pub async fn send_feedback( recorded_tokens: Data, req_data: Json, @@ -33,19 +116,14 @@ pub async fn send_feedback( .body("Using this endpoint without accepting the privacy policy is not allowed"); }; - github::open_issue(&req_data.subject, &req_data.body, parse_labels(&req_data)).await + github::open_issue(&req_data.subject, &req_data.body, parse_labels(&req_data.0)).await } -fn parse_labels(req_data: &Json) -> Vec { +fn parse_labels(req_data: &FeedbackPostData) -> Vec { let mut labels = vec!["webform".to_string()]; if req_data.deletion_requested { labels.push("delete-after-processing".to_string()); } - match req_data.category.as_str() { - "general" | "bug" | "feature" | "search" | "entry" | "navigation" => { - labels.push(req_data.category.as_str().to_string()); - } - _ => {} - }; + labels.push(req_data.category.to_string()); labels } diff --git a/server/src/feedback/proposed_edits/coordinate.rs b/server/src/feedback/proposed_edits/coordinate.rs index 56f39a364..14fcec5e6 100644 --- a/server/src/feedback/proposed_edits/coordinate.rs +++ b/server/src/feedback/proposed_edits/coordinate.rs @@ -38,9 +38,13 @@ impl CoordinateFile { } } -#[derive(Deserialize, Debug, Clone, Copy, Default, PartialEq)] +#[derive(Deserialize, Debug, Clone, Copy, Default, PartialEq, utoipa::ToSchema)] pub struct Coordinate { + /// Latitude + #[schema(example = 48.26244490906312)] lat: f64, + /// Longitude + #[schema(example = 48.26244490906312)] lon: f64, } diff --git a/server/src/feedback/proposed_edits/image.rs b/server/src/feedback/proposed_edits/image.rs index e4de53755..a1fcbaa8e 100644 --- a/server/src/feedback/proposed_edits/image.rs +++ b/server/src/feedback/proposed_edits/image.rs @@ -11,7 +11,7 @@ use tracing::error; use super::AppliableEdit; -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, utoipa::ToSchema)] pub struct Source { author: String, license: Property, @@ -21,22 +21,24 @@ pub struct Source { #[serde(skip_serializing_if = "Option::is_none")] meta: Option>, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, utoipa::ToSchema)] struct Property { text: String, #[serde(skip_serializing_if = "Option::is_none")] url: Option, } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, utoipa::ToSchema)] pub struct Offsets { #[serde(skip_serializing_if = "Option::is_none")] header: Option, #[serde(skip_serializing_if = "Option::is_none")] thumb: Option, } -#[derive(Debug, Deserialize, Clone, Eq, PartialEq)] +#[derive(Debug, Deserialize, Clone, Eq, PartialEq, utoipa::ToSchema)] pub struct Image { + /// The image encoded as base64 + #[schema(content_encoding = "base64")] content: String, metadata: Source, } @@ -109,7 +111,10 @@ impl AppliableEdit for Image { let content_result = self.save_content(&target); let metadata_result = self.save_metadata(key, &image_dir); - let success=format!("Full image for {key} Layout", content=self.content); + let success = format!( + "Full image for {key} Layout", + content = self.content + ); match (content_result, metadata_result) { (Ok(()), Ok(())) => success, (Err(e), Ok(())) => { diff --git a/server/src/feedback/proposed_edits/mod.rs b/server/src/feedback/proposed_edits/mod.rs index 1d33ecddf..4b81f1a58 100644 --- a/server/src/feedback/proposed_edits/mod.rs +++ b/server/src/feedback/proposed_edits/mod.rs @@ -5,6 +5,11 @@ use actix_web::web::{Data, Json}; use actix_web::{post, HttpResponse}; use serde::Deserialize; use tracing::error; +#[expect( + unused_imports, + reason = "has to be imported as otherwise utoipa generates incorrect code" +)] +use url::Url; use crate::limited::hash_map::LimitedHashMap; @@ -19,7 +24,7 @@ mod discription; mod image; mod tmp_repo; -#[derive(Debug, Deserialize, Clone)] +#[derive(Debug, Deserialize, Clone, utoipa::ToSchema)] struct Edit { coordinate: Option, image: Option, @@ -28,11 +33,24 @@ pub trait AppliableEdit { fn apply(&self, key: &str, base_dir: &Path) -> String; } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, utoipa::IntoParams, utoipa::ToSchema)] pub struct EditRequest { + /// The JWT token, that can be used to generate feedback + #[schema( + example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Njk2MzczODEsImlhdCI6MTY2OTU5NDE4MSwibmJmIjoxNjY5NTk0MTkxLCJraWQiOjE1ODU0MTUyODk5MzI0MjU0Mzg2fQ.sN0WwXzsGhjOVaqWPe-Fl5x-gwZvh28MMUM-74MoNj4" + )] token: String, + /// The edits to be made to the room. The keys are the ID of the props to be edited, the values are the proposed Edits. edits: LimitedHashMap, + /// Additional context for the edit. + /// + /// Will be displayed in the discription field of the PR + #[schema(example = "I have a picture of the room, please add it to the roomfinder")] additional_context: String, + /// Whether the user has checked the privacy-checkbox. + /// + /// We are posting the feedback publicly on GitHub (not a EU-Company). + /// **You MUST also include such a checkmark.** privacy_checked: bool, } @@ -93,7 +111,35 @@ impl EditRequest { } } -#[post("/propose_edit")] +/// Post Edit-Requests +/// +/// ***Do not abuse this endpoint.*** +/// +/// This posts the actual feedback to GitHub and returns the github link. +/// This API will create pull-requests instead of issues => only a subset of feedback is allowed. +/// For this Endpoint to work, you need to generate a token via the [`/api/feedback/get_token`](#tag/feedback/operation/get_token) endpoint. +/// +/// # Note: +/// +/// Tokens are only used if we return a 201 Created response. Otherwise, they are still valid +#[utoipa::path( + tags=["feedback"], + responses( + (status = 201, description= "The edit request feedback has been **successfully posted to GitHub**. We return the link to the GitHub issue.", body= Url, content_type="text/plain", example="https://github.com/TUM-Dev/navigatum/issues/9"), + (status = 400, description= "**Bad Request.** Not all fields in the body are present as defined above"), + (status = 403, description= r#"**Forbidden.** Causes are (delivered via the body): + +- `Invalid token`: You have not supplied a token generated via the `gen_token`-Endpoint. +- `Token not old enough, please wait`: Tokens are only valid after 10s. +- `Token expired`: Tokens are only valid for 12h. +- `Token already used`: Tokens are non reusable/refreshable single-use items."#), + (status = 422, description= "**Unprocessable Entity.** Subject or body missing or too short."), + (status = 451, description= "**Unavailable for legal reasons.** Using this endpoint without accepting the privacy policy is not allowed. For us to post to GitHub, this has to be true"), + (status = 500, description= "**Internal Server Error.** We have a problem communicating with GitHubs servers. Please try again later."), + (status = 503, description= "Service unavailable. We have not configured a GitHub Access Token. This could be because we are experiencing technical difficulties or intentional. Please try again later."), + ) +)] +#[post("/api/feedback/propose_edits")] pub async fn propose_edits( recorded_tokens: Data, req_data: Json, @@ -141,7 +187,7 @@ pub async fn propose_edits( error!("Error while applying changes: {e}", e = e); HttpResponse::InternalServerError() .content_type("text/plain") - .body("could not apply changes, please try again later") + .body("Could apply changes, please try again later") } } } diff --git a/server/src/feedback/tokens.rs b/server/src/feedback/tokens.rs index cfdade370..61326b5fd 100644 --- a/server/src/feedback/tokens.rs +++ b/server/src/feedback/tokens.rs @@ -1,6 +1,6 @@ use std::fmt; -use actix_web::HttpResponse; +use actix_web::{post, HttpResponse}; use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; @@ -108,12 +108,43 @@ impl RecordedTokens { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, utoipa::IntoParams, utoipa::ToSchema)] struct Token { - created_at: i64, // unix timestamp + /// Unix timestamp of when the token was created + #[schema(example = "1629564181")] + created_at: i64, + /// The JWT token, that can be used to generate feedback + #[schema( + example = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Njk2MzczODEsImlhdCI6MTY2OTU5NDE4MSwibmJmIjoxNjY5NTk0MTkxLCJraWQiOjE1ODU0MTUyODk5MzI0MjU0Mzg2fQ.sN0WwXzsGhjOVaqWPe-Fl5x-gwZvh28MMUM-74MoNj4" + )] token: String, } +/// Get a feedback-token +/// +/// ***Do not abuse this endpoint.*** +/// +/// This returns a JWT token usable for submitting feedback. +/// You should request a token, ***if (and only if) a user is on a feedback page*** +/// +/// As a rudimentary way of rate-limiting feedback, this endpoint returns a token. +/// To post feedback, you will need this token. +/// +/// Tokens gain validity after 5s, and are invalid after 12h of being issued. +/// They are not refreshable, and are only valid for one usage. +/// +/// # Note: +/// +/// Global Rate-Limiting allows bursts with up to 20 requests and replenishes 50 requests per day +#[utoipa::path( + tags=["feedback"], + responses( + (status = 201, description = "**Created** a usable token", body= Token, content_type="application/json"), + (status = 429, description = "**Too many requests.** We are rate-limiting everyone's requests, please try again later."), + (status = 503, description= "**Service unavailable.** We have not configured a GitHub Access Token. This could be because we are experiencing technical difficulties or intentional. Please try again later."), + ) +)] +#[post("")] pub async fn get_token() -> HttpResponse { if !able_to_process_feedback() { return HttpResponse::ServiceUnavailable() @@ -137,7 +168,7 @@ pub async fn get_token() -> HttpResponse { error!("Failed to generate token: {e:?}"); HttpResponse::InternalServerError() .content_type("text/plain") - .body("Failed to generate token.") + .body("Failed to generate token, please try again later") } } } diff --git a/server/src/limited/hash_map.rs b/server/src/limited/hash_map.rs index da4322032..b7de05de6 100644 --- a/server/src/limited/hash_map.rs +++ b/server/src/limited/hash_map.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use crate::limited::OrMore; -#[derive(Serialize, Deserialize, Clone, Default)] +#[derive(Serialize, Deserialize, Clone, Default, utoipa::ToSchema)] pub struct LimitedHashMap(pub HashMap); impl From> for LimitedHashMap { diff --git a/server/src/limited/vec.rs b/server/src/limited/vec.rs index da6723ff0..7b1c9801f 100644 --- a/server/src/limited/vec.rs +++ b/server/src/limited/vec.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::limited::OrMore; -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, utoipa::ToSchema)] pub struct LimitedVec(pub Vec); impl AsRef<[T]> for LimitedVec { diff --git a/server/src/localisation.rs b/server/src/localisation.rs index b8912f218..6fb5f8a93 100644 --- a/server/src/localisation.rs +++ b/server/src/localisation.rs @@ -1,6 +1,6 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq, Default)] +#[derive(Deserialize, Serialize, Copy, Clone, Debug, Eq, PartialEq, Default, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum LanguageOptions { #[default] @@ -8,9 +8,21 @@ enum LanguageOptions { En, } -#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq, Default)] +#[derive( + Deserialize, + Serialize, + Copy, + Clone, + Debug, + Eq, + PartialEq, + Default, + utoipa::IntoParams, + utoipa::ToSchema, +)] #[serde(default)] pub struct LangQueryArgs { + /// The language you want your preview to be in. If either this or the query parameter is set to en, this will be delivered. lang: LanguageOptions, } diff --git a/server/src/locations/details.rs b/server/src/locations/details.rs index 2231770ae..36d320682 100644 --- a/server/src/locations/details.rs +++ b/server/src/locations/details.rs @@ -7,15 +7,42 @@ use tracing::error; use crate::localisation; use crate::models::LocationKeyAlias; +#[expect( + unused_imports, + reason = "has to be imported as otherwise utoipa generates incorrect code" +)] +use serde_json::json; + +#[derive(Deserialize, utoipa::IntoParams)] +struct DetailsPathParams { + /// ID of the location + id: String, +} -#[get("/{id}")] +/// Get entry-details +/// +/// This returns the full data available for the entry (room/building). +/// +/// This is more data, that should be supplied once a user clicks on an entry. +/// Preloading this is not an issue on our end, but keep in mind bandwith constraints on your side. +/// The data can be up to 50kB (using gzip) or 200kB unzipped. +/// More about this data format is described in the NavigaTUM-data documentation +#[utoipa::path( + tags=["locations"], + params(DetailsPathParams, localisation::LangQueryArgs), + responses( + (status = 200, description = "**Details** about the **location**", body= LocationDetailsResponse, content_type="application/json"), + (status = 404, description = "**Not found.** Make sure that requested item exists", body = String, content_type = "text/plain", example = "Not found"), + ) +)] +#[get("/api/locations/{id}")] pub async fn get_handler( - params: web::Path, + params: web::Path, web::Query(args): web::Query, data: web::Data, ) -> HttpResponse { let id = params - .into_inner() + .id .replace(|c: char| c.is_whitespace() || c.is_control(), ""); let Some((probable_id, redirect_url)) = get_alias_and_redirect(&data.pool, &id).await else { return HttpResponse::NotFound() @@ -40,7 +67,7 @@ pub async fn get_handler( error!("cannot serialise {id} because {e:?}"); HttpResponse::InternalServerError() .content_type("text/plain") - .body("Internal Server Error") + .body("Failed to fetch details, please try again later") } Ok(mut res) => { res.redirect_url = Some(redirect_url); @@ -67,15 +94,26 @@ pub async fn get_handler( } } -#[derive(Serialize, Deserialize, Debug, Clone)] +/// Operator of a location +#[derive(Serialize, Deserialize, Debug, Clone, utoipa::ToSchema)] struct Operator { + /// ID of the operator + #[schema(examples(51901))] id: u32, + ///Link to the operator + #[schema(examples("https://campus.tum.de/tumonline/webnav.navigate_to?corg=51901"))] url: String, + /// designation code of the operator + #[schema(examples("TUS7000"))] code: String, + /// The full name of the operator (localized). Null for organisations that + /// are no longer active (e.g. id=38698), but where the operator has not been + /// updated in TUMonline. + #[schema(examples("TUM School of Social Sciences and Technology"))] name: String, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum LocationType { #[default] @@ -88,47 +126,66 @@ enum LocationType { Poi, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct LocationDetailsResponse { /// The id, that was requested + #[schema(examples("5606.EG.036"))] id: String, /// The type of the entry r#type: LocationType, /// The type of the entry in a human-readable form + #[schema(examples("Büro"))] type_common_name: String, /// The name of the entry in a human-readable form + #[schema(examples("5606.EG.036 (Büro Fachschaft Mathe Physik Informatik Chemie / MPIC)"))] name: String, /// A list of alternative ids for this entry. /// /// Not to be confused with - /// - [`id`] which is the unique identifier or - /// - [`visual-id`] which is an alternative identifier for the entry (only displayed in the URL). + /// - `id` which is the unique identifier or + /// - `visual-id` which is an alternative identifier for the entry (only displayed in the URL). + #[schema(examples(json!(["26503@5406"])))] aliases: Vec, /// The ids of the parents. + /// /// They are ordered as they would appear in a Breadcrumb menu. - /// See [`parent_names`] for their human names. + /// See `parent_names` for their human names. + #[schema(min_items=1, examples(json!(["root","garching","mi", "5602"])))] parents: Vec, - /// The ids of the parents. They are ordered as they would appear in a Breadcrumb menu. - /// See [`parents`] for their actual ids. + /// The ids of the parents. + /// + /// They are ordered as they would appear in a Breadcrumb menu. + /// See `parents` for their actual ids. + #[schema(min_items=1, examples(json!(["Standorte","Garching Forschungszentrum","Fakultät Mathematik & Informatik (FMI oder MI)", "Finger 06 (BT06)"])))] parent_names: Vec, /// Data for the info-card table props: Props, - /// The information you need to request Images from the /cdn/{size}/{id}_{counter}.webp endpoint + /// The information you need to request Images from the `/cdn/{size}/{id}_{counter}.webp` endpoint + /// /// TODO: Sometimes missing, sometimes not.. so weird.. #[serde(skip_serializing_if = "Option::is_none")] imgs: Option>, ranking_factors: RankingFactors, /// Where we got our data from, should be displayed at the bottom of any page containing this data sources: Sources, - /// The url, this item should be displayed at. Present on both redirects and normal entries, to allow for the common /view/:id path + /// The url, this item should be displayed at. + /// + /// Present on both redirects and normal entries, to allow for the common /view/:id path + #[schema(examples("/room/5606.EG.036"))] redirect_url: Option, + /// Coordinate of the location coords: Coordinate, + /// Print or overlay maps for said location maps: Maps, + /// informations for different sectons on the page like the + /// - buildings overview, + /// - rooms overview and + /// - featured view #[serde(skip_serializing_if = "Option::is_none")] sections: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct Sections { #[serde(skip_serializing_if = "Option::is_none")] buildings_overview: Option, @@ -138,7 +195,7 @@ struct Sections { featured_overview: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct BuildingsOverviewItem { /// The id of the entry id: String, @@ -150,7 +207,7 @@ struct BuildingsOverviewItem { thumb: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct FeaturedOverviewItem { /// The id of the entry id: String, @@ -162,53 +219,54 @@ struct FeaturedOverviewItem { image_url: String, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct BuildingsOverview { entries: Vec, n_visible: u32, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RoomsOverviewUsageChild { id: String, name: String, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RoomsOverviewUsage { name: String, count: u32, children: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RoomsOverview { usages: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct FeaturedOverview { entries: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct Maps { + /// type of the Map that should be shown by default default: DefaultMaps, #[serde(skip_serializing_if = "Option::is_none")] roomfinder: Option, - /// [`None`] would mean no overlay maps are displayed by default. + /// `None` would mean no overlay maps are displayed by default. /// For rooms, you should add a warning that no floor map is available for this room #[serde(skip_serializing_if = "Option::is_none")] overlays: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RoomfinderMap { /// The id of the map, that should be shown as a default - /// Example: `rf142` + #[schema(examples("rf142"))] default: String, available: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RoomfinderMapEntry { /// human-readable name of the map name: String, @@ -229,64 +287,76 @@ struct RoomfinderMapEntry { /// Where the map is stored file: String, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct OverlayMaps { - /// The floor-id of the map, that should be shown as a default. + /// The floor-id of the map, that should be shown as a default. /// null means: /// - We suggest, you don't show a map by default. /// - This is only the case for buildings or other such entities and not for rooms, if we know where they are and a map exists + #[schema(example = 0)] default: Option, available: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct OverlayMapEntry { - /// machine-readable floor-id of the map. + /// Machine-readable floor-id of the map. + /// /// Should start with 0 for the ground level (defined by the main entrance) and increase or decrease. /// It is not guaranteed that numbers are consecutive or that `1` corresponds to level `01`, because buildings sometimes have more complicated layouts. They are however always in the correct (physical) order. + #[schema(example = 0)] id: i32, /// Floor of the Map. + /// /// Should be used for display to the user in selectors. /// Matches the floor part of the TUMonline roomcode. + #[schema(example = "EG")] floor: String, /// human-readable name of the map + #[schema(example = "MI Gebäude (EG)")] name: String, /// filename of the map + #[schema(example = "webp/rf95.webp")] file: String, /// Coordinates are four `[lon, lat]` pairs, for the top left, top right, bottom right, bottom left image corners. + #[schema(min_items = 4, max_items = 4, example = json!([[11.666739,48.263478],[11.669666,48.263125],[11.669222,48.261585],[11.666331,48.261929]]))] coordinates: [(f64, f64); 4], } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum DefaultMaps { + /// interactive maps should be shown first #[default] Interactive, + /// roomfinder maps should be shown first Roomfinder, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct ExtraComputedProp { - /// example: `Genauere Angaben` + #[schema(examples("Genauere Angaben"))] #[serde(skip_serializing_if = "Option::is_none")] header: Option, - /// example: `for exams: 102 in tight, 71 in wide, 49 in corona` + #[schema(examples("for exams: 102 in tight, 71 in wide, 49 in corona"))] body: String, - /// example: `data based on a Survey of chimneysweeps` + #[schema(examples("data based on a Survey of chimneysweeps"))] #[serde(skip_serializing_if = "Option::is_none")] footer: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct ComputedProp { - /// example: `Raumkennung` + #[schema(examples("Raumkennung"))] name: String, - /// example: `5602.EG.001` + #[schema(examples("5602.EG.001"))] text: String, #[serde(skip_serializing_if = "Option::is_none")] extra: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] + +/// Data for the info-card table +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct Props { /// The operator of the room #[serde(skip_serializing_if = "Option::is_none")] @@ -295,27 +365,31 @@ struct Props { #[serde(skip_serializing_if = "Vec::is_empty", default = "Vec::new")] links: Vec, /// A comment to show to an entry. + /// /// It is used in the rare cases, where some aspect about the room/.. or its translation are misleading. - /// An example of a room with a comment is `MW1801`. #[serde(skip_serializing_if = "String::is_empty", default = "String::new")] comment: String, - /// link to the calendar of the room - /// examples: - /// - 'https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12543&cReadonly=J' - /// - 'https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12559&cReadonly=J' + /// Link to the calendar of the room + #[schema(examples( + "https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12543&cReadonly=J", + "https://campus.tum.de/tumonline/tvKalender.wSicht?cOrg=19691&cRes=12559&cReadonly=J" + ))] #[serde(skip_serializing_if = "Option::is_none")] calendar_url: Option, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, utoipa::ToSchema)] struct Source { - /// name of the provider + /// Name of the provider + #[schema(example = "NavigaTUM")] name: String, - /// url of the provider + /// Url of the provider #[serde(skip_serializing_if = "Option::is_none")] + #[schema(example = "https://nav.tum.de")] url: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +/// Where we got our data from, should be displayed at the bottom of any page containing this data +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct Sources { /// Was this entry patched by us? (e.g. to fix a typo in the name/...) /// If so, we should not display the source, as it is not the original source. @@ -325,9 +399,12 @@ struct Sources { base: Vec, } -#[derive(Deserialize, Serialize, Debug, Default)] +/// The information you need to request Images from the `/cdn/{size}/{id}_{counter}.webp` endpoint +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct ImageInfo { - /// The name of the image file. consists of {building_id}_{image_id}.webp, where image_id is a counter starting at 0 + /// The name of the image file. + /// consists of {building_id}_{image_id}.webp, where image_id is a counter starting at 0 + #[schema(examples("mi_0.webp"))] name: String, author: URLRef, source: PossibleURLRef, @@ -336,14 +413,16 @@ struct ImageInfo { meta: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +/// A link with a localized link text and url +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct PossibleURLRef { text: String, #[serde(skip_serializing_if = "Option::is_none")] url: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +/// A link with a localized link text and url +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct URLRef { text: String, url: Option, @@ -352,7 +431,7 @@ struct URLRef { /// Additional data about the images. /// Does not have to be displayed. /// All fields are optional. -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct ImageMetadata { ///optional date description #[serde(skip_serializing_if = "Option::is_none")] @@ -387,7 +466,7 @@ struct ImageMetadata { department: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct RankingFactors { rank_combined: u32, rank_type: u32, @@ -398,23 +477,32 @@ struct RankingFactors { rank_custom: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] struct Coordinate { + /// Latitude + #[schema(example = 48.26244490906312)] lat: f64, + /// Longitude + #[schema(example = 48.26244490906312)] lon: f64, + /// Source of the Coordinates + #[schema(example = "navigatum")] source: CoordinateSource, + /// How accurate the coordinate is. + /// Only present, if it is limited to a degree (e.g. we only know the building) #[serde(skip_serializing_if = "Option::is_none")] + #[schema(example = "building")] accuracy: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum CoordinateAccuracy { #[default] Building, } -#[derive(Serialize, Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum CoordinateSource { #[default] diff --git a/server/src/locations/mod.rs b/server/src/locations/mod.rs index bf9be4ed9..c604ff5c0 100644 --- a/server/src/locations/mod.rs +++ b/server/src/locations/mod.rs @@ -1,15 +1,3 @@ -use actix_web::web; - -mod details; -mod nearby; -mod preview; - -pub fn configure(cfg: &mut web::ServiceConfig) { - cfg.service(details::get_handler) - .service(nearby::nearby_handler) - .service(preview::maps_handler); - let tile_cache = std::env::temp_dir().join("tiles"); - if !tile_cache.exists() { - std::fs::create_dir(tile_cache).unwrap(); - } -} +pub mod details; +pub mod nearby; +pub mod preview; diff --git a/server/src/locations/nearby.rs b/server/src/locations/nearby.rs index 157b9deb4..c9c186aec 100644 --- a/server/src/locations/nearby.rs +++ b/server/src/locations/nearby.rs @@ -3,30 +3,52 @@ use actix_web::{get, web, HttpResponse}; use serde::{Deserialize, Serialize}; use tracing::error; -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, utoipa::ToSchema)] struct Transportation { id: String, name: String, parent_id: Option, parent_name: Option, - /// not really null, sqlx just thinks this - lat: Option, - /// not really null, sqlx just thinks this - lon: Option, - /// not really null, sqlx just thinks this - distance_meters: Option, + /// Latitude + #[schema(example = 48.26244490906312, nullable = false)] + lat: Option, // not really null, sqlx just thinks this + /// Longitude + #[schema(example = 48.26244490906312, nullable = false)] + lon: Option, // not really null, sqlx just thinks this + #[schema(exclusive_minimum = 0.0, nullable = false)] + distance_meters: Option, // not really null, sqlx just thinks this } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Clone, Debug, utoipa::ToSchema)] struct NearbyResponse { + #[schema(max_items = 50)] public_transport: Vec, } -#[get("/{id}/nearby")] +#[derive(Deserialize, utoipa::IntoParams)] +struct NearbyPathParams { + /// ID of a location + id: String, +} + +/// Get the nearby items +/// +/// Shows nearby POIs like public transport stations +#[utoipa::path( + tags=["locations"], + params(NearbyPathParams), + responses( + (status = 200, description = "Things **nearby to the location**", body=NearbyResponse, content_type = "application/json"), + (status = 404, description = "**Not found.** Make sure that requested item exists", body = String, content_type = "text/plain", example = "Not found"), + ) +)] +#[get("/api/locations/{id}/nearby")] pub async fn nearby_handler( - params: web::Path, + params: web::Path, data: web::Data, ) -> HttpResponse { - let id = params.into_inner(); + let id = params + .id + .replace(|c: char| c.is_whitespace() || c.is_control(), ""); // TODO: use the spatial index instead of just computing the distance for every entry let transportation = sqlx::query_as!( Transportation, diff --git a/server/src/locations/preview.rs b/server/src/locations/preview.rs index bd2294a34..9cc40bf38 100644 --- a/server/src/locations/preview.rs +++ b/server/src/locations/preview.rs @@ -59,7 +59,7 @@ async fn get_localised_data( error!("Error preparing statement: {e:?}"); return Err(HttpResponse::InternalServerError() .content_type("text/plain") - .body("Internal Server Error")); + .body("Could not get data for location, please try again later")); } } } @@ -172,7 +172,7 @@ async fn get_possible_redirect_url(pool: &PgPool, query: &str, args: &QueryArgs) } } -#[derive(Deserialize, Default, Debug, Copy, Clone)] +#[derive(Deserialize, Default, Debug, Copy, Clone, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] enum PreviewFormat { #[default] @@ -188,23 +188,39 @@ impl PreviewFormat { } } -#[derive(Deserialize, Default, Debug)] -#[serde(rename_all = "snake_case")] -#[serde(default)] +#[derive(Deserialize, Default, Debug, utoipa::IntoParams)] struct QueryArgs { #[serde(flatten)] lang: localisation::LangQueryArgs, format: PreviewFormat, } -#[get("/{id}/preview")] +#[derive(Deserialize, utoipa::IntoParams)] +struct MapsPathParams { + id: String, +} + +/// Get a entry-preview +/// +/// This returns a 1200x630px preview for the location (room/building/..). +/// +/// This is usefully for implementing custom OpenGraph images for detail previews. +#[utoipa::path( + tags=["locations"], + params(MapsPathParams, QueryArgs), + responses( + (status = 200, description = "**Preview image**", content_type="image/png"), + (status = 404, description = "**Not found.** Make sure that requested item exists", body = String, content_type = "text/plain", example = "Not found"), + ) +)] +#[get("/api/locations/{id}/preview")] pub async fn maps_handler( - params: web::Path, - web::Query(args): web::Query, + params: web::Path, + args: web::Query, data: web::Data, ) -> HttpResponse { let id = params - .into_inner() + .id .replace(|c: char| c.is_whitespace() || c.is_control(), ""); if let Some(redirect_url) = get_possible_redirect_url(&data.pool, &id, &args).await { return HttpResponse::PermanentRedirect() diff --git a/server/src/main.rs b/server/src/main.rs index 7de991515..163514158 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use std::sync::Arc; use actix_cors::Cors; +use actix_governor::{GlobalKeyExtractor, GovernorConfigBuilder}; use actix_middleware_etag::Etag; -use actix_web::web::Redirect; use actix_web::{get, middleware, web, App, HttpResponse, HttpServer, Responder}; use actix_web_prom::{PrometheusMetrics, PrometheusMetricsBuilder}; use meilisearch_sdk::client::Client; @@ -17,6 +17,7 @@ use tracing::{debug_span, error, info}; use tracing_actix_web::TracingLogger; mod calendar; +mod docs; mod feedback; mod limited; mod localisation; @@ -25,9 +26,12 @@ mod maps; mod models; mod search; mod setup; +use utoipa_actix_web::{scope, AppExt}; const MAX_JSON_PAYLOAD: usize = 1024 * 1024; // 1 MB +const SECONDS_PER_DAY: u64 = 60 * 60 * 24; + #[derive(Clone, Debug)] pub struct AppData { /// shared [sqlx::PgPool] to connect to postgis @@ -50,6 +54,16 @@ impl AppData { } } +/// API healthcheck +/// +/// If this endpoint does not return 200, the API is experiencing a catastrophic outage. +/// **Should never happen.** +#[utoipa::path( + responses( + (status = 200, description = "API is **healthy**", body = String, content_type = "text/plain", example="healthy\nsource_code: https://github.com/TUM-Dev/navigatum/tree/{hash}"), + (status = 503, description = "API is **NOT healthy**", body = String, content_type = "text/plain", example="unhealthy\nsource_code: https://github.com/TUM-Dev/navigatum/tree/{hash}"), + ) +)] #[get("/api/status")] async fn health_status_handler(data: web::Data) -> HttpResponse { let github_link = match option_env!("GIT_COMMIT_SHA") { @@ -68,15 +82,18 @@ async fn health_status_handler(data: web::Data) -> HttpResponse { } } } -#[get("/api/get/{id}")] -async fn details_redirect(params: web::Path) -> impl Responder { - let id = params.into_inner(); - Redirect::to(format!("https://nav.tum.de/locations/{id}")).permanent() -} -#[get("/api/preview/{id}")] -async fn preview_redirect(params: web::Path) -> impl Responder { - let id = params.into_inner(); - Redirect::to(format!("https://nav.tum.de/locations/{id}/preview")).permanent() + +/// Openapi service definition +/// +/// Usefull for consuming in external openapi tooling +#[utoipa::path( + responses( + (status = 200, description = "The openapi definition", content_type="application/json") + ) +)] +#[get("/api/openapi.json")] +async fn openapi_doc(openapi: web::Data) -> impl Responder { + HttpResponse::Ok().json(openapi) } fn connection_string() -> String { @@ -188,6 +205,15 @@ async fn run() -> anyhow::Result<()> { let prometheus = build_metrics(); let shutdown_pool_clone = data.pool.clone(); initialisation_started.wait().await; + // feedback specific initialisation + let feedback_ratelimit = GovernorConfigBuilder::default() + .key_extractor(GlobalKeyExtractor) + .seconds_per_request(SECONDS_PER_DAY / 300) // replenish new token every .. seconds + .burst_size(50) + .finish() + .expect("Invalid configuration of the governor"); + let recorded_tokens = web::Data::new(crate::feedback::tokens::RecordedTokens::default()); + info!("running the server"); HttpServer::new(move || { let cors = Cors::default() @@ -197,24 +223,35 @@ async fn run() -> anyhow::Result<()> { .max_age(3600) .send_wildcard(); - App::new() - .wrap(Etag) - .wrap(prometheus.clone()) - .wrap(cors) - .wrap(TracingLogger::default()) - .wrap(middleware::Compress::default()) - .wrap(sentry_actix::Sentry::new()) - .app_data(web::JsonConfig::default().limit(MAX_JSON_PAYLOAD)) - .app_data(web::Data::new(data.clone())) - .service(health_status_handler) - .service(calendar::calendar_handler) - .service(maps::indoor::list_indoor_maps) - .service(maps::indoor::get_indoor_map) - .service(search::search_handler) - .service(web::scope("/api/feedback").configure(feedback::configure)) - .service(web::scope("/api/locations").configure(locations::configure)) - .service(details_redirect) - .service(preview_redirect) + docs::add_openapi_docs( + App::new() + .wrap(Etag) + .wrap(prometheus.clone()) + .wrap(cors) + .wrap(TracingLogger::default()) + .wrap(middleware::Compress::default()) + .wrap(sentry_actix::Sentry::new()) + .app_data(web::JsonConfig::default().limit(MAX_JSON_PAYLOAD)) + .app_data(web::Data::new(data.clone())) + .into_utoipa_app() + .app_data(recorded_tokens.clone()) + .service(health_status_handler) + .service(calendar::calendar_handler) + .service(maps::indoor::list_indoor_maps) + .service(maps::indoor::get_indoor_map) + .service(search::search_handler) + .service(locations::details::get_handler) + .service(locations::nearby::nearby_handler) + .service(locations::preview::maps_handler) + .service(feedback::post_feedback::send_feedback) + .service(feedback::proposed_edits::propose_edits) + .service( + scope("/api/feedback/get_token") + .wrap(actix_governor::Governor::new(&feedback_ratelimit)) + .service(feedback::tokens::get_token), + ) + .service(openapi_doc), + ) }) .bind(std::env::var("BIND_ADDRESS").unwrap_or_else(|_| "0.0.0.0:3003".to_string()))? .run() diff --git a/server/src/maps/indoor.rs b/server/src/maps/indoor.rs index 8b2da3480..0e3b7fef1 100644 --- a/server/src/maps/indoor.rs +++ b/server/src/maps/indoor.rs @@ -34,7 +34,7 @@ ORDER BY ST_Distance(convex_hull::geometry, ST_SetSRID($1::geometry, 4326))"#, Ok(filtered_group_ids) } #[tracing::instrument(skip(pool))] -pub async fn fetch_indoor_map(pool: &PgPool, id: i64) -> anyhow::Result { +pub async fn fetch_indoor_map(pool: &PgPool, id: i64) -> anyhow::Result> { let row = sqlx::query( r#" SELECT features @@ -42,43 +42,81 @@ pub async fn fetch_indoor_map(pool: &PgPool, id: i64) -> anyhow::Result { + let value: serde_json::Value = row.get(0); + Some(value) + } + None => None, + }) +} - Ok(value) +#[derive(Deserialize, utoipa::IntoParams)] +struct IndoorPathParams { + /// ID of the indoor map + id: i64, } + +/// Get indoor features +/// +/// Get all features of a certain indoor map +#[utoipa::path( + tags=["maps"], + params(IndoorPathParams), + responses( + (status = 200, description = "**Indoor features** as GeoJSON", content_type = "application/json"), + (status = 404, description = "**Not found.** The requested location does not have a calendar", body = String, content_type = "text/plain", example = "Not found"), + ) +)] #[get("/api/maps/indoor/{id}")] pub async fn get_indoor_map( - params: web::Path, + params: web::Path, data: web::Data, ) -> HttpResponse { - let id = params.into_inner(); - let map = fetch_indoor_map(&data.pool, id).await; + let map = fetch_indoor_map(&data.pool, params.id).await; match map { - Ok(geometry) => HttpResponse::Ok() + Ok(None) => HttpResponse::NotFound() + .content_type("text/plain") + .body("Not found"), + Ok(Some(geometry)) => HttpResponse::Ok() .insert_header(CacheControl(vec![ CacheDirective::MaxAge(2 * 24 * 60 * 60), // valid for 2d CacheDirective::Public, ])) .json(geometry), Err(err) => { - error!("Failed to fetch indoor map {id} because {err:?}"); + error!( + "Failed to fetch indoor map {id} because {err:?}", + id = params.id + ); HttpResponse::InternalServerError() .content_type("text/plain") - .body("could get indoor maps, please try again later") + .body("Cannot fetch indoor map, please try again later") } } } -#[derive(Serialize)] +#[derive(Serialize, utoipa::ToSchema)] struct RemoteMap { + /// Name of the map + #[schema(example = "1234")] name: String, + /// Where the indoor GeoJSON is located at + #[schema(example = "https://nav.tum.de/api/maps/indoor/1234")] url: Url, } -#[derive(Deserialize)] +#[derive(Deserialize, utoipa::IntoParams, utoipa::ToSchema)] struct Arguments { + /// Requires the bbox to be 4 floating point numbers of format `"y,x,y,x"` + /// + /// Bounding box according to https://datatracker.ietf.org/doc/html/rfc7946#section-5 + #[schema( + pattern = "-?[\\d]+.[\\d]+,-?[\\d]+.[\\d]+,-?[\\d]+.[\\d]+,-?[\\d]+.[\\d]+", + example = "48.266600,11.669800,48.268470,11.670600" + )] bbox: String, } impl Arguments { @@ -100,6 +138,17 @@ impl Arguments { } } +/// Lists indoor maps in bounding box +/// +/// Returns all the available maps for a given bbox +#[utoipa::path( + tags=["maps"], + params(Arguments), + responses( + (status = 200, description = "**List indoor maps** in bounding box", body = Vec, content_type = "application/json"), + (status = 400, description = "**Bad Request.** Please check that the input provided matches above.", body = String, content_type = "text/plain", example = "the bbox-parameter needs 4 floating point numbers of format y,x,y,x"), + ) +)] #[get("/api/maps/indoor")] pub async fn list_indoor_maps( web::Query(args): web::Query, diff --git a/server/src/search/mod.rs b/server/src/search/mod.rs index 12a9b4a19..f7298e591 100644 --- a/server/src/search/mod.rs +++ b/server/src/search/mod.rs @@ -14,22 +14,95 @@ use unicode_truncate::UnicodeTruncateStr; mod search_executor; -#[derive(Deserialize, Debug, Default)] +#[derive(Deserialize, Debug, Default, utoipa::IntoParams, utoipa::ToSchema)] pub struct SearchQueryArgs { + /// string you want to search for. + /// + /// The amounts returned can be controlled using the `limit\*` paramerters. + /// + /// The following query-filters are supported: + /// - `in:`/`@`: Only return rooms in the given parent (e.g. `in:5304` or `in:garching`) + /// - `usage:`/`nutzung:`/`=`: Only return entries of the given usage (e.g. `usage:wc` or `usage:büro`) + /// - `type:`: Only return entries of the given type (e.g. `type:building` or `type:room`) + /// - `near:,`: prioritise sorting the entries by distance to a coordinate + #[schema( + min_length = 1, + examples( + "mi hs1", + "sfarching", + "5606.EG.036", + "interims", + "AStA", + "WC @garching" + ) + )] + // TODO ideally, this would be documented as below, but this does for some reaon not work. + // examples( + // ("mi hs1" = (summary = "\'misspelled\' (according to tumonline) lecture-hall", value = "mi hs1")), + // ("sfarching" = (summary = "misspelled campus garching", value = "sfarching")), + // ("5606.EG.036" = (summary = "regular room (fsmpic)", value = "5606.EG.036")), + // ("interims" = (summary = "\'interims\' Lecture halls", value = "interims")), + // ("AStA" = (summary = "common name synonyms for SV", value = "AStA")), + //))] q: String, + /// Include adresses in the saerch + /// + /// Be aware that Nominatim (which we use to do this search) is really slow (~100ms). + /// Only activate this when you really need it. search_addresses: Option, + /// Maximum number of buildings/sites to return. + /// + /// Clamped to `0`..`1000`. + /// If this is a problem for you, please open an issue. + #[schema(default = 5, maximum = 1000, minimum = 0)] limit_buildings: Option, + /// Maximum number of rooms to return. + /// + /// Clamped to `0`..`1000`. + /// If this is an problem for you, please open an issue. + #[schema(default = 10, maximum = 1000, minimum = 0)] limit_rooms: Option, + /// Maximum number of results to return. + /// + /// Clamped to `1`..`1000`. + /// If this is an problem for you, please open an issue. + #[schema(default = 10, maximum = 1000, minimum = 1)] limit_all: Option, + /// string to include in front of highlighted sequences. + /// + /// If this and `post_highlight` are empty, highlighting is disabled. + /// For background on the default values, please see [Wikipedia](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Modified_C0_control_code_sets)). + #[schema( + default = "/u0019", + max_length = 25, + max_length = 0, + examples("/u0019", "", "") + )] pre_highlight: Option, + /// string to include after the highlighted sequences. + /// + /// If this and `pre_highlight` are empty, highlighting is disabled. + /// For background on the default values, please see [Wikipedia](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Modified_C0_control_code_sets)). + #[schema( + default = "/u0017", + max_length = 25, + max_length = 0, + examples("/u0017", "", "") + )] post_highlight: Option, } /// Returned search results by this -#[derive(Serialize)] +#[derive(Serialize, utoipa::ToSchema)] pub struct SearchResults { sections: Vec, - time_ms: u128, + /// Time the search took in the server side, not including network delay + /// + /// Maximum as timeout. + /// other timeouts (browser, your client) may be smaller. + /// Expected average is `10`..`50` for uncached, regular requests. + #[schema(example = 8)] + time_ms: u32, } impl Debug for SearchResults { @@ -139,6 +212,26 @@ impl From<&SearchQueryArgs> for Highlighting { Self { pre, post } } } + +/// Search entries +/// +/// This endpoint is designed to support search-as-you-type results. +/// +/// Instead of simply returning a list, the search results are returned in a way to provide a richer experience by splitting them up into sections. You might not necessarily need to implement all types of sections, or all sections features (if you just want to show a list). The order of sections is a suggested order to display them, but you may change this as you like. +/// +/// Some fields support highlighting the query terms and it uses \x19 and \x17 to mark the beginning/end of a highlighted sequence. +/// (See [Wikipedia](https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Modified_C0_control_code_sets)). +/// Some text-renderers will ignore them, but in case you do not want to use them, you might want to remove them from the responses via empty `pre_highlight` and `post_highlight` query parameters. +#[utoipa::path( + tags=["locations"], + params(SearchQueryArgs), + responses( + (status = 200, description = "Search entries", body = Vec, content_type = "application/json"), + (status = 400, description= "**Bad Request.** Not all fields in the body are present as defined above", body = String, content_type = "text/plain", example = "Query deserialize error: invalid digit found in string"), + (status = 404, description = "**Not found.** `q` is empty. Since searching for nothing is nonsensical, we dont support this.", body = String, content_type = "text/plain", example = "Not found"), + (status = 414, description = "**URI Too Long.** The uri you are trying to request is unreasonably long. Search querys dont have thousands of chars..", body = String, content_type = "text/plain"), + ) +)] #[get("/api/search")] pub async fn search_handler( data: web::Data, @@ -162,11 +255,11 @@ pub async fn search_handler( ); return HttpResponse::InternalServerError() .content_type("text/plain") - .body("Internal error"); + .body("Cannot perform search, please try again later"); } let search_results = SearchResults { sections: results_sections, - time_ms: start_time.elapsed().as_millis(), + time_ms: start_time.elapsed().as_millis() as u32, }; HttpResponse::Ok() .insert_header(CacheControl(vec![ diff --git a/server/src/search/search_executor/mod.rs b/server/src/search/search_executor/mod.rs index af9e38e66..ea9256a5f 100644 --- a/server/src/search/search_executor/mod.rs +++ b/server/src/search/search_executor/mod.rs @@ -15,7 +15,7 @@ mod merger; mod parser; mod query; -#[derive(Serialize, Clone, Copy)] +#[derive(Serialize, Clone, Copy, utoipa::ToSchema)] #[serde(rename_all = "snake_case")] pub enum ResultFacet { SitesBuildings, @@ -23,12 +23,20 @@ pub enum ResultFacet { Addresses, } -#[derive(Serialize, Clone)] +#[derive(Serialize, Clone, utoipa::ToSchema)] pub struct ResultsSection { + /// These indicate the type of item this represents pub(crate) facet: ResultFacet, entries: Vec, + /// A recommendation how many of the entries should be displayed by default. + /// + /// The number is usually from `0`..`5`. + /// More results might be displayed when clicking "expand". + #[schema(example = 4)] n_visible: usize, + /// The estimated (not exact) number of hits for that query #[serde(rename = "estimatedTotalHits")] + #[schema(example = 6)] estimated_total_hits: usize, } @@ -47,16 +55,40 @@ impl Debug for ResultsSection { } } -#[derive(Serialize, Default, Debug, Clone)] +#[derive(Serialize, Default, Debug, Clone, utoipa::ToSchema)] struct ResultEntry { #[serde(skip)] hit: MSHit, + /// The id of the location + #[schema(example = "5510.03.002")] id: String, + /// the type of the site/building + #[schema(example = "room")] r#type: String, + /// Subtext to show below the search result. + /// + /// Usually contains the context of where this rooms is located in. + /// Currently not highlighted. + #[schema(example = "5510.03.002 (\x19MW\x17 2001, Empore)")] name: String, + /// Subtext to show below the search result. + /// + /// Usually contains the context of where this rooms is located in. + /// Currently not highlighted. + #[schema(example = "Maschinenwesen (MW)")] subtext: String, + /// Subtext to show below the search (by default in bold and after the non-bold subtext). + /// + /// Usually contains the arch-id of the room, which is another common room id format, and supports highlighting. #[serde(skip_serializing_if = "Option::is_none")] + #[schema(example = "3002@5510")] subtext_bold: Option, + /// This is an optional feature, that is only supported for some rooms. + /// + /// It might be displayed instead or before the name, to show that a different room id format has matched, that was probably used. + /// See the image below for an example. + /// It will be cropped to a maximum length to not take too much space in UIs. + /// Supports highlighting. #[serde(skip_serializing_if = "Option::is_none")] parsed_id: Option, } @@ -190,9 +222,10 @@ pub async fn do_geoentry_search( #[cfg(test)] mod test { + use std::fmt::{Display, Formatter}; + use super::*; use crate::setup::tests::MeiliSearchTestContainer; - use std::fmt::{Display, Formatter}; #[derive(serde::Deserialize)] struct TestQuery { diff --git a/server/src/setup/database/mod.rs b/server/src/setup/database/mod.rs index ff47ae9f3..d3f936fe9 100644 --- a/server/src/setup/database/mod.rs +++ b/server/src/setup/database/mod.rs @@ -106,17 +106,29 @@ async fn cleanup_deleted( tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> anyhow::Result<()> { let keys = &keys.0; - sqlx::query!("DELETE FROM aliases WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE aliases.key = expected.key)", keys) - .execute(&mut **tx) - .await?; - sqlx::query!("DELETE FROM en WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE en.key = expected.key)", keys) - .execute(&mut **tx) - .await?; - sqlx::query!("DELETE FROM calendar WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE calendar.room_code = expected.key)", keys) - .execute(&mut **tx) - .await?; - sqlx::query!("DELETE FROM de WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE de.key = expected.key)", keys) - .execute(&mut **tx) - .await?; + sqlx::query!( + "DELETE FROM aliases WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE aliases.key = expected.key)", + keys + ) + .execute(&mut **tx) + .await?; + sqlx::query!( + "DELETE FROM en WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE en.key = expected.key)", + keys + ) + .execute(&mut **tx) + .await?; + sqlx::query!( + "DELETE FROM calendar WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE calendar.room_code = expected.key)", + keys + ) + .execute(&mut **tx) + .await?; + sqlx::query!( + "DELETE FROM de WHERE NOT EXISTS (SELECT * FROM UNNEST($1::text[]) AS expected(key) WHERE de.key = expected.key)", + keys + ) + .execute(&mut **tx) + .await?; Ok(()) } diff --git a/webclient/app/components/AppFooter.vue b/webclient/app/components/AppFooter.vue index d506f9060..56d60cbcf 100644 --- a/webclient/app/components/AppFooter.vue +++ b/webclient/app/components/AppFooter.vue @@ -13,7 +13,7 @@ const navigation = computed(() => [ }, { name: t("api.text"), - href: "/api", + href: "https://nav.tum.de/api", }, { name: t("about.text"), diff --git a/webclient/app/components/SwaggerUI.vue b/webclient/app/components/SwaggerUI.vue deleted file mode 100644 index 22d2f9892..000000000 --- a/webclient/app/components/SwaggerUI.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/webclient/app/pages/api.vue b/webclient/app/pages/api.vue deleted file mode 100644 index ba8a7d339..000000000 --- a/webclient/app/pages/api.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/webclient/package.json b/webclient/package.json index 8e31d69cf..b6618558d 100644 --- a/webclient/package.json +++ b/webclient/package.json @@ -31,8 +31,6 @@ "nightwind": "1.1.13", "nuxt": "3.13.0", "sharp": "0.33.5", - "swagger-ui": "5.18.2", - "swaggerdark": "github:octycs/SwaggerDark#f02d394c8ff698cdd93e09c2188b058d2d686ca3", "vue": "3.5.13", "vue-router": "4.5.0", "vue3-carousel": "0.10.0" @@ -43,7 +41,6 @@ "@nuxtjs/tailwindcss": "6.12.2", "@types/geojson": "7946.0.15", "@types/nightwind": "1.0.0", - "@types/swagger-ui": "3.52.4", "@vue/tsconfig": "0.7.0", "autoprefixer": "10.4.20", "eslint": "9.17.0", diff --git a/webclient/pnpm-lock.yaml b/webclient/pnpm-lock.yaml index c222f3f83..aaf4b6577 100644 --- a/webclient/pnpm-lock.yaml +++ b/webclient/pnpm-lock.yaml @@ -62,12 +62,6 @@ importers: sharp: specifier: 0.33.5 version: 0.33.5 - swagger-ui: - specifier: 5.18.2 - version: 5.18.2 - swaggerdark: - specifier: github:octycs/SwaggerDark#f02d394c8ff698cdd93e09c2188b058d2d686ca3 - version: https://codeload.github.com/octycs/SwaggerDark/tar.gz/f02d394c8ff698cdd93e09c2188b058d2d686ca3 vue: specifier: 3.5.13 version: 3.5.13(typescript@5.7.2) @@ -93,9 +87,6 @@ importers: '@types/nightwind': specifier: 1.0.0 version: 1.0.0 - '@types/swagger-ui': - specifier: 3.52.4 - version: 3.52.4 '@vue/tsconfig': specifier: 0.7.0 version: 0.7.0(typescript@5.7.2)(vue@3.5.13(typescript@5.7.2)) @@ -354,14 +345,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime-corejs3@7.24.7': - resolution: {integrity: sha512-eytSX6JLBY6PVAeQa2bFlDx/7Mmln/gaEpsit5a3WEvjGfiIytEsgAwuIXCPM0xvw0v0cJn3ilq0/TvXrW0kgA==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.24.1': - resolution: {integrity: sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==} - engines: {node: '>=6.9.0'} - '@babel/standalone@7.24.3': resolution: {integrity: sha512-PbObiI21Z/1DoJLr6DKsdmyp7uUIuw6zv5zIMorH98rOBE/TehkjK7xqXiwJmbCqi7deVbIksDerZ9Ds9hRLGw==} engines: {node: '>=6.9.0'} @@ -394,9 +377,6 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} - '@braintree/sanitize-url@7.0.4': - resolution: {integrity: sha512-hPYRrKFoI+nuckPgDJfyYAkybFvheo4usS0Vw0HNAe+fmGBQA5Az37b/yStO284atBoqqdOUhKJ3d9Zw3PQkcQ==} - '@clack/core@0.3.5': resolution: {integrity: sha512-5cfhQNH+1VQ2xLQlmzXMqUoiaH0lRBq9/CLW9lTyMbuKLC3+xEK01tHVvyut++mLOn5urSHmkm6I0Lg9MaJSTQ==} @@ -1104,6 +1084,10 @@ packages: resolution: {integrity: sha512-bmsP4L2HqBF6i6uaMqJMcFBONVjKt+siGluRq4Ca4C0q7W2eMaVZr8iCgF9dKbcVXutftkC7D6z2SaSMmLiDyA==} engines: {node: '>= 16'} + '@intlify/shared@11.0.0': + resolution: {integrity: sha512-MLKIyFz37qYF1G5UQZMwGoJyp8DD3rtcXDplRHZdSOmbfOYbD4g9kJZ6qCsm1Ru3vee6CTnJcbO4LV1JeIDGbA==} + engines: {node: '>= 16'} + '@intlify/shared@11.0.0-rc.1': resolution: {integrity: sha512-8tR1xe7ZEbkabTuE/tNhzpolygUn9OaYp9yuYAF4MgDNZg06C3Qny80bes2/e9/Wm3aVkPUlCw6WgU7mQd0yEg==} engines: {node: '>= 16'} @@ -1665,9 +1649,6 @@ packages: cpu: [x64] os: [win32] - '@scarf/scarf@1.4.0': - resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - '@shikijs/core@1.22.2': resolution: {integrity: sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg==} @@ -1703,90 +1684,6 @@ packages: peerDependencies: eslint: '>=8.40.0' - '@swagger-api/apidom-ast@1.0.0-alpha.10': - resolution: {integrity: sha512-f4Y9t1oBlnsvMoLPCykzn5LRrmARiaPzorocQkMFTkYUPb7RKA4zCuWi67hH4iDVsVvkPutgew19XyJiI3OF9Q==} - - '@swagger-api/apidom-core@1.0.0-alpha.10': - resolution: {integrity: sha512-4uXIN8cLigD1SZUDhmrEwW+1zbrB6bbD9Hlpo/BF74t/Nh4ZoEOUXv1oR/8QXB9AsIkdO65FdDHyaPzyGbjMiQ==} - - '@swagger-api/apidom-error@1.0.0-alpha.10': - resolution: {integrity: sha512-ydHNOKTdp9jaeW2yBvdZazXNCVFPbzC2Dy3dtDWU3MwUtSryoefT9OUQFWL7NxzChFRneNhBEcVl4NRocitXeA==} - - '@swagger-api/apidom-json-pointer@1.0.0-alpha.10': - resolution: {integrity: sha512-Xo0v4Jxp0ZiAm+OOL2PSLyjiw5OAkCMxI0nN9+vOw1/mfXcC+tdb30QQ9WNtF7O9LExjznfFID/NnDEYqBRDwA==} - - '@swagger-api/apidom-ns-api-design-systems@1.0.0-alpha.5': - resolution: {integrity: sha512-aq9Ix2Wo2TMfYW3HmheTO3qVd2MYrdinjLFHn9uozzC2x+CSzALhvKkwOc29HiGOn4QQ6QHHPRojNgD86WkwUg==} - - '@swagger-api/apidom-ns-asyncapi-2@1.0.0-alpha.5': - resolution: {integrity: sha512-JFtQBhCOkYuyNVcYGMFd9+U0UO6lEj9kO5qCgUjPOTgkOpZOZQslVEtg3TDmRlBATwVdmRv39xy3ZLK8O/JdmQ==} - - '@swagger-api/apidom-ns-json-schema-draft-4@1.0.0-alpha.10': - resolution: {integrity: sha512-sNj4pAmxEfFYIqRcP9A7/gjNMaa7nu1pWT6gTMXtYROyo4XrChc3wit8F76WJEFIiEPLrPs2SrnnA5GIHM7EnA==} - - '@swagger-api/apidom-ns-json-schema-draft-6@1.0.0-alpha.5': - resolution: {integrity: sha512-ylh96E59aaV1VDv9sDrNwpTmjVT6vmOSncpmytlc0ynb374dwZkLZ63Hd30rcMFAhKmg5aYOG+i5O1QXKFYz8A==} - - '@swagger-api/apidom-ns-json-schema-draft-7@1.0.0-alpha.5': - resolution: {integrity: sha512-Mks9gabJvz4atkjzLDwjWbo12xirul7a9ifHYZQJc/jfVKfVNy1e3QgFG1+EbSWWG5Yfbr3WKyxUDJLgr75qKg==} - - '@swagger-api/apidom-ns-openapi-2@1.0.0-alpha.5': - resolution: {integrity: sha512-uY+1G4oRf9UT/6sGuatvWKstmlRnEiN9XqaVvV8euXESxI4jtwcPbRwoEX31vEYXoTqq2ZScFy8UQJ2CJ2ZADw==} - - '@swagger-api/apidom-ns-openapi-3-0@1.0.0-alpha.10': - resolution: {integrity: sha512-zF2tPojJBGmQ/GuX+QJ0BhBWmnC+ET8Zah9utKpYWFFjqG/Wl6YzWpyrEflXpfGFzDFgoo+R+/3QvzScbPssqg==} - - '@swagger-api/apidom-ns-openapi-3-1@1.0.0-alpha.10': - resolution: {integrity: sha512-/7o+/Z2LelLcOdDSeY8O467Tjmr4yp0c8T4l13+zoQlaJFCzoeJqUUzP/dyqLPxqSeSMOez7uXnYpii6F8uYcA==} - - '@swagger-api/apidom-ns-workflows-1@1.0.0-alpha.5': - resolution: {integrity: sha512-6cMv37y4kftJySoMAeubz5yhHaRKnSK0YglvCv8v7rE2OBduR/yEITDOej2/KFAnt29LxkhotSbNsmHx0weICQ==} - - '@swagger-api/apidom-parser-adapter-api-design-systems-json@1.0.0-alpha.5': - resolution: {integrity: sha512-QVWS2sPKA1sG52UIJut/St6+j7zO8QxzPlL5akR/8QPX2FWKqmw808Ewvjq9WLtqlPhVY2G33tv90d4/FJUNwQ==} - - '@swagger-api/apidom-parser-adapter-api-design-systems-yaml@1.0.0-alpha.5': - resolution: {integrity: sha512-T7UD/SWd5u2zlPyswDdtfAStm6Qt5hQWAWvCmQKxy37qJA9QGXcQKNavaSMPGvN660hufNaJEBxgJ/B0Zd5iaw==} - - '@swagger-api/apidom-parser-adapter-asyncapi-json-2@1.0.0-alpha.5': - resolution: {integrity: sha512-UfCS9DFIURTUfaHfmEn8omHaevIV2i24Ncp46M/Pnk6JwZHjAEMxmPxsgMl4TTGbzqvySUQsJka8Qz1ziYZ1og==} - - '@swagger-api/apidom-parser-adapter-asyncapi-yaml-2@1.0.0-alpha.5': - resolution: {integrity: sha512-X5avFyLnlu6Zjyul35f8Ff0DRE70aNc+Bk7il+eV8g+FR/qgrmuNziQEBOhCrIUnYB1kFbTty6BZRsNLdjW9XQ==} - - '@swagger-api/apidom-parser-adapter-json@1.0.0-alpha.5': - resolution: {integrity: sha512-NdVjlRrtr1EvrBsk6DHSkjI8zdnSve/bjeGgo0NR2IRmA/8BRcY6rffM1BR76Ku+CjxhCB2mfQxotilD71dL+g==} - - '@swagger-api/apidom-parser-adapter-openapi-json-2@1.0.0-alpha.5': - resolution: {integrity: sha512-qOwQl2WezfdDVmtf9ZlOiqT1hcDS52j7ZbBdH9MqMGJ+/mo6sv0qEY2ZXS104lWeRamgi4o/4o4jGqjZS1YrMg==} - - '@swagger-api/apidom-parser-adapter-openapi-json-3-0@1.0.0-alpha.5': - resolution: {integrity: sha512-t5oj7XteTu2Yh8uNkzXAcKU81CQky+q6Qt/ImQ/S6MGxpXJnWwgVfm/j/dH2wnHFKghNS3vgm6IewpojSbUw4w==} - - '@swagger-api/apidom-parser-adapter-openapi-json-3-1@1.0.0-alpha.5': - resolution: {integrity: sha512-w0G53HXYdzcespfa3atN90jVLDRoH9FU7XEWG4DvFWM90WGwuNscojcaB28r8pZMhSQAKMPxggh6PnmvK3gdEQ==} - - '@swagger-api/apidom-parser-adapter-openapi-yaml-2@1.0.0-alpha.5': - resolution: {integrity: sha512-nfeYRL0o6QwtKsyF30d2JmtW7fzoI/EYKSFgzaDm7IFlrQWMpB6BidpZKdk5MtYN4zvmfAM+lOhrqR7a5BvHMg==} - - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-0@1.0.0-alpha.5': - resolution: {integrity: sha512-HRziGD/YUcO21hmDIYNzwYivp/faeZRxcq8Gex7RLLhJZ60fGTJJ1k1yhWFPNSe9DEJUNBN949SDxMdZnGT9PQ==} - - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-1@1.0.0-alpha.5': - resolution: {integrity: sha512-aul2wSOvkdp9jQjSv1pvEGllVaDUnTKmRbCy7M/dFQyIhJQBvwW+/Cu//PprzAODtFNraOBjIXiJ5tVdv6NuIQ==} - - '@swagger-api/apidom-parser-adapter-workflows-json-1@1.0.0-alpha.5': - resolution: {integrity: sha512-R1LVe/gx7fRSCuDmmN3qScWonz6Xlaw11J+NAfiJzrNXBy1Qa1mCxgGs47w0slQN+FjYkVj5Y/q29jJgpUbLHA==} - - '@swagger-api/apidom-parser-adapter-workflows-yaml-1@1.0.0-alpha.5': - resolution: {integrity: sha512-W5wD+TdGNdW4aP9uqkxFbVmjWvLOXyV02VvyStyTlzxdUaPzKY3FGaxjxk8TGVRqwe2yEQVUc2zfGalrScA/Sg==} - - '@swagger-api/apidom-parser-adapter-yaml-1-2@1.0.0-alpha.5': - resolution: {integrity: sha512-21TIQPkB+Z4ekNj5dh1uN0dhOBBCPeK572YpooA/pBTFLeH6Wtildx7ZZYfpJEejHaQKaqoRx3hp0G42GDOb7g==} - - '@swagger-api/apidom-reference@1.0.0-alpha.10': - resolution: {integrity: sha512-aFG6EHC1NOa0IhawTiE8A8TffzmW0PSO5d+lpzvcJ0w7KbrYG6SFQF2L6lZppqGaIGWbmV0Mq3LDU9mgSVEqqQ==} - '@tanstack/virtual-core@3.2.0': resolution: {integrity: sha512-P5XgYoAw/vfW65byBbJQCw+cagdXDT/qH6wmABiLt4v4YBT2q2vqCOhihe+D1Nt325F/S/0Tkv6C5z0Lv+VBQQ==} @@ -1829,9 +1726,6 @@ packages: '@types/geojson@7946.0.15': resolution: {integrity: sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==} - '@types/hast@2.3.10': - resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} - '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -1865,27 +1759,18 @@ packages: '@types/pbf@3.0.5': resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} - '@types/ramda@0.30.0': - resolution: {integrity: sha512-DQtfqUbSB18iM9NHbQ++kVUDuBWHMr6T2FpW1XTiksYRGjq4WnNPZLt712OEHEBJs7aMyJ68Mf2kGMOP1srVVw==} - '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} '@types/supercluster@7.1.3': resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==} - '@types/swagger-ui@3.52.4': - resolution: {integrity: sha512-7NV7q8BfupqdQxr26OkM0g0YEPB9uXnKGzXadgcearvI9MoCHt3F72lPTX3fZZIlrr21DC0IK26wcDMZ37oFDA==} - '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} '@types/unist@3.0.2': resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} - '@types/use-sync-external-store@0.0.3': - resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} - '@types/web-bluetooth@0.0.20': resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} @@ -2301,9 +2186,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - apg-lite@1.0.3: - resolution: {integrity: sha512-lOoNkL7vN7PGdyQMFPey1aok2oVVqvs3n7UMFBRvQ9FoELSbKhgPc3rd7JptaGwCmo4125gLX9Cqb8ElvLCFaQ==} - aproba@2.0.0: resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} @@ -2327,9 +2209,6 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -2358,16 +2237,10 @@ packages: async@3.2.5: resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - autolinker@3.16.2: - resolution: {integrity: sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==} - autoprefixer@10.4.20: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -2375,9 +2248,6 @@ packages: peerDependencies: postcss: ^8.1.0 - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} - b4a@1.6.6: resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} @@ -2537,21 +2407,12 @@ packages: character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - character-entities-legacy@1.1.4: - resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} - character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - character-entities@1.2.4: - resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} - character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - character-reference-invalid@1.1.4: - resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} - character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} @@ -2577,9 +2438,6 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -2633,13 +2491,6 @@ packages: colorette@1.4.0: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - comma-separated-tokens@1.0.8: - resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} - comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -2709,10 +2560,6 @@ packages: cookie-es@1.2.2: resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - cookies@0.9.1: resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} engines: {node: '>= 0.8'} @@ -2721,15 +2568,9 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} - copy-to-clipboard@3.3.3: - resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - core-js-compat@3.39.0: resolution: {integrity: sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==} - core-js-pure@3.36.1: - resolution: {integrity: sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2793,9 +2634,6 @@ packages: resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} engines: {node: '>= 6'} - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -2917,10 +2755,6 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -2989,9 +2823,6 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.1.6: - resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==} - domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} @@ -3003,10 +2834,6 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} - drange@1.1.1: - resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} - engines: {node: '>=4'} - duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -3285,9 +3112,6 @@ packages: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} - fast-json-patch@3.1.1: - resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -3300,9 +3124,6 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - fault@1.0.4: - resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} - fdir@6.4.2: resolution: {integrity: sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==} peerDependencies: @@ -3350,27 +3171,10 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - - format@0.2.2: - resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} - engines: {node: '>=0.4.x'} - fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -3557,9 +3361,6 @@ packages: hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - hast-util-parse-selector@2.2.5: - resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} - hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} @@ -3578,9 +3379,6 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - hastscript@6.0.0: - resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} - hastscript@8.0.0: resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} @@ -3588,9 +3386,6 @@ packages: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} @@ -3661,10 +3456,6 @@ packages: image-meta@0.2.1: resolution: {integrity: sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==} - immutable@3.8.2: - resolution: {integrity: sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==} - engines: {node: '>=0.10.0'} - import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -3702,9 +3493,6 @@ packages: resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ioredis@5.4.1: resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} engines: {node: '>=12.22.0'} @@ -3720,15 +3508,9 @@ packages: resolution: {integrity: sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - is-alphabetical@1.0.4: - resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} - is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - is-alphanumerical@1.0.4: - resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} - is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} @@ -3749,9 +3531,6 @@ packages: is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - is-decimal@1.0.4: - resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} - is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -3789,9 +3568,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-hexadecimal@1.0.4: - resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} - is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} @@ -3882,9 +3658,6 @@ packages: resolution: {integrity: sha512-H5UpaUI+aHOqZXlYOaFP/8AzKsg+guWu+Pr3Y8i7+Y3zr1aXAvCvTAQ1RxSc6oVD8R8c7brgNtTVP91E7upH/g==} hasBin: true - js-file-download@0.4.12: - resolution: {integrity: sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==} - js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} @@ -4050,9 +3823,6 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} @@ -4077,13 +3847,6 @@ packages: longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lowlight@1.20.0: - resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} - lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} @@ -4307,10 +4070,6 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - minim@0.23.8: - resolution: {integrity: sha512-bjdr2xW1dBCMsMGGsUeqM4eFI60m94+szhxWys+B1ztIt6gWSfeGBdSVCIawezeHYLYn0j6zrsXdQS/JllBzww==} - engines: {node: '>=6'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4318,10 +4077,6 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} - minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -4395,9 +4150,6 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} - nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -4418,10 +4170,6 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - neotraverse@0.6.18: - resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} - engines: {node: '>= 10'} - nightwind@1.1.13: resolution: {integrity: sha512-ipTD+u64LXa03wDf1v0EawdsFC6vtS4xzzXknRd50BBtckDYzZAendkE+4VjSLrwQcTpk0XphWxFk4ORIDdrOg==} peerDependencies: @@ -4441,9 +4189,6 @@ packages: resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} engines: {node: '>=10'} - node-abort-controller@3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@6.1.0: resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} @@ -4451,18 +4196,10 @@ packages: resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} engines: {node: ^16 || ^18 || >= 20} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - node-emoji@2.1.3: resolution: {integrity: sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA==} engines: {node: '>=18'} - node-fetch-commonjs@3.3.2: - resolution: {integrity: sha512-VBlAiynj3VMLrotgwOS3OyECFxas5y7ltLcK4t41lMUZeaK15Ym4QRkqN0EQKAFL42q9i21EPKjzLUPfltR72A==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-fetch-native@1.6.4: resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} @@ -4589,14 +4326,6 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} - openapi-path-templating@1.6.0: - resolution: {integrity: sha512-1atBNwOUrZXthTvlvvX8k8ovFEF3iA8mDidYMkdOtvVdndBhTrspbwGXNOzEUaJhm9iUl4Tf5uQaeTLAJvwPig==} - engines: {node: '>=12.20.0'} - - openapi-server-url-templating@1.1.0: - resolution: {integrity: sha512-dtyTFKx2xVcO0W8JKaluXIHC9l/MLjHeflBaWjiWNMCHp/TBs9dEjQDbj/VFlHR4omFOKjjmqm1pW1aCAhmPBg==} - engines: {node: '>=12.20.0'} - openapi-typescript@6.7.6: resolution: {integrity: sha512-c/hfooPx+RBIOPM09GSxABOZhYPblDoyaGhqBkD/59vtpN21jEuWKDlM0KYTvqJVlSYjKs0tBcIdeXKChlSPtw==} hasBin: true @@ -4649,9 +4378,6 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-entities@2.0.0: - resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} - parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -5059,14 +4785,6 @@ packages: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} - prismjs@1.27.0: - resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} - engines: {node: '>=6'} - - prismjs@1.29.0: - resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} - engines: {node: '>=6'} - process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -5078,12 +4796,6 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - property-information@5.6.0: - resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} - property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} @@ -5093,9 +4805,6 @@ packages: protocols@2.0.1: resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} @@ -5103,9 +4812,6 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -5121,19 +4827,6 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - ramda-adjunct@5.0.1: - resolution: {integrity: sha512-UTQCcWnoiuYH+ua+jGg3GTktcmCSD2W7OO2++tmv8p2Ze+N9VgVACERg4g36rRfIXklVMtqazyBLBWXfoPKgRQ==} - engines: {node: '>=0.10.3'} - peerDependencies: - ramda: '>= 0.30.0' - - ramda@0.30.1: - resolution: {integrity: sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==} - - randexp@0.5.3: - resolution: {integrity: sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==} - engines: {node: '>=4'} - randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -5148,62 +4841,6 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-copy-to-clipboard@5.1.0: - resolution: {integrity: sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==} - peerDependencies: - react: ^15.3.0 || 16 || 17 || 18 - - react-debounce-input@3.3.0: - resolution: {integrity: sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA==} - peerDependencies: - react: ^15.3.0 || 16 || 17 || 18 - - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - - react-immutable-proptypes@2.2.0: - resolution: {integrity: sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==} - peerDependencies: - immutable: '>=3.6.2' - - react-immutable-pure-component@2.2.2: - resolution: {integrity: sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A==} - peerDependencies: - immutable: '>= 2 || >= 4.0.0-rc' - react: '>= 16.6' - react-dom: '>= 16.6' - - react-inspector@6.0.2: - resolution: {integrity: sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ==} - peerDependencies: - react: ^16.8.4 || ^17.0.0 || ^18.0.0 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-redux@9.1.2: - resolution: {integrity: sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==} - peerDependencies: - '@types/react': ^18.2.25 - react: ^18.0 - redux: ^5.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - redux: - optional: true - - react-syntax-highlighter@15.5.0: - resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==} - peerDependencies: - react: '>= 0.14.0' - - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -5245,24 +4882,10 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} - redux-immutable@4.0.0: - resolution: {integrity: sha512-SchSn/DWfGb3oAejd+1hhHx01xUoxY+V7TeK0BKqpkLKiQPVFf7DYzEaKmrEVxsWxielKfSK9/Xq66YyxgR1cg==} - peerDependencies: - immutable: ^3.8.1 || ^4.0.0-rc.1 - - redux@5.0.1: - resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - refractor@3.6.0: - resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} - - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regex@4.4.0: resolution: {integrity: sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==} @@ -5312,15 +4935,6 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - remarkable@2.0.1: - resolution: {integrity: sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==} - engines: {node: '>= 6.0.0'} - hasBin: true - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - replace-in-file@6.3.5: resolution: {integrity: sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg==} engines: {node: '>=10'} @@ -5334,12 +4948,6 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - - reselect@5.1.1: - resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -5362,10 +4970,6 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true - ret@0.2.2: - resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} - engines: {node: '>=4'} - reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -5412,9 +5016,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - scheduler@0.23.0: - resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} - scslre@0.3.0: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} @@ -5439,10 +5040,6 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} - serialize-error@8.1.0: - resolution: {integrity: sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==} - engines: {node: '>=10'} - serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -5466,10 +5063,6 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - sharp@0.32.6: resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} engines: {node: '>=14.15.0'} @@ -5492,10 +5085,6 @@ packages: shiki@1.22.2: resolution: {integrity: sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA==} - short-unique-id@5.0.3: - resolution: {integrity: sha512-yhniEILouC0s4lpH0h7rJsfylZdca10W9mDJRAFh3EpcSUanCHGb0R7kcFOIUCZYSAPo0PUD5ZxWQdW0T4xaug==} - hasBin: true - signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -5575,9 +5164,6 @@ packages: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} - space-separated-tokens@1.1.5: - resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} - space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -5604,9 +5190,6 @@ packages: resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} engines: {node: '>=0.10.0'} - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} @@ -5719,16 +5302,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - swagger-client@3.31.0: - resolution: {integrity: sha512-hVYift5XB8nOgNJVl6cbNtVTVPT2Fdx2wCOcIvuAFcyq0Mwe6+70ezoZ5WfiaIAzzwWfq72jyaLeg8TViGNSmw==} - - swagger-ui@5.18.2: - resolution: {integrity: sha512-zu28qHMVaXrL2T02xEnItoKQcS6tikJs6IJpzjoXexqJCqhwYAXOOypnXYMPkVfq9Ige67oPuUQvEGdeid0/Aw==} - - swaggerdark@https://codeload.github.com/octycs/SwaggerDark/tar.gz/f02d394c8ff698cdd93e09c2188b058d2d686ca3: - resolution: {tarball: https://codeload.github.com/octycs/SwaggerDark/tar.gz/f02d394c8ff698cdd93e09c2188b058d2d686ca3} - version: 1.0.0 - synckit@0.9.1: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5803,9 +5376,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -5821,15 +5391,6 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tree-sitter-json@0.20.2: - resolution: {integrity: sha512-eUxrowp4F1QEGk/i7Sa+Xl8Crlfp7J0AXxX1QdJEQKQYMWhgMbCIgyQvpO3Q0P9oyTrNQxRLlRipDS44a8EtRw==} - - tree-sitter-yaml@0.5.0: - resolution: {integrity: sha512-POJ4ZNXXSWIG/W4Rjuyg36MkUD4d769YRUGKRqN+sVaj/VCo6Dh6Pkssn1Rtewd5kybx+jT1BWMyWN0CijXnMA==} - - tree-sitter@0.20.4: - resolution: {integrity: sha512-rjfR5dc4knG3jnJNN/giJ9WOoN1zL/kZyrS0ILh+eqq8RNcIbiXA63JsMEgluug0aNvfQvK4BfCErN1vIzvKog==} - trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -5845,12 +5406,6 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ts-mixer@6.0.4: - resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - - ts-toolbelt@9.6.0: - resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==} - tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} @@ -5892,9 +5447,6 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - types-ramda@0.30.0: - resolution: {integrity: sha512-oVPw/KHB5M0Du0txTEKKM8xZOG9cZBRdCVXvwHYuNJUVkAiJ9oWyqkA+9Bj2gjMsHgkkhsYevobQBWs8I2/Xvw==} - typescript@5.7.2: resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} engines: {node: '>=14.17'} @@ -6017,9 +5569,6 @@ packages: resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==} engines: {node: '>=14.0.0'} - unraw@3.0.0: - resolution: {integrity: sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg==} - unstorage@1.10.2: resolution: {integrity: sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ==} peerDependencies: @@ -6144,17 +5693,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@8.0.2: resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} - use-sync-external-store@1.2.0: - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -6347,13 +5888,6 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - web-tree-sitter@0.20.3: - resolution: {integrity: sha512-zKGJW9r23y3BcJusbgvnOH2OYAW40MXAOi9bi3Gcc7T4Gms9WWgXF8m6adsJWpGJEhgOzCrfiz1IzKowJWrtYw==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -6420,16 +5954,10 @@ packages: utf-8-validate: optional: true - xml-but-prettier@1.0.1: - resolution: {integrity: sha512-C2CJaadHrZTqESlH03WOyw0oZTtoy2uEg6dSDF6YRg+9GnYNub53RRemLpnvtbHDFelxMx4LajiFsYeR6XJHgQ==} - xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} - xml@1.0.1: - resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} - xmlhttprequest-ssl@2.1.2: resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} engines: {node: '>=0.4.0'} @@ -6439,10 +5967,6 @@ packages: engines: {node: '>= 0.10.0'} hasBin: true - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -6485,9 +6009,6 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} - zenscroll@4.0.2: - resolution: {integrity: sha512-jEA1znR7b4C/NnaycInCU6h/d15ZzCd1jmsruqOKnZP6WXQSMH3W2GL+OXbkruslU4h+Tzuos0HdswzRUk/Vgg==} - zhead@2.2.4: resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==} @@ -6799,15 +6320,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/runtime-corejs3@7.24.7': - dependencies: - core-js-pure: 3.36.1 - regenerator-runtime: 0.14.1 - - '@babel/runtime@7.24.1': - dependencies: - regenerator-runtime: 0.14.1 - '@babel/standalone@7.24.3': {} '@babel/standalone@7.26.2': {} @@ -6862,8 +6374,6 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@braintree/sanitize-url@7.0.4': {} - '@clack/core@0.3.5': dependencies: picocolors: 1.1.1 @@ -7346,14 +6856,16 @@ snapshots: '@intlify/shared@10.0.5': {} + '@intlify/shared@11.0.0': {} + '@intlify/shared@11.0.0-rc.1': {} '@intlify/unplugin-vue-i18n@6.0.1(@vue/compiler-dom@3.5.13)(eslint@9.17.0(jiti@2.4.0))(rollup@4.24.4)(typescript@5.7.2)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.17.0(jiti@2.4.0)) '@intlify/bundle-utils': 10.0.0(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2))) - '@intlify/shared': 10.0.5 - '@intlify/vue-i18n-extensions': 7.0.0(@intlify/shared@10.0.5)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2)) + '@intlify/shared': 11.0.0 + '@intlify/vue-i18n-extensions': 7.0.0(@intlify/shared@11.0.0)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2)) '@rollup/pluginutils': 5.1.3(rollup@4.24.4) '@typescript-eslint/scope-manager': 8.13.0 '@typescript-eslint/typescript-estree': 8.13.0(typescript@5.7.2) @@ -7377,11 +6889,11 @@ snapshots: '@intlify/utils@0.13.0': {} - '@intlify/vue-i18n-extensions@7.0.0(@intlify/shared@10.0.5)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))': + '@intlify/vue-i18n-extensions@7.0.0(@intlify/shared@11.0.0)(@vue/compiler-dom@3.5.13)(vue-i18n@10.0.4(vue@3.5.13(typescript@5.7.2)))(vue@3.5.13(typescript@5.7.2))': dependencies: '@babel/parser': 7.26.2 optionalDependencies: - '@intlify/shared': 10.0.5 + '@intlify/shared': 11.0.0 '@vue/compiler-dom': 3.5.13 vue: 3.5.13(typescript@5.7.2) vue-i18n: 10.0.4(vue@3.5.13(typescript@5.7.2)) @@ -8393,8 +7905,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.24.4': optional: true - '@scarf/scarf@1.4.0': {} - '@shikijs/core@1.22.2': dependencies: '@shikijs/engine-javascript': 1.22.2 @@ -8444,338 +7954,6 @@ snapshots: - supports-color - typescript - '@swagger-api/apidom-ast@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - unraw: 3.0.0 - - '@swagger-api/apidom-core@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-ast': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - minim: 0.23.8 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - short-unique-id: 5.0.3 - ts-mixer: 6.0.4 - - '@swagger-api/apidom-error@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - - '@swagger-api/apidom-json-pointer@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - - '@swagger-api/apidom-ns-api-design-systems@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-ns-asyncapi-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-json-schema-draft-7': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-ns-json-schema-draft-4@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-ast': 1.0.0-alpha.10 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - - '@swagger-api/apidom-ns-json-schema-draft-6@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-json-schema-draft-4': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-ns-json-schema-draft-7@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-json-schema-draft-6': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-ns-openapi-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-json-schema-draft-4': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-ns-openapi-3-0@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-json-schema-draft-4': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - - '@swagger-api/apidom-ns-openapi-3-1@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-ast': 1.0.0-alpha.10 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-json-pointer': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-0': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - - '@swagger-api/apidom-ns-workflows-1@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - ts-mixer: 6.0.4 - optional: true - - '@swagger-api/apidom-parser-adapter-api-design-systems-json@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-api-design-systems': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-api-design-systems-yaml@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-api-design-systems': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-asyncapi-json-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-asyncapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-asyncapi-yaml-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-asyncapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-json@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-ast': 1.0.0-alpha.10 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - tree-sitter: 0.20.4 - tree-sitter-json: 0.20.2 - web-tree-sitter: 0.20.3 - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-json-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-json-3-0@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-0': 1.0.0-alpha.10 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-json-3-1@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-yaml-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-0@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-0': 1.0.0-alpha.10 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-1@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-workflows-json-1@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-workflows-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-workflows-yaml-1@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-workflows-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optional: true - - '@swagger-api/apidom-parser-adapter-yaml-1-2@1.0.0-alpha.5': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-ast': 1.0.0-alpha.10 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - tree-sitter: 0.20.4 - tree-sitter-yaml: 0.5.0 - web-tree-sitter: 0.20.3 - optional: true - - '@swagger-api/apidom-reference@1.0.0-alpha.10': - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@types/ramda': 0.30.0 - axios: 1.7.7 - minimatch: 7.4.6 - process: 0.11.10 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - optionalDependencies: - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-json-pointer': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-asyncapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-ns-openapi-2': 1.0.0-alpha.5 - '@swagger-api/apidom-ns-openapi-3-0': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-workflows-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-api-design-systems-json': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-api-design-systems-yaml': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-asyncapi-json-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-asyncapi-yaml-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-json': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-json-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-json-3-0': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-json-3-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-yaml-2': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-0': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-openapi-yaml-3-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-workflows-json-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-workflows-yaml-1': 1.0.0-alpha.5 - '@swagger-api/apidom-parser-adapter-yaml-1-2': 1.0.0-alpha.5 - transitivePeerDependencies: - - debug - '@tanstack/virtual-core@3.2.0': {} '@tanstack/vue-virtual@3.2.0(vue@3.5.13(typescript@5.7.2))': @@ -8834,10 +8012,6 @@ snapshots: '@types/geojson@7946.0.15': {} - '@types/hast@2.3.10': - dependencies: - '@types/unist': 2.0.10 - '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.2 @@ -8876,24 +8050,16 @@ snapshots: '@types/pbf@3.0.5': {} - '@types/ramda@0.30.0': - dependencies: - types-ramda: 0.30.0 - '@types/resolve@1.20.2': {} '@types/supercluster@7.1.3': dependencies: '@types/geojson': 7946.0.15 - '@types/swagger-ui@3.52.4': {} - '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} - '@types/use-sync-external-store@0.0.3': {} - '@types/web-bluetooth@0.0.20': {} '@typescript-eslint/eslint-plugin@8.18.0(@typescript-eslint/parser@8.18.0(eslint@9.17.0(jiti@2.4.0))(typescript@5.7.2))(eslint@9.17.0(jiti@2.4.0))(typescript@5.7.2)': @@ -9516,8 +8682,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - apg-lite@1.0.3: {} - aproba@2.0.0: {} archiver-utils@5.0.2: @@ -9549,10 +8713,6 @@ snapshots: arg@5.0.2: {} - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} arr-union@3.1.0: {} @@ -9577,14 +8737,8 @@ snapshots: async@3.2.5: {} - asynckit@0.4.0: {} - at-least-node@1.0.0: {} - autolinker@3.16.2: - dependencies: - tslib: 2.7.0 - autoprefixer@10.4.20(postcss@8.4.49): dependencies: browserslist: 4.23.3 @@ -9595,14 +8749,6 @@ snapshots: postcss: 8.4.49 postcss-value-parser: 4.2.0 - axios@1.7.7: - dependencies: - follow-redirects: 1.15.6 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - b4a@1.6.6: {} bail@2.0.2: {} @@ -9785,16 +8931,10 @@ snapshots: character-entities-html4@2.1.0: {} - character-entities-legacy@1.1.4: {} - character-entities-legacy@3.0.0: {} - character-entities@1.2.4: {} - character-entities@2.0.2: {} - character-reference-invalid@1.1.4: {} - character-reference-invalid@2.0.1: {} chokidar@3.6.0: @@ -9824,8 +8964,6 @@ snapshots: dependencies: consola: 3.2.3 - classnames@2.5.1: {} - clean-regexp@1.0.0: dependencies: escape-string-regexp: 1.0.5 @@ -9876,12 +9014,6 @@ snapshots: colorette@1.4.0: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - comma-separated-tokens@1.0.8: {} - comma-separated-tokens@2.0.3: {} commander@2.20.3: {} @@ -9930,8 +9062,6 @@ snapshots: cookie-es@1.2.2: {} - cookie@0.7.2: {} - cookies@0.9.1: dependencies: depd: 2.0.0 @@ -9941,16 +9071,10 @@ snapshots: dependencies: is-what: 4.1.16 - copy-to-clipboard@3.3.3: - dependencies: - toggle-selection: 1.0.6 - core-js-compat@3.39.0: dependencies: browserslist: 4.24.2 - core-js-pure@3.36.1: {} - core-util-is@1.0.3: {} crc-32@1.2.2: {} @@ -10008,8 +9132,6 @@ snapshots: css-what@6.1.0: {} - css.escape@1.5.1: {} - cssesc@3.0.0: {} cssfilter@0.0.10: @@ -10094,7 +9216,8 @@ snapshots: deep-equal@1.0.1: {} - deep-extend@0.6.0: {} + deep-extend@0.6.0: + optional: true deep-is@0.1.4: {} @@ -10113,8 +9236,6 @@ snapshots: defu@6.1.4: {} - delayed-stream@1.0.0: {} - delegates@1.0.0: {} denque@2.1.0: {} @@ -10163,8 +9284,6 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.1.6: {} - domutils@3.1.0: dependencies: dom-serializer: 2.0.0 @@ -10177,8 +9296,6 @@ snapshots: dotenv@16.4.5: {} - drange@1.1.1: {} - duplexer@0.1.2: {} earcut@3.0.0: {} @@ -10606,8 +9723,6 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-patch@3.1.1: {} - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -10618,10 +9733,6 @@ snapshots: dependencies: reusify: 1.0.4 - fault@1.0.4: - dependencies: - format: 0.2.2 - fdir@6.4.2(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 @@ -10663,21 +9774,11 @@ snapshots: flatted@3.3.1: {} - follow-redirects@1.15.6: {} - foreground-child@3.1.1: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - form-data@4.0.0: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - - format@0.2.2: {} - fraction.js@4.3.7: {} fresh@0.5.2: {} @@ -10897,8 +9998,6 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hast-util-parse-selector@2.2.5: {} - hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 @@ -10951,14 +10050,6 @@ snapshots: dependencies: '@types/hast': 3.0.4 - hastscript@6.0.0: - dependencies: - '@types/hast': 2.3.10 - comma-separated-tokens: 1.0.8 - hast-util-parse-selector: 2.2.5 - property-information: 5.6.0 - space-separated-tokens: 1.1.5 - hastscript@8.0.0: dependencies: '@types/hast': 3.0.4 @@ -10969,8 +10060,6 @@ snapshots: he@1.2.0: {} - highlight.js@10.7.3: {} - hookable@5.5.3: {} hosted-git-info@2.8.9: {} @@ -11042,8 +10131,6 @@ snapshots: image-meta@0.2.1: {} - immutable@3.8.2: {} - import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -11070,10 +10157,6 @@ snapshots: ini@4.1.3: {} - invariant@2.2.4: - dependencies: - loose-envify: 1.4.0 - ioredis@5.4.1: dependencies: '@ioredis/commands': 1.2.0 @@ -11127,15 +10210,8 @@ snapshots: is-absolute-url@4.0.1: {} - is-alphabetical@1.0.4: {} - is-alphabetical@2.0.1: {} - is-alphanumerical@1.0.4: - dependencies: - is-alphabetical: 1.0.4 - is-decimal: 1.0.4 - is-alphanumerical@2.0.1: dependencies: is-alphabetical: 2.0.1 @@ -11157,8 +10233,6 @@ snapshots: dependencies: hasown: 2.0.2 - is-decimal@1.0.4: {} - is-decimal@2.0.1: {} is-docker@2.2.1: {} @@ -11183,8 +10257,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-hexadecimal@1.0.4: {} - is-hexadecimal@2.0.1: {} is-https@4.0.0: {} @@ -11254,8 +10326,6 @@ snapshots: jiti@2.4.0: {} - js-file-download@0.4.12: {} - js-levenshtein@1.1.6: {} js-tokens@4.0.0: {} @@ -11467,8 +10537,6 @@ snapshots: dependencies: p-locate: 6.0.0 - lodash.debounce@4.0.8: {} - lodash.defaults@4.2.0: {} lodash.isarguments@3.1.0: {} @@ -11485,15 +10553,6 @@ snapshots: longest-streak@3.1.0: {} - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lowlight@1.20.0: - dependencies: - fault: 1.0.4 - highlight.js: 10.7.3 - lru-cache@10.2.0: optional: true @@ -11909,10 +10968,6 @@ snapshots: min-indent@1.0.1: {} - minim@0.23.8: - dependencies: - lodash: 4.17.21 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -11921,10 +10976,6 @@ snapshots: dependencies: brace-expansion: 2.0.1 - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -11996,9 +11047,6 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nan@2.19.0: - optional: true - nanoid@3.3.7: {} nanoid@5.0.7: {} @@ -12010,8 +11058,6 @@ snapshots: negotiator@0.6.3: {} - neotraverse@0.6.18: {} - nightwind@1.1.13(tailwindcss@3.4.17): dependencies: tailwindcss: 3.4.17 @@ -12115,15 +11161,11 @@ snapshots: semver: 7.6.3 optional: true - node-abort-controller@3.1.1: {} - node-addon-api@6.1.0: optional: true node-addon-api@7.1.0: {} - node-domexception@1.0.0: {} - node-emoji@2.1.3: dependencies: '@sindresorhus/is': 4.6.0 @@ -12131,11 +11173,6 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 - node-fetch-commonjs@3.3.2: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - node-fetch-native@1.6.4: {} node-fetch@2.7.0(encoding@0.1.13): @@ -12362,14 +11399,6 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 - openapi-path-templating@1.6.0: - dependencies: - apg-lite: 1.0.3 - - openapi-server-url-templating@1.1.0: - dependencies: - apg-lite: 1.0.3 - openapi-typescript@6.7.6: dependencies: ansi-colors: 4.1.3 @@ -12434,15 +11463,6 @@ snapshots: dependencies: callsites: 3.1.0 - parse-entities@2.0.0: - dependencies: - character-entities: 1.2.4 - character-entities-legacy: 1.1.4 - character-reference-invalid: 1.1.4 - is-alphanumerical: 1.0.4 - is-decimal: 1.0.4 - is-hexadecimal: 1.0.4 - parse-entities@4.0.1: dependencies: '@types/unist': 2.0.10 @@ -12785,10 +11805,6 @@ snapshots: pretty-bytes@6.1.1: {} - prismjs@1.27.0: {} - - prismjs@1.29.0: {} - process-nextick-args@2.0.1: {} process@0.11.10: {} @@ -12798,24 +11814,12 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - - property-information@5.6.0: - dependencies: - xtend: 4.0.2 - property-information@6.5.0: {} protocol-buffers-schema@3.6.0: {} protocols@2.0.1: {} - proxy-from-env@1.1.0: {} - pump@3.0.0: dependencies: end-of-stream: 1.4.4 @@ -12824,8 +11828,6 @@ snapshots: punycode@2.3.1: {} - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} queue-tick@1.0.1: {} @@ -12836,17 +11838,6 @@ snapshots: radix3@1.1.2: {} - ramda-adjunct@5.0.1(ramda@0.30.1): - dependencies: - ramda: 0.30.1 - - ramda@0.30.1: {} - - randexp@0.5.3: - dependencies: - drange: 1.1.1 - ret: 0.2.2 - randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -12866,62 +11857,6 @@ snapshots: strip-json-comments: 2.0.1 optional: true - react-copy-to-clipboard@5.1.0(react@18.2.0): - dependencies: - copy-to-clipboard: 3.3.3 - prop-types: 15.8.1 - react: 18.2.0 - - react-debounce-input@3.3.0(react@18.2.0): - dependencies: - lodash.debounce: 4.0.8 - prop-types: 15.8.1 - react: 18.2.0 - - react-dom@18.2.0(react@18.2.0): - dependencies: - loose-envify: 1.4.0 - react: 18.2.0 - scheduler: 0.23.0 - - react-immutable-proptypes@2.2.0(immutable@3.8.2): - dependencies: - immutable: 3.8.2 - invariant: 2.2.4 - - react-immutable-pure-component@2.2.2(immutable@3.8.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): - dependencies: - immutable: 3.8.2 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - - react-inspector@6.0.2(react@18.2.0): - dependencies: - react: 18.2.0 - - react-is@16.13.1: {} - - react-redux@9.1.2(react@18.2.0)(redux@5.0.1): - dependencies: - '@types/use-sync-external-store': 0.0.3 - react: 18.2.0 - use-sync-external-store: 1.2.0(react@18.2.0) - optionalDependencies: - redux: 5.0.1 - - react-syntax-highlighter@15.5.0(react@18.2.0): - dependencies: - '@babel/runtime': 7.24.1 - highlight.js: 10.7.3 - lowlight: 1.20.0 - prismjs: 1.29.0 - react: 18.2.0 - refractor: 3.6.0 - - react@18.2.0: - dependencies: - loose-envify: 1.4.0 - read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -12979,24 +11914,10 @@ snapshots: dependencies: redis-errors: 1.2.0 - redux-immutable@4.0.0(immutable@3.8.2): - dependencies: - immutable: 3.8.2 - - redux@5.0.1: {} - refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.1 - refractor@3.6.0: - dependencies: - hastscript: 6.0.0 - parse-entities: 2.0.0 - prismjs: 1.27.0 - - regenerator-runtime@0.14.1: {} - regex@4.4.0: {} regexp-ast-analysis@0.7.1: @@ -13109,13 +12030,6 @@ snapshots: mdast-util-to-markdown: 2.1.0 unified: 11.0.5 - remarkable@2.0.1: - dependencies: - argparse: 1.0.10 - autolinker: 3.16.2 - - repeat-string@1.6.1: {} - replace-in-file@6.3.5: dependencies: chalk: 4.1.2 @@ -13126,10 +12040,6 @@ snapshots: require-from-string@2.0.2: {} - requires-port@1.0.0: {} - - reselect@5.1.1: {} - resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -13151,8 +12061,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - ret@0.2.2: {} - reusify@1.0.4: {} rfdc@1.4.1: {} @@ -13209,10 +12117,6 @@ snapshots: safer-buffer@2.1.2: optional: true - scheduler@0.23.0: - dependencies: - loose-envify: 1.4.0 - scslre@0.3.0: dependencies: '@eslint-community/regexpp': 4.12.1 @@ -13245,10 +12149,6 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-error@8.1.0: - dependencies: - type-fest: 0.20.2 - serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -13279,11 +12179,6 @@ snapshots: setprototypeof@1.2.0: {} - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - sharp@0.32.6: dependencies: color: 4.2.3 @@ -13339,8 +12234,6 @@ snapshots: '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 - short-unique-id@5.0.3: {} - signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -13429,8 +12322,6 @@ snapshots: source-map@0.7.4: {} - space-separated-tokens@1.1.5: {} - space-separated-tokens@2.0.2: {} spdx-correct@3.2.0: @@ -13458,8 +12349,6 @@ snapshots: dependencies: extend-shallow: 3.0.2 - sprintf-js@1.0.3: {} - stable-hash@0.0.4: {} standard-as-callback@2.1.0: {} @@ -13579,73 +12468,6 @@ snapshots: csso: 5.0.5 picocolors: 1.1.1 - swagger-client@3.31.0: - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@scarf/scarf': 1.4.0 - '@swagger-api/apidom-core': 1.0.0-alpha.10 - '@swagger-api/apidom-error': 1.0.0-alpha.10 - '@swagger-api/apidom-json-pointer': 1.0.0-alpha.10 - '@swagger-api/apidom-ns-openapi-3-1': 1.0.0-alpha.10 - '@swagger-api/apidom-reference': 1.0.0-alpha.10 - cookie: 0.7.2 - deepmerge: 4.3.1 - fast-json-patch: 3.1.1 - js-yaml: 4.1.0 - neotraverse: 0.6.18 - node-abort-controller: 3.1.1 - node-fetch-commonjs: 3.3.2 - openapi-path-templating: 1.6.0 - openapi-server-url-templating: 1.1.0 - ramda: 0.30.1 - ramda-adjunct: 5.0.1(ramda@0.30.1) - transitivePeerDependencies: - - debug - - swagger-ui@5.18.2: - dependencies: - '@babel/runtime-corejs3': 7.24.7 - '@braintree/sanitize-url': 7.0.4 - '@scarf/scarf': 1.4.0 - base64-js: 1.5.1 - classnames: 2.5.1 - css.escape: 1.5.1 - deep-extend: 0.6.0 - dompurify: 3.1.6 - ieee754: 1.2.1 - immutable: 3.8.2 - js-file-download: 0.4.12 - js-yaml: 4.1.0 - lodash: 4.17.21 - prop-types: 15.8.1 - randexp: 0.5.3 - randombytes: 2.1.0 - react: 18.2.0 - react-copy-to-clipboard: 5.1.0(react@18.2.0) - react-debounce-input: 3.3.0(react@18.2.0) - react-dom: 18.2.0(react@18.2.0) - react-immutable-proptypes: 2.2.0(immutable@3.8.2) - react-immutable-pure-component: 2.2.2(immutable@3.8.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - react-inspector: 6.0.2(react@18.2.0) - react-redux: 9.1.2(react@18.2.0)(redux@5.0.1) - react-syntax-highlighter: 15.5.0(react@18.2.0) - redux: 5.0.1 - redux-immutable: 4.0.0(immutable@3.8.2) - remarkable: 2.0.1 - reselect: 5.1.1 - serialize-error: 8.1.0 - sha.js: 2.4.11 - swagger-client: 3.31.0 - url-parse: 1.5.10 - xml: 1.0.1 - xml-but-prettier: 1.0.1 - zenscroll: 4.0.2 - transitivePeerDependencies: - - '@types/react' - - debug - - swaggerdark@https://codeload.github.com/octycs/SwaggerDark/tar.gz/f02d394c8ff698cdd93e09c2188b058d2d686ca3: {} - synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 @@ -13769,8 +12591,6 @@ snapshots: dependencies: is-number: 7.0.0 - toggle-selection@1.0.6: {} - toidentifier@1.0.1: {} tosource@2.0.0-alpha.3: {} @@ -13779,22 +12599,6 @@ snapshots: tr46@0.0.3: {} - tree-sitter-json@0.20.2: - dependencies: - nan: 2.19.0 - optional: true - - tree-sitter-yaml@0.5.0: - dependencies: - nan: 2.19.0 - optional: true - - tree-sitter@0.20.4: - dependencies: - nan: 2.19.0 - prebuild-install: 7.1.2 - optional: true - trim-lines@3.0.1: {} trough@2.2.0: {} @@ -13805,10 +12609,6 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-mixer@6.0.4: {} - - ts-toolbelt@9.6.0: {} - tslib@2.6.3: optional: true @@ -13840,10 +12640,6 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - types-ramda@0.30.0: - dependencies: - ts-toolbelt: 9.6.0 - typescript@5.7.2: {} typewise-core@1.2.0: {} @@ -14056,8 +12852,6 @@ snapshots: acorn: 8.14.0 webpack-virtual-modules: 0.6.2 - unraw@3.0.0: {} - unstorage@1.10.2(ioredis@5.4.1): dependencies: anymatch: 3.1.3 @@ -14154,17 +12948,8 @@ snapshots: dependencies: punycode: 2.3.1 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - urlpattern-polyfill@8.0.2: {} - use-sync-external-store@1.2.0(react@18.2.0): - dependencies: - react: 18.2.0 - util-deprecate@1.0.2: {} validate-npm-package-license@3.0.4: @@ -14363,11 +13148,6 @@ snapshots: web-namespaces@2.0.1: {} - web-streams-polyfill@3.3.3: {} - - web-tree-sitter@0.20.3: - optional: true - webidl-conversions@3.0.1: {} webpack-sources@3.2.3: {} @@ -14413,14 +13193,8 @@ snapshots: ws@8.18.0: {} - xml-but-prettier@1.0.1: - dependencies: - repeat-string: 1.6.1 - xml-name-validator@4.0.0: {} - xml@1.0.1: {} - xmlhttprequest-ssl@2.1.2: {} xss@1.0.15: @@ -14429,8 +13203,6 @@ snapshots: cssfilter: 0.0.10 optional: true - xtend@4.0.2: {} - y18n@5.0.8: {} yallist@3.1.1: {} @@ -14465,8 +13237,6 @@ snapshots: yocto-queue@1.0.0: {} - zenscroll@4.0.2: {} - zhead@2.2.4: {} zip-stream@6.0.1: