From df056d6f1ec3a9d7f5b28771eebc82e4d4436350 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Tue, 22 Sep 2026 23:50:33 +0200 Subject: [PATCH 01/17] ref: reorganize ADR collection and add ADR-027 --- .../001-centralize-signing-key-management.md | 0 .../en/adr}/002-encrypt-keystore-at-rest.md | 0 ...ing-key-lifecycle-immutable-transitions.md | 0 .../en/adr}/004-token-key-bindings-domain.md | 0 .../en/adr}/005-public-keys-via-jwks.md | 0 .../en/adr}/006-kid-as-generated-guid.md | 0 .../007-default-signing-algorithm-rsa-4096.md | 0 .../adr}/008-standardized-error-response.md | 0 .../en/adr}/009-dynamic-plugin-discovery.md | 0 .../adr}/010-plugin-loading-from-directory.md | 0 ...-persisted-as-singleton-marten-document.md | 0 ...-token-key-bindings-persisted-in-marten.md | 0 .../adr}/013-dual-rest-and-grpc-transport.md | 0 .../014-error-responses-via-middleware.md | 0 .../015-keycloak-external-jwt-authority.md | 0 ...016-marten-and-wolverine-infrastructure.md | 0 ...pi-key-credential-extraction-strategies.md | 0 ...urity-scheme-contract-explicit-handling.md | 0 .../en/adr}/019-plugin-metadata-attribute.md | 0 .../en/adr}/020-devtools-plugin.md | 0 .../021-swagger-serving-via-reflection.md | 0 ...lugin-configuration-context-and-builder.md | 0 .../023-plugin-application-pipeline-hooks.md | 0 ...24-plugin-lifecycle-and-hosted-services.md | 0 ...options-openapi-and-marten-integrations.md | 4 +- ...-authentication-and-authorization-hooks.md | 0 .../en/adr/027-devtools-ui-typescript.md | 39 +++++++ ...tract-and-dynamic-loading-architecture.md} | 6 +- .../029-structured-plugin-health-contract.md} | 8 +- Docs/content/en/adr/README.md | 109 ++++++++++++++++++ 30 files changed, 157 insertions(+), 9 deletions(-) rename Docs/{ADR => content/en/adr}/001-centralize-signing-key-management.md (100%) rename Docs/{ADR => content/en/adr}/002-encrypt-keystore-at-rest.md (100%) rename Docs/{ADR => content/en/adr}/003-signing-key-lifecycle-immutable-transitions.md (100%) rename Docs/{ADR => content/en/adr}/004-token-key-bindings-domain.md (100%) rename Docs/{ADR => content/en/adr}/005-public-keys-via-jwks.md (100%) rename Docs/{ADR => content/en/adr}/006-kid-as-generated-guid.md (100%) rename Docs/{ADR => content/en/adr}/007-default-signing-algorithm-rsa-4096.md (100%) rename Docs/{ADR => content/en/adr}/008-standardized-error-response.md (100%) rename Docs/{ADR => content/en/adr}/009-dynamic-plugin-discovery.md (100%) rename Docs/{ADR => content/en/adr}/010-plugin-loading-from-directory.md (100%) rename Docs/{ADR => content/en/adr}/011-keystore-persisted-as-singleton-marten-document.md (100%) rename Docs/{ADR => content/en/adr}/012-token-key-bindings-persisted-in-marten.md (100%) rename Docs/{ADR => content/en/adr}/013-dual-rest-and-grpc-transport.md (100%) rename Docs/{ADR => content/en/adr}/014-error-responses-via-middleware.md (100%) rename Docs/{ADR => content/en/adr}/015-keycloak-external-jwt-authority.md (100%) rename Docs/{ADR => content/en/adr}/016-marten-and-wolverine-infrastructure.md (100%) rename Docs/{ADR => content/en/adr}/017-api-key-credential-extraction-strategies.md (100%) rename Docs/{ADR => content/en/adr}/018-security-scheme-contract-explicit-handling.md (100%) rename Docs/{ADR => content/en/adr}/019-plugin-metadata-attribute.md (100%) rename Docs/{ADR => content/en/adr}/020-devtools-plugin.md (100%) rename Docs/{ADR => content/en/adr}/021-swagger-serving-via-reflection.md (100%) rename Docs/{ADR => content/en/adr}/022-plugin-configuration-context-and-builder.md (100%) rename Docs/{ADR => content/en/adr}/023-plugin-application-pipeline-hooks.md (100%) rename Docs/{ADR => content/en/adr}/024-plugin-lifecycle-and-hosted-services.md (100%) rename Docs/{ADR => content/en/adr}/025-plugin-options-openapi-and-marten-integrations.md (96%) rename Docs/{ADR => content/en/adr}/026-plugin-authentication-and-authorization-hooks.md (100%) create mode 100644 Docs/content/en/adr/027-devtools-ui-typescript.md rename Docs/{ADR/017-Plugin-Contract-and-Dynamic-Loading-Architecture.md => content/en/adr/028-plugin-contract-and-dynamic-loading-architecture.md} (97%) rename Docs/{ADR/025-structured-plugin-health-contract.md => content/en/adr/029-structured-plugin-health-contract.md} (92%) create mode 100644 Docs/content/en/adr/README.md diff --git a/Docs/ADR/001-centralize-signing-key-management.md b/Docs/content/en/adr/001-centralize-signing-key-management.md similarity index 100% rename from Docs/ADR/001-centralize-signing-key-management.md rename to Docs/content/en/adr/001-centralize-signing-key-management.md diff --git a/Docs/ADR/002-encrypt-keystore-at-rest.md b/Docs/content/en/adr/002-encrypt-keystore-at-rest.md similarity index 100% rename from Docs/ADR/002-encrypt-keystore-at-rest.md rename to Docs/content/en/adr/002-encrypt-keystore-at-rest.md diff --git a/Docs/ADR/003-signing-key-lifecycle-immutable-transitions.md b/Docs/content/en/adr/003-signing-key-lifecycle-immutable-transitions.md similarity index 100% rename from Docs/ADR/003-signing-key-lifecycle-immutable-transitions.md rename to Docs/content/en/adr/003-signing-key-lifecycle-immutable-transitions.md diff --git a/Docs/ADR/004-token-key-bindings-domain.md b/Docs/content/en/adr/004-token-key-bindings-domain.md similarity index 100% rename from Docs/ADR/004-token-key-bindings-domain.md rename to Docs/content/en/adr/004-token-key-bindings-domain.md diff --git a/Docs/ADR/005-public-keys-via-jwks.md b/Docs/content/en/adr/005-public-keys-via-jwks.md similarity index 100% rename from Docs/ADR/005-public-keys-via-jwks.md rename to Docs/content/en/adr/005-public-keys-via-jwks.md diff --git a/Docs/ADR/006-kid-as-generated-guid.md b/Docs/content/en/adr/006-kid-as-generated-guid.md similarity index 100% rename from Docs/ADR/006-kid-as-generated-guid.md rename to Docs/content/en/adr/006-kid-as-generated-guid.md diff --git a/Docs/ADR/007-default-signing-algorithm-rsa-4096.md b/Docs/content/en/adr/007-default-signing-algorithm-rsa-4096.md similarity index 100% rename from Docs/ADR/007-default-signing-algorithm-rsa-4096.md rename to Docs/content/en/adr/007-default-signing-algorithm-rsa-4096.md diff --git a/Docs/ADR/008-standardized-error-response.md b/Docs/content/en/adr/008-standardized-error-response.md similarity index 100% rename from Docs/ADR/008-standardized-error-response.md rename to Docs/content/en/adr/008-standardized-error-response.md diff --git a/Docs/ADR/009-dynamic-plugin-discovery.md b/Docs/content/en/adr/009-dynamic-plugin-discovery.md similarity index 100% rename from Docs/ADR/009-dynamic-plugin-discovery.md rename to Docs/content/en/adr/009-dynamic-plugin-discovery.md diff --git a/Docs/ADR/010-plugin-loading-from-directory.md b/Docs/content/en/adr/010-plugin-loading-from-directory.md similarity index 100% rename from Docs/ADR/010-plugin-loading-from-directory.md rename to Docs/content/en/adr/010-plugin-loading-from-directory.md diff --git a/Docs/ADR/011-keystore-persisted-as-singleton-marten-document.md b/Docs/content/en/adr/011-keystore-persisted-as-singleton-marten-document.md similarity index 100% rename from Docs/ADR/011-keystore-persisted-as-singleton-marten-document.md rename to Docs/content/en/adr/011-keystore-persisted-as-singleton-marten-document.md diff --git a/Docs/ADR/012-token-key-bindings-persisted-in-marten.md b/Docs/content/en/adr/012-token-key-bindings-persisted-in-marten.md similarity index 100% rename from Docs/ADR/012-token-key-bindings-persisted-in-marten.md rename to Docs/content/en/adr/012-token-key-bindings-persisted-in-marten.md diff --git a/Docs/ADR/013-dual-rest-and-grpc-transport.md b/Docs/content/en/adr/013-dual-rest-and-grpc-transport.md similarity index 100% rename from Docs/ADR/013-dual-rest-and-grpc-transport.md rename to Docs/content/en/adr/013-dual-rest-and-grpc-transport.md diff --git a/Docs/ADR/014-error-responses-via-middleware.md b/Docs/content/en/adr/014-error-responses-via-middleware.md similarity index 100% rename from Docs/ADR/014-error-responses-via-middleware.md rename to Docs/content/en/adr/014-error-responses-via-middleware.md diff --git a/Docs/ADR/015-keycloak-external-jwt-authority.md b/Docs/content/en/adr/015-keycloak-external-jwt-authority.md similarity index 100% rename from Docs/ADR/015-keycloak-external-jwt-authority.md rename to Docs/content/en/adr/015-keycloak-external-jwt-authority.md diff --git a/Docs/ADR/016-marten-and-wolverine-infrastructure.md b/Docs/content/en/adr/016-marten-and-wolverine-infrastructure.md similarity index 100% rename from Docs/ADR/016-marten-and-wolverine-infrastructure.md rename to Docs/content/en/adr/016-marten-and-wolverine-infrastructure.md diff --git a/Docs/ADR/017-api-key-credential-extraction-strategies.md b/Docs/content/en/adr/017-api-key-credential-extraction-strategies.md similarity index 100% rename from Docs/ADR/017-api-key-credential-extraction-strategies.md rename to Docs/content/en/adr/017-api-key-credential-extraction-strategies.md diff --git a/Docs/ADR/018-security-scheme-contract-explicit-handling.md b/Docs/content/en/adr/018-security-scheme-contract-explicit-handling.md similarity index 100% rename from Docs/ADR/018-security-scheme-contract-explicit-handling.md rename to Docs/content/en/adr/018-security-scheme-contract-explicit-handling.md diff --git a/Docs/ADR/019-plugin-metadata-attribute.md b/Docs/content/en/adr/019-plugin-metadata-attribute.md similarity index 100% rename from Docs/ADR/019-plugin-metadata-attribute.md rename to Docs/content/en/adr/019-plugin-metadata-attribute.md diff --git a/Docs/ADR/020-devtools-plugin.md b/Docs/content/en/adr/020-devtools-plugin.md similarity index 100% rename from Docs/ADR/020-devtools-plugin.md rename to Docs/content/en/adr/020-devtools-plugin.md diff --git a/Docs/ADR/021-swagger-serving-via-reflection.md b/Docs/content/en/adr/021-swagger-serving-via-reflection.md similarity index 100% rename from Docs/ADR/021-swagger-serving-via-reflection.md rename to Docs/content/en/adr/021-swagger-serving-via-reflection.md diff --git a/Docs/ADR/022-plugin-configuration-context-and-builder.md b/Docs/content/en/adr/022-plugin-configuration-context-and-builder.md similarity index 100% rename from Docs/ADR/022-plugin-configuration-context-and-builder.md rename to Docs/content/en/adr/022-plugin-configuration-context-and-builder.md diff --git a/Docs/ADR/023-plugin-application-pipeline-hooks.md b/Docs/content/en/adr/023-plugin-application-pipeline-hooks.md similarity index 100% rename from Docs/ADR/023-plugin-application-pipeline-hooks.md rename to Docs/content/en/adr/023-plugin-application-pipeline-hooks.md diff --git a/Docs/ADR/024-plugin-lifecycle-and-hosted-services.md b/Docs/content/en/adr/024-plugin-lifecycle-and-hosted-services.md similarity index 100% rename from Docs/ADR/024-plugin-lifecycle-and-hosted-services.md rename to Docs/content/en/adr/024-plugin-lifecycle-and-hosted-services.md diff --git a/Docs/ADR/025-plugin-options-openapi-and-marten-integrations.md b/Docs/content/en/adr/025-plugin-options-openapi-and-marten-integrations.md similarity index 96% rename from Docs/ADR/025-plugin-options-openapi-and-marten-integrations.md rename to Docs/content/en/adr/025-plugin-options-openapi-and-marten-integrations.md index 3b92f13..0b0115a 100644 --- a/Docs/ADR/025-plugin-options-openapi-and-marten-integrations.md +++ b/Docs/content/en/adr/025-plugin-options-openapi-and-marten-integrations.md @@ -1,4 +1,4 @@ -[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next]() +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next](./026-plugin-authentication-and-authorization-hooks.md) # [ADR-025] Keep Plugin Options, OpenAPI, And Marten Integrations Explicit @@ -45,4 +45,4 @@ Plugin configuration is isolated and strongly typed. OpenAPI and Marten contribu - [ADR-023](./023-plugin-application-pipeline-hooks.md) - application integration hooks - [Issue #11](https://github.com/AuthKits/AuthKit.Server/issues/11) - options, OpenAPI, and Marten integration requirements -[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next]() \ No newline at end of file +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next](./026-plugin-authentication-and-authorization-hooks.md) \ No newline at end of file diff --git a/Docs/ADR/026-plugin-authentication-and-authorization-hooks.md b/Docs/content/en/adr/026-plugin-authentication-and-authorization-hooks.md similarity index 100% rename from Docs/ADR/026-plugin-authentication-and-authorization-hooks.md rename to Docs/content/en/adr/026-plugin-authentication-and-authorization-hooks.md diff --git a/Docs/content/en/adr/027-devtools-ui-typescript.md b/Docs/content/en/adr/027-devtools-ui-typescript.md new file mode 100644 index 0000000..8b587d4 --- /dev/null +++ b/Docs/content/en/adr/027-devtools-ui-typescript.md @@ -0,0 +1,39 @@ +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./026-plugin-authentication-and-authorization-hooks.md) | [Next](./028-plugin-contract-and-dynamic-loading-architecture.md) + +# [ADR-027] Compile The DevTools UI From Modular TypeScript Into A Single Embedded Resource + +*2026-09* | Status: accepted + +**Tag:** #adr_027 + +**Date:** 2026-09-16 + +**Scope:** Plugins.Solutions.DevTools + +## Context + +The DevTools plugin ships a web UI (Svelte 5 with Tailwind) for exploring gRPC services and invoking methods. Deploying that UI as loose static files would split every release into two artifacts that can drift apart: the server and the interface used to inspect it. + +## Problem + +A modular TypeScript application does not deploy itself as one file. Without a bundling step the UI would require a static-file hosting story (paths, caching, version matching) on top of the plugin assembly that already carries everything else. + +## Decision + +The UI builds with `vite build`, collapses to a single self-contained HTML file through `vite-plugin-singlefile`, and is finalized for embedding by `scripts/finalize-ui.mjs`. Type safety is enforced up front with `svelte-check`. The resulting resource travels inside the plugin assembly: one assembly, one UI, always matching the backend it ships with. + +## Rejected + +- Serving the UI as loose static files next to the plugin assembly. +- Versioning the UI independently from the server it inspects. + +## Consequences + +Deploying AuthKit never involves a separate static-file step, and the UI version cannot drift from the inspected server. The cost is build-time coupling: UI changes require rebuilding the plugin assembly. + +## Related + +- [ADR-020](./020-devtools-plugin.md) - DevTools plugin hosting the UI +- [ADR-009](./009-dynamic-plugin-discovery.md) - plugin discovery loading the assembly + +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./026-plugin-authentication-and-authorization-hooks.md) | [Next](./028-plugin-contract-and-dynamic-loading-architecture.md) diff --git a/Docs/ADR/017-Plugin-Contract-and-Dynamic-Loading-Architecture.md b/Docs/content/en/adr/028-plugin-contract-and-dynamic-loading-architecture.md similarity index 97% rename from Docs/ADR/017-Plugin-Contract-and-Dynamic-Loading-Architecture.md rename to Docs/content/en/adr/028-plugin-contract-and-dynamic-loading-architecture.md index 8c5634f..54c4ec1 100644 --- a/Docs/ADR/017-Plugin-Contract-and-Dynamic-Loading-Architecture.md +++ b/Docs/content/en/adr/028-plugin-contract-and-dynamic-loading-architecture.md @@ -1,4 +1,4 @@ -# ADR-017: Plugin Contract and Dynamic Loading Architecture +# ADR-028: Plugin Contract and Dynamic Loading Architecture ## Context @@ -110,10 +110,10 @@ The `PluginLoader.LoadPlugins()` method signature changed from 2 to 3 required p Plugins ### Previous -ADR-016: Using Marten and Wolverine as the host infrastructure +ADR-027: Compile The DevTools UI From Modular TypeScript Into A Single Embedded Resource ### Next -N/A (latest in collection) +ADR-029: Expose Structured And Cancellable Plugin Health Results ## Consequences diff --git a/Docs/ADR/025-structured-plugin-health-contract.md b/Docs/content/en/adr/029-structured-plugin-health-contract.md similarity index 92% rename from Docs/ADR/025-structured-plugin-health-contract.md rename to Docs/content/en/adr/029-structured-plugin-health-contract.md index 4e225b0..49dcebf 100644 --- a/Docs/ADR/025-structured-plugin-health-contract.md +++ b/Docs/content/en/adr/029-structured-plugin-health-contract.md @@ -1,10 +1,10 @@ -[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next]() +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./028-plugin-contract-and-dynamic-loading-architecture.md) | [Next]() -# [ADR-025] Expose Structured And Cancellable Plugin Health Results +# [ADR-029] Expose Structured And Cancellable Plugin Health Results *2026-09* | Status: accepted -**Tag:** #adr_025 +**Tag:** #adr_029 **Date:** 2026-09-13 @@ -71,4 +71,4 @@ contract validator invokes the new method and rejects an empty result collection - [Issue #14](https://github.com/AuthKits/AuthKit.Server/issues/14) - structured plugin health result - [Issue #15](https://github.com/AuthKits/AuthKit.Server/issues/15) - multiple results and cancellation -[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./024-plugin-lifecycle-and-hosted-services.md) | [Next]() +[ADR Home](../../README.md) | [Category Index](./README.md) | [Previous](./028-plugin-contract-and-dynamic-loading-architecture.md) | [Next]() diff --git a/Docs/content/en/adr/README.md b/Docs/content/en/adr/README.md new file mode 100644 index 0000000..60489df --- /dev/null +++ b/Docs/content/en/adr/README.md @@ -0,0 +1,109 @@ +# Architecture Decision Records + +This directory stores AuthKit.Server architectural decisions as ADRs. It is not changelog and not rewritten commit history. It is curated set of technical decisions that explains why the system has its current shape and which constraints that imposes on future work. + +ADRs are grouped by architecture area. Numbering is global, so decision ID does not depend on the file it lives in. Moving a file to another area does not change its number, and the number should be treated as stable decision identifier. + +## How To Read This Collection + +Start with the area that matches what you are changing: + +- if the change affects key management, token key bindings, or core domain contracts, read the `AuthKit.Core` decisions below +- if it affects the REST or gRPC surface, CLI, configuration, or how the server is composed and hosted, see the Host decisions +- if it affects the plugin system, solutions, or plugin abstractions, see the Plugins decisions + +Each ADR contains: + +- `Context`: + the layer and architectural location of the decision +- `Problem`: + the specific technical tension the decision resolves +- `Decision`: + the chosen direction and responsibility boundary +- `Rejected`: + realistic alternatives that were intentionally not selected +- `Consequences`: + maintenance impact, constraints, side effects, and practical implications for future code + +## How To Use ADRs During Changes + +ADRs do not replace reading the code, but they reduce the cost of understanding decisions that have already been made. When you change a given area: + +1. find the matching area +2. read the 2-4 closest ADRs, not just one +3. check whether the new change extends the current model or actually breaks it +4. if decision is no longer true, add a new ADR instead of silently drifting away from the current direction + +This collection is meant to preserve consistency across Core, Host, and Plugins. In AuthKit.Server, much of the cost of change comes from contracts between layers rather than from any single class. + +## Category Map + +The table below shows the architecture areas and their current scope. + +| Area | Scope | +| --- | --- | +| Core | Shared domain model: signing key management, token key bindings, error contracts, and Core interfaces. | +| Host | Application composition and external surface: REST, gRPC, CLI, configuration, and key-material hosting. | +| Plugins | Plugin system: solutions, plugin abstractions, and extension boundaries. | + +## Current ADRs + +| ID | Title | Area | Status | Date | +|----|-------|------|--------|------| +| [ADR-001](./001-centralize-signing-key-management.md) | Centralize Signing Key Management Through A Core Key Store Abstraction | Core | accepted | 2026-08-26 | +| [ADR-002](./002-encrypt-keystore-at-rest.md) | Encrypt Persisted Keystore Material At Rest Through A Pluggable Encryptor | Core | accepted | 2026-08-26 | +| [ADR-003](./003-signing-key-lifecycle-immutable-transitions.md) | Model Signing Key Lifecycle As Immutable State Transitions | Core | accepted | 2026-08-26 | +| [ADR-004](./004-token-key-bindings-domain.md) | Treat Developer Token To Signing Key Bindings As A Core Domain | Core | accepted | 2026-08-26 | +| [ADR-005](./005-public-keys-via-jwks.md) | Publish Public Keys Through JWKS Exposing Only Non-Revoked Keys | Core | accepted | 2026-08-26 | +| [ADR-006](./006-kid-as-generated-guid.md) | Derive The JWT Key Identifier As A Generated GUID | Core | accepted | 2026-08-26 | +| [ADR-007](./007-default-signing-algorithm-rsa-4096.md) | Default Signing Algorithm Is RSA-4096 With RS256 | Core | accepted | 2026-08-26 | +| [ADR-008](./008-standardized-error-response.md) | Standardize API Errors Through A Core Error Response Contract | Core | accepted | 2026-08-26 | +| [ADR-009](./009-dynamic-plugin-discovery.md) | Discover And Load Plugins Dynamically Through The IAuthKitPlugin Contract | Plugins | accepted | 2026-08-26 | +| [ADR-010](./010-plugin-loading-from-directory.md) | Load Plugins From A Configurable Directory At Startup | Host | accepted | 2026-08-26 | +| [ADR-011](./011-keystore-persisted-as-singleton-marten-document.md) | Persist The Encrypted Keystore As A Singleton Marten Document | Host | accepted | 2026-08-26 | +| [ADR-012](./012-token-key-bindings-persisted-in-marten.md) | Persist Token Key Bindings In Marten | Host | accepted | 2026-08-26 | +| [ADR-013](./013-dual-rest-and-grpc-transport.md) | Expose Both REST And gRPC Transport Surfaces | Host | accepted | 2026-08-26 | +| [ADR-014](./014-error-responses-via-middleware.md) | Render HTTP Errors As RFC 7807 Problem Details Via Middleware | Host | accepted | 2026-08-26 | +| [ADR-015](./015-keycloak-external-jwt-authority.md) | Use Keycloak As The External JWT Authority | Host | accepted | 2026-08-26 | +| [ADR-016](./016-marten-and-wolverine-infrastructure.md) | Use Marten And Wolverine As Host Infrastructure | Host | accepted | 2026-08-26 | +| [ADR-017](./017-api-key-credential-extraction-strategies.md) | Define API Key Credential Extraction Strategies | Host | accepted | 2026-09-11 | +| [ADR-018](./018-security-scheme-contract-explicit-handling.md) | Handle Security Scheme Contract Values Explicitly | Plugins | accepted | 2026-09-11 | +| [ADR-019](./019-plugin-metadata-attribute.md) | Declare Plugin Identity Through The PluginMetadata Attribute | Plugins | accepted | 2026-09-11 | +| [ADR-020](./020-devtools-plugin.md) | Host Developer Tools Through A Dedicated DevTools Plugin | Plugins | accepted | 2026-09-11 | +| [ADR-021](./021-swagger-serving-via-reflection.md) | Serve Swagger Through Reflection-Based SwaggerHost In DevTools | Plugins | accepted | 2026-09-11 | +| [ADR-022](./022-plugin-configuration-context-and-builder.md) | Extend Plugin Configuration With The Host Builder And Scoped Context | Plugins | accepted | 2026-09-12 | +| [ADR-023](./023-plugin-application-pipeline-hooks.md) | Integrate Plugin Endpoints And Middleware Through Explicit Host Pipeline Hooks | Plugins | accepted | 2026-09-12 | +| [ADR-024](./024-plugin-lifecycle-and-hosted-services.md) | Bridge Plugin Lifecycle Hooks To The Standard .NET Host Lifecycle | Plugins | accepted | 2026-09-12 | +| [ADR-025](./025-plugin-options-openapi-and-marten-integrations.md) | Keep Plugin Options, OpenAPI, And Marten Integrations Explicit | Plugins | accepted | 2026-09-12 | +| [ADR-026](./026-plugin-authentication-and-authorization-hooks.md) | Configure Plugin Authentication And Authorization Through Host Security Infrastructure | Plugins | accepted | 2026-09-12 | +| [ADR-027](./027-devtools-ui-typescript.md) | Compile The DevTools UI From Modular TypeScript Into A Single Embedded Resource | Plugins | accepted | 2026-09-16 | +| [ADR-028](./028-plugin-contract-and-dynamic-loading-architecture.md) | Define The Plugin Contract And Dynamic Loading Architecture | Plugins | accepted | 2026-09-11 | +| [ADR-029](./029-structured-plugin-health-contract.md) | Expose Structured And Cancellable Plugin Health Results | Plugins | accepted | 2026-09-13 | + +## Relationships Between Areas + +The most common architectural flow in AuthKit.Server looks like this: + +`Core -> Host -> Plugins` + +This is not strict dependency diagram of the project, but it is useful map for reading decisions. In practice: + +- `Core` defines what the system considers to be domain data and the cryptographic contracts (keys, bindings, errors) +- `Host` defines how that domain is exposed and composed into a running server (API surfaces, CLI, configuration) +- `Plugins` extend behavior on top of the stable Core and Host contracts + +## When To Add A New ADR + +A new ADR is worth adding when change: + +- shifts responsibility boundaries between layers +- introduces a new data contract or new durable artifact +- changes the execution model of key management, hosting, or plugin loading +- adds a new provider or plugin specific behavior that no longer fits the current model +- replaces an earlier decision with a different conscious trade off + +It is usually not worth adding an ADR for: + +- an ordinary refactor without an architectural change in direction +- a cosmetic local API change limited to one file or class +- a documentation or test only adjustment that does not change system contracts From d0a02056d8b8f64ab191877518b1998590b628a0 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:12:59 +0200 Subject: [PATCH 02/17] docs: document architecture decisions in Polish --- .../001-centralize-signing-key-management.md | 82 ++++++++ .../pl/adr/002-encrypt-keystore-at-rest.md | 55 +++++ ...ing-key-lifecycle-immutable-transitions.md | 54 +++++ .../pl/adr/004-token-key-bindings-domain.md | 67 ++++++ .../pl/adr/005-public-keys-via-jwks.md | 54 +++++ .../pl/adr/006-kid-as-generated-guid.md | 47 +++++ .../007-default-signing-algorithm-rsa-4096.md | 46 +++++ .../pl/adr/008-standardized-error-response.md | 59 ++++++ .../pl/adr/009-dynamic-plugin-discovery.md | 65 ++++++ .../adr/010-plugin-loading-from-directory.md | 61 ++++++ ...-persisted-as-singleton-marten-document.md | 54 +++++ ...-token-key-bindings-persisted-in-marten.md | 60 ++++++ .../adr/013-dual-rest-and-grpc-transport.md | 47 +++++ .../adr/014-error-responses-via-middleware.md | 50 +++++ .../015-keycloak-external-jwt-authority.md | 46 +++++ ...016-marten-and-wolverine-infrastructure.md | 51 +++++ ...pi-key-credential-extraction-strategies.md | 59 ++++++ ...urity-scheme-contract-explicit-handling.md | 59 ++++++ .../pl/adr/019-plugin-metadata-attribute.md | 53 +++++ Docs/content/pl/adr/020-devtools-plugin.md | 126 ++++++++++++ .../adr/021-swagger-serving-via-reflection.md | 55 +++++ ...lugin-configuration-context-and-builder.md | 62 ++++++ .../023-plugin-application-pipeline-hooks.md | 60 ++++++ ...24-plugin-lifecycle-and-hosted-services.md | 62 ++++++ ...options-openapi-and-marten-integrations.md | 48 +++++ ...-authentication-and-authorization-hooks.md | 49 +++++ .../pl/adr/027-devtools-ui-typescript.md | 39 ++++ ...ntract-and-dynamic-loading-architecture.md | 190 ++++++++++++++++++ .../029-structured-plugin-health-contract.md | 74 +++++++ Docs/content/pl/adr/README.md | 109 ++++++++++ 30 files changed, 1943 insertions(+) create mode 100644 Docs/content/pl/adr/001-centralize-signing-key-management.md create mode 100644 Docs/content/pl/adr/002-encrypt-keystore-at-rest.md create mode 100644 Docs/content/pl/adr/003-signing-key-lifecycle-immutable-transitions.md create mode 100644 Docs/content/pl/adr/004-token-key-bindings-domain.md create mode 100644 Docs/content/pl/adr/005-public-keys-via-jwks.md create mode 100644 Docs/content/pl/adr/006-kid-as-generated-guid.md create mode 100644 Docs/content/pl/adr/007-default-signing-algorithm-rsa-4096.md create mode 100644 Docs/content/pl/adr/008-standardized-error-response.md create mode 100644 Docs/content/pl/adr/009-dynamic-plugin-discovery.md create mode 100644 Docs/content/pl/adr/010-plugin-loading-from-directory.md create mode 100644 Docs/content/pl/adr/011-keystore-persisted-as-singleton-marten-document.md create mode 100644 Docs/content/pl/adr/012-token-key-bindings-persisted-in-marten.md create mode 100644 Docs/content/pl/adr/013-dual-rest-and-grpc-transport.md create mode 100644 Docs/content/pl/adr/014-error-responses-via-middleware.md create mode 100644 Docs/content/pl/adr/015-keycloak-external-jwt-authority.md create mode 100644 Docs/content/pl/adr/016-marten-and-wolverine-infrastructure.md create mode 100644 Docs/content/pl/adr/017-api-key-credential-extraction-strategies.md create mode 100644 Docs/content/pl/adr/018-security-scheme-contract-explicit-handling.md create mode 100644 Docs/content/pl/adr/019-plugin-metadata-attribute.md create mode 100644 Docs/content/pl/adr/020-devtools-plugin.md create mode 100644 Docs/content/pl/adr/021-swagger-serving-via-reflection.md create mode 100644 Docs/content/pl/adr/022-plugin-configuration-context-and-builder.md create mode 100644 Docs/content/pl/adr/023-plugin-application-pipeline-hooks.md create mode 100644 Docs/content/pl/adr/024-plugin-lifecycle-and-hosted-services.md create mode 100644 Docs/content/pl/adr/025-plugin-options-openapi-and-marten-integrations.md create mode 100644 Docs/content/pl/adr/026-plugin-authentication-and-authorization-hooks.md create mode 100644 Docs/content/pl/adr/027-devtools-ui-typescript.md create mode 100644 Docs/content/pl/adr/028-plugin-contract-and-dynamic-loading-architecture.md create mode 100644 Docs/content/pl/adr/029-structured-plugin-health-contract.md create mode 100644 Docs/content/pl/adr/README.md diff --git a/Docs/content/pl/adr/001-centralize-signing-key-management.md b/Docs/content/pl/adr/001-centralize-signing-key-management.md new file mode 100644 index 0000000..dd84e60 --- /dev/null +++ b/Docs/content/pl/adr/001-centralize-signing-key-management.md @@ -0,0 +1,82 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni]() | [Następny](/pl/adr/002-encrypt-keystore-at-rest/) + +# [ADR-001] Scentralizuj zarządzanie kluczami podpisującymi poprzez abstrakcję głównego magazynu kluczy w Core + +*2026-08* | Status: accepted + +**Tag:** #adr_001 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement + +## Kontekst + +Rdzeń (core) AuthKit jest właścicielem materiału kryptograficznego używanego do wystawiania i weryfikowania JWT. Udostępnia mały zestaw prymitywów `IKeyGenerator`, `IKeyEncryptor`, `IJwtKeyStore` i `IKeyStoreRepository` które łącznie obejmują tworzenie kluczy, szyfrowanie w spoczynku oraz utrwalanie. Warstwa hosta (REST, gRPC, wtyczki) musi mieć możliwość wybijania, rotowania i publikowania kluczy podpisujących bez przejmowania wiedzy o tym, jak te klucze są generowane, szyfrowane lub przechowywane. + +## Problem + +Host nie powinien zależeć od konkretnych formatów przechowywania kluczy, algorytmów szyfrowania ani parametrów generowania. Bez centralnej abstrakcji zarządzania kluczami należącej do rdzenia wiedza ta wycieka do hosta i do poszczególnych punktów końcowych: każdy konsument na nowo wymyśla sposób wytwarzania kluczy, ich ochrony na dysku oraz rozwiązywania aktywnego klucza podpisującego. Zmiana nazwy klucza, zmiana schematu szyfrowania lub podmiana backendu przechowywania staje się wówczas zmianą przekrojową bez jednego kontraktu, na którym można się oprzeć. + +## Decyzja + +Zarządzanie kluczami podpisującymi jest scentralizowane za abstrakcją rdzenia, która tworzy kontrakt pomiędzy generowaniem kluczy, szyfrowaniem i utrwalaniem z jednej strony a hostem z drugiej. Klucz podpisujący staje się stabilną encją rdzenia (`SigningKey`) rozwiązywaną poprzez magazyn kluczy, a nie surowym plikiem ani rekordem repozytorium znanym tylko jednemu punktowi końcowemu. + +### IKeyGenerator + +**Obowiązki:** + +- Wytwarza nowe asymetryczne pary kluczy do podpisywania (`GenerateAsync`). +- Ujawnia używany algorytm i parametry, aby reszta rdzenia mogła wnioskować o sile klucza. +- Pozostaje niezależny od zagadnień przechowywania i szyfrowania. + +### IKeyEncryptor + +**Obowiązki:** + +- Szyfruje surowy materiał kluczy w celu ochrony w spoczynku (`EncryptAsync` / `DecryptAsync`). +- Izoluje algorytm szyfrowania (np. AES) od magazynu i generatora. +- Nigdy nie ujawnia materiału w postaci jawnej poza granicę rdzenia. + +### IJwtKeyStore + +**Obowiązki:** + +- Rozwiązuje aktywny klucz podpisujący oraz zbiór opublikowanych kluczy publicznych (`GetActiveKeyAsync`, `GetPublicJwksAsync`). +- Koordynuje generator i szyfrator tak, aby utrwalane klucze były zawsze zaszyfrowane. +- Prezentuje hostowi klucze jako encje `SigningKey` oraz publiczne JWK, ukrywając szczegóły przechowywania. + +### IKeyStoreRepository + +**Obowiązki:** + +- Utrwala i wczytuje zaszyfrowany rekord magazynu kluczy (`KeystoreOnDisk`, `KeyEntry`, `KeyMetadata`). +- Pozostaje czystą granicą utrwalania bez logiki kryptograficznej ani domenowej. + +### Uzasadnienie projektowe + +- Jeden kontrakt rdzenia sprawia, że decyzje kryptograficzne są testowalne, audytowalne i wymienialne bez dotykania hosta. +- Rozdzielenie generowania, szyfrowania i przechowywania pozwala każdemu zagadnieniu ewoluować niezależnie (aktualizacja algorytmu, zmiana backendu przechowywania, polityka rotacji) za stabilnymi interfejsami. +- Ujawnianie kluczy jako encji domenowych i publicznych JWK zapobiega sprzęganiu hosta z formatami dyskowymi i zmniejsza ryzyko błędów obsługi kluczy. + +## Odrzucone + +- Pozwolenie hostowi na bezpośrednie generowanie, szyfrowanie i utrwalanie kluczy za pomocą doraźnych wywołań. +- Sprzęganie wiedzy o kluczu podpisującym i szyfrowaniu z konkretnym kodem punktów końcowych. +- Jedna monolityczna usługa kluczy łącząca generowanie, szyfrowanie i przechowywanie w jednej klasie. +- Przechowywanie kluczy w postaci jawnej lub poleganie na sekretach zarządzanych przez hosta zamiast na szyfratorze rdzenia. + +## Konsekwencje + +Rdzeń staje się jedynym, przewidywalnym właścicielem cyklu życia kluczy podpisujących i łatwiej jest kontrolować kompletność kluczy, rotację oraz spójność algorytmów w całym hoście. Kosztem jest utrzymywanie abstrakcji rdzenia jako kontraktu i aktualizowanie jej przy każdym wprowadzeniu nowej capability zarządzania kluczami. + +## Powiązane + +- [ADR-002](/pl/adr/002-encrypt-keystore-at-rest/) - szyfrowanie bajtów magazynu kluczy w spoczynku +- [ADR-003](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) - przejścia cyklu życia klucza podpisującego +- [ADR-005](/pl/adr/005-public-keys-via-jwks/) - odkrywanie kluczy publicznych poprzez JWKS +- [ADR-006](/pl/adr/006-kid-as-generated-guid/) - strategia identyfikatora klucza +- [ADR-007](/pl/adr/007-default-signing-algorithm-rsa-4096/) - domyślny algorytm podpisywania +- [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) - utrwalanie magazynu kluczy + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni]() | [Następny](/pl/adr/002-encrypt-keystore-at-rest/) diff --git a/Docs/content/pl/adr/002-encrypt-keystore-at-rest.md b/Docs/content/pl/adr/002-encrypt-keystore-at-rest.md new file mode 100644 index 0000000..6d188d4 --- /dev/null +++ b/Docs/content/pl/adr/002-encrypt-keystore-at-rest.md @@ -0,0 +1,55 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/001-centralize-signing-key-management/) | [Następny](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) + +# [ADR-002] Szyfruj utrwalony materiał magazynu kluczy w spoczynku poprzez wymienialny szyfrator + +*2026-08* | Status: accepted + +**Tag:** #adr_002 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement + +## Kontekst + +Magazyn kluczy utrwala wrażliwy materiał prywatnych kluczy RSA, aby klucze podpisujące przetrwały restarty. Granica repozytorium (`IKeyStoreRepository`) jest celowo czystym ujściem utrwalania przechowuje i zwraca nieprzezroczyste bajty bez rozumienia ich zawartości. + +## Problem + +Materiał kluczy prywatnych nie może być nigdy zapisywany na dysku w postaci jawnej. Jednocześnie warstwa utrwalania musi pozostać nieświadoma kryptografii, aby można ją było podmieniać (plik, blob, baza danych) bez dotykania logiki bezpieczeństwa. System potrzebuje też jednego, wymienialnego miejsca do zmiany algorytmu szyfrowania, gdyby zmienił się model zagrożeń. + +## Decyzja + +Wszystkie bajty magazynu kluczy są szyfrowane przed utrwaleniem i odszyfrowywane po wczytaniu poprzez granicę `IKeyEncryptor`. Domyślna implementacja (`AesKeyEncryptor`) używa AES-256-CBC z 256-bitowym kluczem głównym podawanym podczas konstrukcji, generuje kryptograficznie losowy IV przy każdym wywołaniu szyfrowania oraz prefiksuje IV do szyfrogramu, aby można go było odzyskać podczas odszyfrowywania. + +### IKeyEncryptor + +**Obowiązki:** + +- Szyfruje tekst jawny UTF-8 do nieprzezroczystego bloba bajtów (`Encrypt`). +- Odwraca operację i zwraca tekst jawny (`Decrypt`). +- Pozostaje bezstanowy i niezależny od repozytorium utrwalania. + +### Uzasadnienie projektowe + +- Umieszczenie szyfrowania w dedykowanej, wstrzykiwalnej granicy pozwala zmienić algorytm (np. na AES-GCM) bez modyfikowania magazynu ani repozytorium. +- Losowy IV na wywołanie zapobiega ponownemu użyciu pary klucz/IV i sprawia, że format dyskowy jest niedeterministyczny. +- Repozytorium pozostaje prostym magazynem bajtów, dzięki czemu backendy przechowywania są wymienne. + +## Odrzucone + +- Utrwalanie kluczy w postaci jawnej lub poleganie wyłącznie na uprawnieniach systemu plików. +- Pozwolenie `IKeyStoreRepository` na wykonywanie szyfrowania lub odszyfrowywania. +- Stały, wbudowany klucz skompilowany w złożeniu (assembly). +- Ponowne używanie jednego statycznego IV we wszystkich szyfrowaniach. + +## Konsekwencje + +Materiał kluczy jest poufny w spoczynku, a algorytm szyfrowania jest odizolowany za kontraktem. Dokumentacja wprost zaznacza, że AES-CBC zapewnia poufność bez uwierzytelnionej integralności, więc zaszyfrowany blob musi być chroniony przed manipulacją innym mechanizmem albo zmigrowany do trybu uwierzytelnionego. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - abstrakcja magazynu kluczy będąca właścicielem kontraktu +- [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) - miejsce utrwalania zaszyfrowanych bajtów + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/001-centralize-signing-key-management/) | [Następny](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) diff --git a/Docs/content/pl/adr/003-signing-key-lifecycle-immutable-transitions.md b/Docs/content/pl/adr/003-signing-key-lifecycle-immutable-transitions.md new file mode 100644 index 0000000..2c37aee --- /dev/null +++ b/Docs/content/pl/adr/003-signing-key-lifecycle-immutable-transitions.md @@ -0,0 +1,54 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/002-encrypt-keystore-at-rest/) | [Następny](/pl/adr/004-token-key-bindings-domain/) + +# [ADR-003] Modeluj cykl życia klucza podpisującego jako niezmienne przejścia stanu + +*2026-08* | Status: accepted + +**Tag:** #adr_003 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement.Entity + +## Kontekst + +Klucz podpisujący przechodzi przez cykl życia: jest generowany, staje się ważny do podpisywania, może zostać zrotowany, wygasa i może zostać unieważniony. Wiele części systemu musi zadawać jedno, wiarygodne pytanie „czy ten klucz może teraz podpisywać?" bez ponownego implementowania reguł cyklu życia. + +## Problem + +Jeśli stan cyklu życia znajduje się wyłącznie w magazynie albo jest mutowany w miejscu przez usługi, reguły aktywacji, wygasania i unieważniania ulegają duplikacji i rozjeżdżają się. Mutowalne encje utrudniają też rozumowanie o współbieżnych operacjach na kluczach oraz o audycie. + +## Decyzja + +Klucz podpisujący jest modelowany jako niezmienny rekord `SigningKey`. Zmiany cyklu życia `Activate`, `Revoke`, `Expire` zwracają nową instancję poprzez wyrażenia `with` zamiast mutować stan, a pojedynczy predykat `IsValidForSigning(now)` ocenia aktywację, unieważnienie i wygaśnięcie względem podanego znacznika czasu. + +### SigningKey + +**Obowiązki:** + +- Przenosi identyfikator klucza, klucz publiczny (PEM), zaszyfrowany materiał prywatny, algorytm oraz znaczniki czasu cyklu życia. +- Ujawnia `Activate`, `Revoke` i `Expire` jako czyste przejścia wytwarzające nowy rekord. +- Udostępnia `IsValidForSigning(DateTime now)` jako autorytatywne sprawdzenie ważności. + +### Uzasadnienie projektowe + +- Niezmienność sprawia, że przejścia są łatwe do testowania i wolne od ukrytych efektów ubocznych. +- Jeden predykat ważności zapobiega kopiowaniu logiki cyklu życia pomiędzy magazyn, host i powiązania. +- Ocena oparta na znaczniku czasu zachowuje determinizm reguły i niezależność od założeń zegara ściennego wewnątrz encji. + +## Odrzucone + +- Mutowalna encja z publicznymi setterami zmienianymi bezpośrednio przez usługi. +- Przechowywanie stanu cyklu życia wyłącznie w bazie danych i ponowne wyliczanie reguł w każdym konsumencie. +- Osadzanie logiki aktywacji/wygasania/unieważniania wewnątrz `JwtKeyStore` zamiast w encji. + +## Konsekwencje + +Zachowanie cyklu życia jest scentralizowane i spójne, a przejścia są audytowalne jako kopie wartości. Kosztem jest bogatszy kształt rekordu oraz dyscyplina zawsze używania zwróconej instancji zamiast oryginału. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - magazyn kluczy konsumujący cykl życia +- [ADR-005](/pl/adr/005-public-keys-via-jwks/) - JWKS wyklucza unieważnione klucze na podstawie tego stanu + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/002-encrypt-keystore-at-rest/) | [Następny](/pl/adr/004-token-key-bindings-domain/) diff --git a/Docs/content/pl/adr/004-token-key-bindings-domain.md b/Docs/content/pl/adr/004-token-key-bindings-domain.md new file mode 100644 index 0000000..895fc10 --- /dev/null +++ b/Docs/content/pl/adr/004-token-key-bindings-domain.md @@ -0,0 +1,67 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) | [Następny](/pl/adr/005-public-keys-via-jwks/) + +# [ADR-004] Traktuj powiązania tokenów deweloperskich z kluczami podpisującymi jako domenę Core + +*2026-08* | Status: accepted + +**Tag:** #adr_004 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.TokenKeyBindings + +## Kontekst + +Tokeny deweloperskie muszą być powiązane z konkretnym kluczem podpisującym RSA (i jego kluczem publicznym) użytym do podpisania ich JWT, aby weryfikację i rotację można było śledzić na token. To powiązanie jest pojęciem domenowym, a nie szczegółem implementacyjnym pojedynczego punktu końcowego. + +## Problem + +Bez pierwszoplanowego pojęcia powiązania mapowanie pomiędzy tokenami a kluczami podpisującymi jest rozproszone pomiędzy hosty i materiał kluczy, co utrudnia śledzenie rotacji, aktualizacji kluczy publicznych i unieważnień oraz prowadzi do niespójności pomiędzy powierzchniami API. + +## Decyzja + +Powiązania tokenów z kluczami są domeną rdzenia: rekord `TokenKeyBinding` przechwytuje `TokenId`, `SigningKeyId`, klucz publiczny, znacznik czasu `BoundAt` oraz flagę `Revoked`. `IKeyBindingService` stosuje zachowania domenowe (`CreateBindingAsync`, `RebindAsync`, `UpdatePublicKeyAsync`, `RevokeAsync`, `ListBindingsAsync`, `GetBindingAsync`), a `IKeyBindingRepository` jest czystą granicą utrwalania. + +### TokenKeyBinding + +**Obowiązki:** + +- Reprezentuje niezmienne przez kopię powiązanie pomiędzy tokenem deweloperskim a kluczem podpisującym. +- Ujawnia `Rebind`, `UpdatePublicKey` i `Revoke` jako przejścia zwracające nowy rekord z odświeżonym `BoundAt`. + +### IKeyBindingService + +**Obowiązki:** + +- Orkiestruje operacje powiązań poprzez repozytorium. +- Wywołuje przejścia encji zamiast bezpośrednio mutować stan powiązania. + +### IKeyBindingRepository + +**Obowiązki:** + +- Utrwala, wczytuje, aktualizuje i listuje powiązania. +- Pozostaje wolny od zachowań kryptograficznych i domenowych. + +### Uzasadnienie projektowe + +- Dedykowana domena sprawia, że pochodzenie klucza na token jest jawne i wspiera rotację bez łamania weryfikacji. +- Rozdzielenie serwisu (zachowanie) od repozytorium (utrwalanie) odzwierciedla projekt zarządzania kluczami i pozostaje testowalne. + +## Odrzucone + +- Kodowanie mapowania token -> klucz niejawnie wewnątrz magazynu kluczy. +- Pozwolenie hostom na zarządzanie powiązaniami poprzez doraźny dostęp do bazy danych. +- Bezpośrednie mutowanie pól powiązania z serwisu zamiast używania przejść encji. + +## Konsekwencje + +Pochodzenie kluczy tokenów, rotacja i unieważnianie są spójne i obserwowalne. Kosztem jest utrzymywanie drugiej domeny rdzenia obok zarządzania kluczami oraz dbanie o czystość granicy repozytorium. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - klucze podpisujące, do których odwołują się powiązania +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - wtyczki konsumują powiązania poprzez tę domenę +- [ADR-012](/pl/adr/012-token-key-bindings-persisted-in-marten/) - utrwalanie powiązań + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) | [Następny](/pl/adr/005-public-keys-via-jwks/) diff --git a/Docs/content/pl/adr/005-public-keys-via-jwks.md b/Docs/content/pl/adr/005-public-keys-via-jwks.md new file mode 100644 index 0000000..5af85d0 --- /dev/null +++ b/Docs/content/pl/adr/005-public-keys-via-jwks.md @@ -0,0 +1,54 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/004-token-key-bindings-domain/) | [Następny](/pl/adr/006-kid-as-generated-guid/) + +# [ADR-005] Publikuj klucze publiczne poprzez JWKS, ujawniając wyłącznie klucze nieunieważnione + +*2026-08* | Status: accepted + +**Tag:** #adr_005 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement + +## Kontekst + +Strony ufające weryfikują podpisy JWT, pobierając klucze publiczne wystawcy. Magazyn kluczy przechowuje już moduł RSA i wykładnik każdego klucza wraz z metadanymi cyklu życia oraz utrzymuje widok w pamięci wszystkich wczytanych kluczy. + +## Problem + +Konsumenci potrzebują standardowego, przyjaznego dla cachowania sposobu odkrywania ważnych kluczy publicznych. Jeśli publikowane są klucze unieważnione lub wygasłe albo odpowiedź jest przeliczana przy każdym żądaniu bez unieważniania, weryfikatory mogą akceptować złe podpisy lub punkt końcowy marnuje CPU na odtwarzanie zestawu kluczy. + +## Decyzja + +Magazyn kluczy udostępnia klucze publiczne poprzez `GetPublicJwks()` jako instancje `PublicJwkDto` w kształcie zgodnym z JWKS (`kty=RSA`, `use=sig`, `kid`, `alg`, `n`, `e`). Dołączane są wyłącznie klucze, których metadane `Revoked` mają wartość false, a wynik jest cachowany i przebudowywany tylko przy zmianie zestawu kluczy (rotacja lub unieważnienie). + +### PublicJwkDto + +**Obowiązki:** + +- Przenosi pola JWKS potrzebne zewnętrznym weryfikatorom. +- Pozostaje projekcją tylko do odczytu wpisu klucza w pamięci. + +### Uzasadnienie projektowe + +- JWKS jest branżowym standardowym formatem odkrywania, więc gotowe weryfikatory integrują się bez własnego kodu. +- Wykluczanie unieważnionych kluczy zapobiega akceptowaniu podpisów z wycofanych kluczy. +- Cachowanie z jawnym unieważnianiem równoważy wydajność ze świeżością po rotacji. + +## Odrzucone + +- Publikowanie unieważnionych lub wygasłych kluczy w odpowiedzi JWKS. +- Regenerowanie zestawu kluczy przy każdym żądaniu bez cache. +- Wymyślanie własnego formatu odkrywania kluczy publicznych zamiast JWKS. + +## Konsekwencje + +Zewnętrzni weryfikatorzy otrzymują poprawny, standardowy zestaw kluczy, a punkt końcowy pozostaje wydajny. Kosztem jest jawne unieważnianie cache przy każdej zmianie cyklu życia oraz utrzymywanie projekcji w synchronizacji z metadanymi kluczy. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - magazyn kluczy udostępniający JWKS +- [ADR-003](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) - cykl życia steruje filtrowaniem unieważnień +- [ADR-006](/pl/adr/006-kid-as-generated-guid/) - wartości `kid` publikowane w zestawie kluczy + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/004-token-key-bindings-domain/) | [Następny](/pl/adr/006-kid-as-generated-guid/) diff --git a/Docs/content/pl/adr/006-kid-as-generated-guid.md b/Docs/content/pl/adr/006-kid-as-generated-guid.md new file mode 100644 index 0000000..5556890 --- /dev/null +++ b/Docs/content/pl/adr/006-kid-as-generated-guid.md @@ -0,0 +1,47 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/005-public-keys-via-jwks/) | [Następny](/pl/adr/007-default-signing-algorithm-rsa-4096/) + +# [ADR-006] Wyznaczaj identyfikator klucza JWT jako generowany GUID + +*2026-08* | Status: accepted + +**Tag:** #adr_006 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement + +## Kontekst + +Każdy klucz podpisujący potrzebuje stabilnego identyfikatora, który występuje jako nagłówek JWT `kid`, indeksuje słownik kluczy w pamięci oraz łączy rekordy utrwalania i wpisy publicznych JWK. Generator tworzy klucze bez przypisanego zewnętrznego identyfikatora. + +## Problem + +Jeśli identyfikator jest znaczący (np. koduje klucz publiczny lub sekwencję), może się zepsuć przy rotacji klucza lub regeneracji jego materiału oraz ujawniać wewnętrzną strukturę. System potrzebuje jednego identyfikatora, który jest stabilny przez całe życie klucza we wszystkich reprezentacjach. + +## Decyzja + +Generator kluczy przypisuje każdemu nowemu kluczowi `kid` wytworzony przez `Guid.NewGuid().ToString("N")`. Ta sama wartość jest używana jako JWT `kid`, klucz `ConcurrentDictionary` w `JwtKeyStore`, `KeyMetadata.Kid` oraz pole JWKS `kid`, więc wszystkie reprezentacje są zakotwiczone w jednym identyfikatorze. + +### Uzasadnienie projektowe + +- Losowy GUID jest unikalny, nieprzezroczysty i stabilny przez cały czas życia klucza niezależnie od rotacji czy ponownego eksportu. +- Ponowne używanie jednego identyfikatora wszędzie usuwa logikę translacji pomiędzy utrwalaniem, pamięcią, JWT i JWKS. +- Żadna wewnętrzna struktura nie jest ujawniana stronom ufającym. + +## Odrzucone + +- Sekwencyjne lub znaczące identyfikatory ujawniające kolejność lub szczegóły wewnętrzne. +- Wyznaczanie `kid` z hasha klucza publicznego, co komplikuje rotację i ponowne eksporty. +- Pozwolenie wywołującym lub hostowi na zewnętrzne przypisywanie `kid`. + +## Konsekwencje + +Tożsamość klucza jest spójna i wolna od kolizji w całym systemie. Kosztem jest to, że `kid` nie niesie znaczenia czytelnego dla człowieka, więc debugowanie opiera się na metadanych, a nie na samym identyfikatorze. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - indeksowanie magazynu kluczy po `kid` +- [ADR-005](/pl/adr/005-public-keys-via-jwks/) - `kid` w publikowanym zestawie kluczy +- [ADR-007](/pl/adr/007-default-signing-algorithm-rsa-4096/) - algorytm sparowany z identyfikatorem + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/005-public-keys-via-jwks/) | [Następny](/pl/adr/007-default-signing-algorithm-rsa-4096/) diff --git a/Docs/content/pl/adr/007-default-signing-algorithm-rsa-4096.md b/Docs/content/pl/adr/007-default-signing-algorithm-rsa-4096.md new file mode 100644 index 0000000..66703a4 --- /dev/null +++ b/Docs/content/pl/adr/007-default-signing-algorithm-rsa-4096.md @@ -0,0 +1,46 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/006-kid-as-generated-guid/) | [Następny](/pl/adr/008-standardized-error-response/) + +# [ADR-007] Domyślnym algorytmem podpisywania jest RSA-4096 z RS256 + +*2026-08* | Status: accepted + +**Tag:** #adr_007 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core.KeyManagement + +## Kontekst + +Generator kluczy i magazyn kluczy muszą zgadzać się co do algorytmu i siły klucza używanych do wytwarzania i weryfikowania JWT. `IKeyGenerator.Generate` przyjmuje konfigurowalne `rsaBits`, a `JwtKeyStore` buduje `SigningCredentials` ze stałą algorytmu. + +## Problem + +Bez zadeklarowanego domyślnego wywołujący mogą wybierać słabe rozmiary kluczy lub niedopasowane algorytmy, a magazyn i generator mogą się rozjechać, wytwarzając klucze, których magazyn nie potrafi użyć ani spójnie zweryfikować. + +## Decyzja + +Domyślny klucz podpisujący to RSA z 4096-bitowym modułem, a podpisy używają `SecurityAlgorithms.RsaSha256` (RS256). Domyślny rozmiar jest wyrażony jednokrotnie jako parametr `rsaBits = 4096` w `IKeyGenerator.Generate` i w `JwtKeyStore.RotateAsync`, natomiast algorytm jest ustalony w momencie tworzenia poświadczeń; rozmiar pozostaje nadpisywalny przez wywołującego na potrzeby rotacji. + +### Uzasadnienie projektowe + +- RSA-4096 daje konserwatywny margines bezpieczeństwa dla długowiecznych kluczy podpisujących. +- RS256 jest szeroko wspierany przez weryfikatory JWT i naturalnie paruje się z kluczami RSA oraz JWKS publikowanym przez magazyn. +- Centralizacja domyślnego utrzymuje generator i magazyn w zgodzie i sprawia, że przyszła zmiana algorytmu to edycja w jednym miejscu. + +## Odrzucone + +- Domyślne RSA-2048 lub mniejsze „ze względu na wydajność". +- Uczynienie ECDSA domyślnym algorytmem. +- Zakodowanie algorytmu na sztywno w magazynie przy pozostawieniu generatorowi swobody wyboru innego. + +## Konsekwencje + +Nowe klucze są konsekwentnie silne i weryfikowalne w całym ekosystemie. Kosztem jest większy rozmiar klucza (więcej CPU na podpis) oraz potrzeba ponownego rozważenia domyślnego, jeśli zmieni się model zagrożeń lub wsparcie standardów. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - magazyn kluczy budujący poświadczenia +- [ADR-006](/pl/adr/006-kid-as-generated-guid/) - identyfikator generowany wraz z kluczem + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/006-kid-as-generated-guid/) | [Następny](/pl/adr/008-standardized-error-response/) diff --git a/Docs/content/pl/adr/008-standardized-error-response.md b/Docs/content/pl/adr/008-standardized-error-response.md new file mode 100644 index 0000000..a090e53 --- /dev/null +++ b/Docs/content/pl/adr/008-standardized-error-response.md @@ -0,0 +1,59 @@ +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/007-default-signing-algorithm-rsa-4096/) | [Następny](/pl/adr/009-dynamic-plugin-discovery/) + +# [ADR-008] Standaryzuj błędy API poprzez kontrakt odpowiedzi na błąd w Core + +*2026-08* | Status: accepted + +**Tag:** #adr_008 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Core + +## Kontekst + +Hosty (REST, gRPC, wtyczki) zgłaszają awarie klientom API i potrzebują spójnego kształtu, aby konsumenci mogli parsować błędy programowo. Rdzeń definiuje już bazę `DomainException` dla naruszeń reguł oraz `ErrorMetadataOptions` dla linków dokumentacyjnych. + +## Problem + +Bez współdzielonego kontraktu błędów należącego do rdzenia każdy host wymyśla własny schemat JSON, nazwy pól i obsługę znaczników czasu, fragmentując obsługę błędów po stronie klientów i łamiąc interoperacyjność pomiędzy powierzchniami API. + +## Decyzja + +Rdzeń jest właścicielem standaryzowanego DTO `ErrorResponse` z polami JSON `error` i `error_description` (zgodnymi z nazewnictwem błędów OAuth2) oraz znacznikiem czasu UTC `timestamp`, a także bazą `DomainException`, którą hosty mapują na ten kontrakt. Odwołania dokumentacyjne błędów są scentralizowane w `ErrorMetadataOptions.DocsBaseUrl`. + +### ErrorResponse + +**Obowiązki:** + +- Prezentuje stabilny, kliencki kształt błędu (`error`, `error_description`, `timestamp`). +- Pozostaje przyjazny serializacji i agnostyczny względem hosta. + +### DomainException + +**Obowiązki:** + +- Działa jako wspólna baza naruszeń reguł domenowych. +- Daje hostom jeden typ do przechwytywania i tłumaczenia na `ErrorResponse`. + +### Uzasadnienie projektowe + +- Jeden kontrakt utrzymuje jednolite parsowanie błędów przez klientów we wszystkich hostach. +- Nazwy pól maksymalizują kompatybilność ze standardowymi klientami. +- Znacznik czasu UTC wspomaga korelację i audyt bez logiki specyficznej dla hosta. + +## Odrzucone + +- Pozwolenie każdemu hostowi na definiowanie własnego kształtu JSON błędów. +- Zwracanie klientom surowego tekstu wyjątków lub śladów stosu. +- Pomijanie znacznika czasu lub linku dokumentacyjnego w kontrakcie. + +## Konsekwencje + +Klienci otrzymują przewidywalny format błędów, a hosty współdzielą jedną ścieżkę tłumaczenia awarii domenowych. Kosztem jest utrzymywanie `ErrorResponse` i `DomainException` w synchronizacji w miarę pojawiania się nowych przypadków błędów. + +## Powiązane + +- [ADR-014](/pl/adr/014-error-responses-via-middleware/) - host renderuje ten kontrakt jako ProblemDetails + +[Strona ADR](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/007-default-signing-algorithm-rsa-4096/) | [Następny](/pl/adr/009-dynamic-plugin-discovery/) diff --git a/Docs/content/pl/adr/009-dynamic-plugin-discovery.md b/Docs/content/pl/adr/009-dynamic-plugin-discovery.md new file mode 100644 index 0000000..3bd8c36 --- /dev/null +++ b/Docs/content/pl/adr/009-dynamic-plugin-discovery.md @@ -0,0 +1,65 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/008-standardized-error-response/) | [Następny](/pl/adr/010-plugin-loading-from-directory/) + +# [ADR-009] Odkrywanie i dynamiczne ładowanie wtyczek poprzez kontrakt IAuthKitPlugin + +*2026-08* | Status: accepted + +**Tag:** #adr_009 + +**Date:** 2026-08-26 + +**Scope:** AuthKit.Plugins.Abstractions + +## Kontekst + +AuthKit.Server składa się z hosta oraz opcjonalnych pakietów rozwiązań (na przykład rozwiązania tokenów deweloperskich `DevTokens`). Host musi móc rozszerzać swój zestaw funkcji nowe usługi, middleware, kontrole kondycji i schematy uwierzytelniania bez rekompilacji ani bezpośredniego odwoływania się do każdego rozwiązania w czasie budowania. + +## Problem + +Jeśli rozwiązania są podłączane do hosta poprzez statyczne referencje projektów i ręcznie pisaną rejestrację, host wiąże się z każdą funkcją, a każda nowa możliwość staje się zmianą hosta. Host potrzebuje też jednolitego sposobu, aby rozszerzenie mogło wnieść wkład do kontenera DI, potoku żądań, powierzchni kondycji oraz metadanych OpenAPI, pozostając jednocześnie odizolowanym za stabilnymi abstrakcjami. + +## Decyzja + +Wtyczki implementują kontrakt `IAuthKitPlugin` i są odkrywane oraz ładowane dynamicznie przez hosta podczas startu. Wtyczka **nie** musi być bezpośrednio referencjonowana przez projekt hosta. Rozszerzenie wnosi wkład do działającego serwera poprzez dobrze zdefiniowane, opcjonalne elementy kontraktu. + +### IAuthKitPlugin + +**Obowiązki:** + +- Identyfikowanie wtyczki (`Name`, `Version`, opcjonalny `Description`) na potrzeby diagnostyki i metadanych. +- Rejestrowanie usług wtyczki w kontenerze DI hosta poprzez `ConfigureServices` (wtyczka nie może tworzyć własnego kontenera). +- Opcjonalne dostarczenie typu middleware ASP.NET Core (`MiddlewareType`) wstawianego przez hosta w slocie potoku wtyczek. +- Opcjonalne udostępnienie sygnału kondycji poprzez `CheckHealthAsync`, rozwiązywanego z głównego dostawcy usług hosta. +- Opcjonalne dostarczenie niezależnych od transportu schematów bezpieczeństwa OpenAPI poprzez `GetSecuritySchemes`. + +### AuthKitSecuritySchemeDescriptor + +**Obowiązki:** + +- Opisywanie mechanizmu uwierzytelniania (klucz API, HTTP, OAuth2, OpenID Connect) na poziomie metadanych. +- Pozostawanie niezależnym od transportu, tak aby ten sam schemat mógł obsługiwać nagłówki HTTP i metadane gRPC. + +### Uzasadnienie projektowe + +- Dynamiczne odkrywanie utrzymuje hosta w separacji od konkretnych rozwiązań i pozwala dostarczać funkcje jako pakiety typu drop-in. +- Jeden kontrakt z sensownymi domyślnymi implementacjami elementów opcjonalnych sprawia, że wtyczki są małe, a kod integracyjny hosta jednolity. +- Izolacja za `AuthKit.Plugins.Abstractions` oznacza, że wtyczki zależą wyłącznie od kontraktu, a nie od wewnętrznych mechanizmów hosta klucze podpisujące i powiązania tokenów z kluczami pozostają własnością rdzenia i są konsumowane poprzez DI, a nie reimplementowane. + +## Odrzucone + +- Statyczne referencje projektów i rejestracja w czasie kompilacji dla każdego rozwiązania. +- Pozwalanie każdej wtyczce na tworzenie własnego kontenera wstrzykiwania zależności i zarządzanie nim. +- Kodowanie middleware wtyczek lub kontroli kondycji na sztywno w hoście zamiast odkrywania ich z kontraktu. +- Osadzanie zależnych od transportu szczegółów uwierzytelniania bezpośrednio w kodzie wtyczki zamiast poprzez niezależny od transportu deskryptor. + +## Konsekwencje + +Host pozostaje stabilny, podczas gdy funkcje są dodawane jako niezależnie ładowalne wtyczki, a każda wtyczka integruje się poprzez jedną przewidywalną powierzchnię. Kosztem jest mechanizm odkrywania/ładowania podczas startu oraz dyscyplina utrzymywania zachowania wtyczek w granicach kontraktu wtyczki muszą polegać na wstrzykiwanych usługach rdzenia (takich jak klucze podpisujące), zamiast sięgać do wewnętrznych mechanizmów hosta. + +## Powiązane + +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - odkrywanie i ładowanie wtyczek po stronie hosta +- [ADR-004](/pl/adr/004-token-key-bindings-domain/) - wtyczki konsumują powiązania rdzenia poprzez kontrakt +- [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) - procedury obsługi wtyczek działają na tej infrastrukturze + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/008-standardized-error-response/) | [Następny](/pl/adr/010-plugin-loading-from-directory/) diff --git a/Docs/content/pl/adr/010-plugin-loading-from-directory.md b/Docs/content/pl/adr/010-plugin-loading-from-directory.md new file mode 100644 index 0000000..c94d8e4 --- /dev/null +++ b/Docs/content/pl/adr/010-plugin-loading-from-directory.md @@ -0,0 +1,61 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/009-dynamic-plugin-discovery/) | [Następny](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) + +# [ADR-010] Ładowanie wtyczek z konfigurowalnego katalogu podczas startu + +*2026-08* | Status: accepted + +**Tag:** #adr_010 + +**Date:** 2026-08-26 + +**Scope:** Host.Plugins + +## Kontekst + +Host musi uruchamiać pakiety wtyczek bez referencji w czasie kompilacji (zob. ADR-009). Krok ładowania musi nastąpić wystarczająco wcześnie, aby infrastruktura konfigurowana później Wolverine, Marten, MVC mogła zobaczyć złożenia wtyczek podczas budowania własnej konfiguracji. + +## Problem + +Jeśli wtyczki są ładowane po zbudowaniu hosta, ich procedury obsługi, kontrolery i rejestracje DI są niewidoczne dla frameworków, które już przeskanowały złożenia. Host potrzebuje też przewidywalnego, prostego sposobu lokalizowania wejściowego złożenia każdej wtyczki oraz bezpiecznego obsługiwania błędów, gdy folder jest nieprawidłowy. + +## Decyzja + +`PluginLoader.LoadPlugins` odkrywa wtyczki z konfigurowalnej ścieżki `PluginsPath` (domyślnie `/plugins`) **przed** wywołaniem `WebApplicationBuilder.Build()`. Każda wtyczka znajduje się we własnym podkatalogu, którego nazwa musi odpowiadać jej wejściowemu złożeniu (`.dll`); program ładujący odnajduje przez refleksję publiczne, nieabstrakcyjne implementacje `IAuthKitPlugin` z konstruktorem bezparametrowym, tworzy ich instancje i zapisuje je jako `LoadedPlugin` (kontrakt + złożenie + katalog). Złożenia są ładowane do `AssemblyLoadContext.Default` (a nie do izolowanego kontekstu), dzięki czemu typy frameworka i pakietów są współdzielone ponad granicą, a gorące przeładowywanie jest jawnie niewspierane. + +### PluginLoader + +**Obowiązki:** + +- Wyliczanie podkatalogów wtyczek i rozwiązywanie zależności każdego wejściowego złożenia. +- Walidowanie i tworzenie instancji implementacji `IAuthKitPlugin`. +- Zwracanie wyłącznie pomyślnie załadowanych wtyczek, logowanie i pomijanie nieprawidłowych folderów. + +### LoadedPlugin + +**Obowiązki:** + +- Przenoszenie instancji kontraktu, złożenia i katalogu źródłowego do późniejszego użycia przez hosta (DI, odkrywanie złożeń przez Wolverine/MVC). + +### Uzasadnienie projektowe + +- Ładowanie przed `Build` pozwala Wolverine, Marten i MVC odkrywać typy wtyczek podczas konfiguracji. +- Domyślny kontekst ładowania współdzieli typy uruchomieniowe (Wolverine `IMessageBus`, Marten `IDocumentSession`, typy MVC) ponad granicą, unikając błędów tożsamości typów. +- Konwencja nazewnictwa oraz łagodne pomijanie sprawiają, że wdrożenie jest proste i odporne na uszkodzony folder wtyczki. + +## Odrzucone + +- Ładowanie wtyczek do izolowanych `AssemblyLoadContext` (niezgodności tożsamości typów ze współdzielonymi frameworkami). +- Ładowanie po zbudowaniu hosta (infrastruktura nie widziałaby złożeń wtyczek). +- Wspieranie gorącej podmiany lub wyładowywania wtyczek w czasie działania. +- Wymaganie pliku manifestu wykraczającego poza konwencję nazewnictwa katalogu/złożenia. + +## Konsekwencje + +Wtyczki są dostępne przed skonfigurowaniem infrastruktury i uczestniczą jednolicie w DI, przesyłaniu komunikatów i MVC. Kosztem jest brak izolacji i przeładowywania w czasie działania, a host ufa złożeniom wtyczek załadowanym do domyślnego kontekstu, więc pochodzenie wtyczek musi być kontrolowane operacyjnie. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - ładowany kontrakt wtyczki +- [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) - załadowane złożenia zasilają Wolverine/Marten + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/009-dynamic-plugin-discovery/) | [Następny](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) diff --git a/Docs/content/pl/adr/011-keystore-persisted-as-singleton-marten-document.md b/Docs/content/pl/adr/011-keystore-persisted-as-singleton-marten-document.md new file mode 100644 index 0000000..19a9a1b --- /dev/null +++ b/Docs/content/pl/adr/011-keystore-persisted-as-singleton-marten-document.md @@ -0,0 +1,54 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/010-plugin-loading-from-directory/) | [Następny](/pl/adr/012-token-key-bindings-persisted-in-marten/) + +# [ADR-011] Utrzymywanie zaszyfrowanego magazynu kluczy jako singletonowego dokumentu Marten + +*2026-08* | Status: accepted + +**Tag:** #adr_011 + +**Date:** 2026-08-26 + +**Scope:** Host.KeyManagement.Repositories + +## Kontekst + +ADR-001 definiuje `IKeyStoreRepository` jako czysty odbiornik utrwalania, a ADR-002 stanowi, że przekazywane są mu wyłącznie zaszyfrowane bajty magazynu kluczy. Host musi zdecydować, gdzie te zaszyfrowane bajty faktycznie będą przechowywane. + +## Problem + +Zaszyfrowany magazyn kluczy musi być trwały pomiędzy restartami, ale repozytorium nie może przejmować kryptografii, a magazyn musi być adresowany w prosty sposób dla całego serwera istnieje dokładnie jeden magazyn kluczy. + +## Decyzja + +`KeyStoreRepository` utrwala magazyn kluczy jako pojedynczy dokument Marten o stałym identyfikatorze (`"singleton"`), przy użyciu lekkich sesji. Przechowuje wyłącznie zaszyfrowany ładunek (`KeystoreDocument.EncryptedData`); nigdy go nie szyfruje, nie odszyfrowuje ani nie interpretuje. Podczas odczytu zwraca `Memory.Empty`, gdy dokument nie istnieje; podczas zapisu wstawia lub aktualizuje singletonowy dokument, najpierw kopiując bajty wywołującego do nowej tablicy. + +### KeyStoreRepository + +**Obowiązki:** + +- Odczyt/zapis zaszyfrowanego magazynu kluczy jako jednego dokumentu Marten identyfikowanego stałym identyfikatorem. +- Pozostawanie agnostycznym wobec kryptografii i używanie wyłącznie lekkich sesji. + +### Uzasadnienie projektowe + +- Singletonowy dokument odpowiada modelowi „jeden magazyn kluczy na serwer” i eliminuje zarządzanie kluczami/wyszukiwaniem. +- Utrzymywanie repozytorium jako prostego magazynu zaszyfrowanych bajtów respektuje granicę z ADR-001/ADR-002. +- Marten zapewnia trwałe, transakcyjne utrwalanie, z którego reszta hosta (Wolverine, wtyczki) już korzysta. + +## Odrzucone + +- Osobny plik płaski lub niestandardowy magazyn blobów poza Marten. +- Wiele dokumentów magazynu kluczy lub dokumenty na klucz. +- Pozwalanie repozytorium na wykonywanie szyfrowania lub odszyfrowywania. + +## Konsekwencje + +Materiał kluczowy przetrwa restarty w tym samym magazynie co reszta danych hosta, a rotacja (ADR-001) jest po prostu aktualizacją (upsert) singletonu. Kosztem jest twarda zależność od Marten/Postgres dla dostępności kluczy oraz dyscyplina, że repozytorium nigdy nie zagląda do ładunku. + +## Powiązane + +- [ADR-001](/pl/adr/001-centralize-signing-key-management/) - abstrakcja magazynu kluczy utrwalana tutaj +- [ADR-002](/pl/adr/002-encrypt-keystore-at-rest/) - przechowywane są wyłącznie zaszyfrowane bajty +- [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) - Marten jako magazyn hosta + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/010-plugin-loading-from-directory/) | [Następny](/pl/adr/012-token-key-bindings-persisted-in-marten/) diff --git a/Docs/content/pl/adr/012-token-key-bindings-persisted-in-marten.md b/Docs/content/pl/adr/012-token-key-bindings-persisted-in-marten.md new file mode 100644 index 0000000..b14671d --- /dev/null +++ b/Docs/content/pl/adr/012-token-key-bindings-persisted-in-marten.md @@ -0,0 +1,60 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) | [Następny](/pl/adr/013-dual-rest-and-grpc-transport/) + +# [ADR-012] Utrzymywanie powiązań tokenów z kluczami w Marten + +*2026-08* | Status: accepted + +**Tag:** #adr_012 + +**Date:** 2026-08-26 + +**Scope:** Host.TokenKeyBindings.Repositories + +## Kontekst + +ADR-004 czyni powiązania tokenów z kluczami podpisującymi domeną rdzenia, a ADR-011 utrwala sam zaszyfrowany materiał kluczy podpisujących jako singletonowy dokument Marten. Host musi zdecydować, gdzie przechowywany jest stan powiązań, aby przetrwał restarty wraz z kluczami, do których się odwołuje. + +## Problem + +Powiązania łączą tokeny deweloperskie z kluczami podpisującymi i wspierają rotację, aktualizacje kluczy publicznych oraz unieważnianie. Jeśli są trzymane wyłącznie w pamięci, znikają przy restarcie, wymuszając ponowne ustanawianie każdego powiązania token -> klucz i psując weryfikację już wydanych tokenów po ponownym wdrożeniu. Repozytorium musi przy tym pozostać wolne od logiki domenowej i używać tego samego magazynu, od którego zależy już reszta hosta. + +## Decyzja + +`KeyBindingRepository` utrwala każde `TokenKeyBinding` jako dokument Marten identyfikowany złożonym identyfikatorem zbudowanym z identyfikatora tokenu deweloperskiego i identyfikatora klucza podpisującego (`"{tokenId:N}:{signingKeyId}"`). Używa lekkich sesji Marten, przechowuje wyłącznie zserializowane powiązanie i nie wykonuje żadnych przejść ani operacji kryptograficznych. + +### KeyBindingRepository + +**Obowiązki:** + +- Dodawanie/pobieranie/aktualizowanie/wyliczanie encji `TokenKeyBinding` poprzez dokumenty Marten. +- Adresowanie każdego powiązania poprzez złożoną tożsamość `(tokenId, signingKeyId)`. +- Pozostawanie czystą granicą utrwalania, jak `KeyStoreRepository` (ADR-011). + +### KeyBindingDocument + +**Obowiązki:** + +- Przenoszenie identyfikatora dokumentu Marten oraz utrwalonego ładunku `TokenKeyBinding`. + +### Uzasadnienie projektowe + +- Trwałe utrwalanie zachowuje pochodzenie token -> klucz oraz stan unieważnień pomiędzy restartami, dzięki czemu wydane tokeny pozostają weryfikowalne po ponownym wdrożeniu. +- Ponowne użycie Marten (ADR-016) eliminuje drugi magazyn danych i utrzymuje powiązania spójne z magazynem kluczy transakcyjnie i operacyjnie. +- Złożony identyfikator dokumentu odpowiada naturalnej tożsamości powiązania i sprawia, że `GetAsync` oraz `ListByTokenAsync` są bezpośrednimi odczytami/zapytaniami. + +## Odrzucone + +- Osobny plik płaski lub niestandardowy magazyn blobów poza Marten. +- Pozwalanie repozytorium na wykonywanie przejść powiązań lub szyfrowania. + +## Konsekwencje + +Powiązania kluczy tokenów są trwałe i przeszukiwalne jak reszta danych hosta, a projekt pozostaje czysty implementacja `IKeyBindingRepository`. Kosztem jest twarda zależność od Marten/Postgres dla dostępności powiązań (ta sama zależność, która jest już wymagana przez magazyn kluczy) oraz dyscyplina, że repozytorium nigdy nie przegląda ani nie modyfikuje ładunku powiązania. + +## Powiązane + +- [ADR-004](/pl/adr/004-token-key-bindings-domain/) - domena utrwalana tutaj +- [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) - magazyn kluczy utrwalany w ten sam sposób +- [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) - Marten jako magazyn hosta + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) | [Następny](/pl/adr/013-dual-rest-and-grpc-transport/) diff --git a/Docs/content/pl/adr/013-dual-rest-and-grpc-transport.md b/Docs/content/pl/adr/013-dual-rest-and-grpc-transport.md new file mode 100644 index 0000000..f527968 --- /dev/null +++ b/Docs/content/pl/adr/013-dual-rest-and-grpc-transport.md @@ -0,0 +1,47 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/012-token-key-bindings-persisted-in-marten/) | [Następny](/pl/adr/014-error-responses-via-middleware/) + +# [ADR-013] Udostępnianie zarówno powierzchni transportowej REST, jak i gRPC + +*2026-08* | Status: accepted + +**Tag:** #adr_013 + +**Date:** 2026-08-26 + +**Scope:** Host + +## Kontekst + +Host musi obsługiwać klientów API o różnych potrzebach konwencjonalnych konsumentów HTTP/JSON oraz wydajnych klientów gRPC działających w podejściu contract-first. Obie powierzchnie opierają się na tej samej domenie Core i wkładzie wtyczek. + +## Problem + +Zobowiązanie do jednego transportu albo wyklucza klasę klientów, albo wymusza niezręczną warstwę adaptacyjną. Uruchamianie dwóch oddzielnych procesów duplikuje kompozycję, konfigurację i powierzchnię operacyjną. + +## Decyzja + +Host jest pojedynczą aplikacją ASP.NET Core, która udostępnia zarówno powierzchnię REST (kontrolery/MVC poprzez `AddRestfulServices` i `MapAppEndpoints`), jak i powierzchnię gRPC (`AddGrpcServices` i `MapGrpcEndpoints`) z jednego złożonego potoku. Obie opierają się na tych samych usługach Core, tym samym wkładzie wtyczek (ADR-009/010) i tej samej infrastrukturze (ADR-016). + +### Uzasadnienie projektowe + +- Jeden proces i jeden korzeń kompozycji utrzymują wspólną konfigurację, DI, middleware i ładowanie wtyczek dla obu transportów. +- REST zapewnia szeroką interoperacyjność HTTP/JSON; gRPC zapewnia typowane, niskonarzutowe kontrakty z tej samej domeny. +- Jeden potok zapobiega rozjazdom między tym, co potrafi każdy transport. + +## Odrzucone + +- Udostępnianie wyłącznie REST albo wyłącznie gRPC. +- Dzielenie powierzchni na oddzielne wdrażalne procesy. +- Tunelowanie jednego transportu przez drugi zamiast natywnych punktów końcowych. + +## Konsekwencje + +Klienci mogą wybrać transport, który im odpowiada, bez drugiego wdrożenia, a oba pozostają spójne z Core. Kosztem jest utrzymywanie dwóch zestawów kontraktów (OpenAPI i protobuf) oraz dbanie o to, aby obie powierzchnie odzwierciedlały to samo zachowanie domenowe i dostarczane przez wtyczki schematy bezpieczeństwa. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - obie powierzchnie eksponują wkład wtyczek +- [ADR-014](/pl/adr/014-error-responses-via-middleware/) - ujednolicone renderowanie błędów dla obu transportów +- [ADR-015](/pl/adr/015-keycloak-external-jwt-authority/) - uwierzytelnianie chroniące obie powierzchnie + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/012-token-key-bindings-persisted-in-marten/) | [Następny](/pl/adr/014-error-responses-via-middleware/) diff --git a/Docs/content/pl/adr/014-error-responses-via-middleware.md b/Docs/content/pl/adr/014-error-responses-via-middleware.md new file mode 100644 index 0000000..d3b85bc --- /dev/null +++ b/Docs/content/pl/adr/014-error-responses-via-middleware.md @@ -0,0 +1,50 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/013-dual-rest-and-grpc-transport/) | [Następny](/pl/adr/015-keycloak-external-jwt-authority/) + +# [ADR-014] Renderowanie błędów HTTP jako Problem Details wg RFC 7807 poprzez middleware + +*2026-08* | Status: accepted + +**Tag:** #adr_014 + +**Date:** 2026-08-26 + +**Scope:** Host.Restful.Middleware.Exceptions + +## Kontekst + +ADR-008 stanowi, że Core jest właścicielem współdzielonego słownika błędów (`DomainException`, `ErrorResponse`, `ErrorMetadataOptions`). Host musi przekształcać niepowodzenia naruszenia domenowe, błędy walidacji i wyniki autoryzacji w spójny kształt HTTP bez ujawniania wewnętrznych szczegółów. + +## Problem + +Rozpraszanie obsługi błędów w każdym kontrolerze daje niespójne odpowiedzi i grozi ujawnieniem śladów stosu. Format na styku musi być standardowy i maszynowo czytelny oraz musi pozostać powiązany ze słownikiem błędów Core. + +## Decyzja + +Trzy komponenty hosta centralizują renderowanie błędów HTTP, wszystkie emitując `ProblemDetails` wg RFC 7807 z polami `error_code`, `trace_id` oraz dokumentacyjnym `type` budowanym z `ErrorMetadataOptions.DocsBaseUrl`: + +- `ExceptionHandlingMiddleware` mapuje `DomainException` na `409 Conflict` (kod wywodzony z typu wyjątku), a każdy inny wyjątek na `500` bez wewnętrznych szczegółów. +- `ValidationExceptionMiddleware` mapuje FluentValidation `ValidationException` na `400 Bad Request` z błędami pogrupowanymi według właściwości. +- `CustomAuthorizationMiddlewareResultHandler` mapuje challenge/forbidden na `401`/`403`. + +### Uzasadnienie projektowe + +- Potok middleware przechwytuje błędy w jednym miejscu, dzięki czemu kontrolery pozostają czyste, a odpowiedzi jednolite. +- RFC 7807 to standardowy format problemów rozumiany przez klientów HTTP i generatory kodu. +- Mapowanie z `DomainException` sprawia, że słownik błędów Core (ADR-008) pozostaje jedynym źródłem domenowego znaczenia błędów, podczas gdy host wybiera konkretną reprezentację na styku. + +## Odrzucone + +- Zwracanie kształtu DTO `ErrorResponse` z Core bezpośrednio jako jedynego kontraktu HTTP (mniej przyjazne narzędziom niż ProblemDetails). +- Pozwalanie wyjątkom propagować się do domyślnej strony frameworka. +- Ujawnianie komunikatów wyjątków lub śladów stosu dla błędów niedomenowych. + +## Konsekwencje + +Klienci HTTP otrzymują przewidywalne, oparte na standardach ciało błędu z kodami i identyfikatorami śledzenia, a błędy domenowe pozostają tworzone w Core. Kosztem jest utrzymywanie dwóch powiązanych, lecz odrębnych kształtów słownika `ErrorResponse` z Core oraz renderowania `ProblemDetails` hosta oraz synchronizowanie mapowania w miarę pojawiania się nowych wyjątków domenowych. + +## Powiązane + +- [ADR-008](/pl/adr/008-standardized-error-response/) - słownik błędów Core renderowany tutaj +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - dotyczy powierzchni REST + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/013-dual-rest-and-grpc-transport/) | [Następny](/pl/adr/015-keycloak-external-jwt-authority/) diff --git a/Docs/content/pl/adr/015-keycloak-external-jwt-authority.md b/Docs/content/pl/adr/015-keycloak-external-jwt-authority.md new file mode 100644 index 0000000..14d10bf --- /dev/null +++ b/Docs/content/pl/adr/015-keycloak-external-jwt-authority.md @@ -0,0 +1,46 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/014-error-responses-via-middleware/) | [Następny](/pl/adr/016-marten-and-wolverine-infrastructure/) + +# [ADR-015] Używanie Keycloak jako zewnętrznego urzędu JWT + +*2026-08* | Status: accepted + +**Tag:** #adr_015 + +**Date:** 2026-08-26 + +**Scope:** Host.Configuration + +## Kontekst + +Host musi uwierzytelniać wywołujących (w tym administracyjne i chronione przez wtyczki punkty końcowe) przy użyciu podpisanych JWT wystawianych przez prawdziwego dostawcę tożsamości, zamiast samodzielnie wystawiać lub weryfikować tokeny. + +## Problem + +Budowanie lokalnego magazynu użytkowników lub tokenów wystawianych samodzielnie wiąże hosta z logiką tożsamości, której nie powinien posiadać, a klienci oczekują standardowych przepływów OIDC/JWT bearer. Host musi weryfikować tokeny i udostępniać role Keycloak autoryzacji ASP.NET Core bez ręcznego przetwarzania oświadczeń. + +## Decyzja + +`AddKeycloakServices` rejestruje uwierzytelnianie JWT bearer ASP.NET Core względem realmu Keycloak: `Authority` i `Audience` pochodzą z `KEYCLOAK_URL`/`KEYCLOAK_REALM`/`KEYCLOAK_CLIENT_ID` (z lokalnymi domyślnymi wartościami deweloperskimi), walidacja wystawcy i odbiorców jest włączona, `NameClaimType` to `preferred_username`, a hak `OnTokenValidated` mapuje role klienta Keycloak z `resource_access` na standardowe oświadczenia `ClaimTypes.Role`. + +### Uzasadnienie projektowe + +- Delegowanie do Keycloak utrzymuje hosta z dala od wystawiania tożsamości i dowodzi tokenów poprzez standardową walidację JWT bearer. +- Mapowanie ról `resource_access` na oświadczenia ról pozwala zwykłym politykom ASP.NET Core autoryzować bez kodu specyficznego dla Keycloak w procedurach obsługi. +- Konfiguracja sterowana środowiskiem wspiera realms deweloperskie, testowe i produkcyjne z tego samego kodu. + +## Odrzucone + +- Samodzielnie wystawiana lub lokalna usługa tokenów wewnątrz hosta. +- Niestandardowa baza użytkowników/ról. +- Wyłączanie walidacji wystawcy/odbiorców. + +## Konsekwencje + +Wywołujący uwierzytelniają się standardowymi JWT wystawianymi przez Keycloak, a polityki oparte na rolach działają jednolicie. Dwa celowe ustępstwa deweloperskie są udokumentowane jako kompromisy: `RequireHttpsMetadata = false` oraz procedura obsługi kanału zwrotnego `DangerousAcceptAnyServerCertificateValidator` oba muszą zostać zaostrzone przed jakimkolwiek wdrożeniem produkcyjnym. + +## Powiązane + +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - chroni obie powierzchnie transportowe +- [ADR-014](/pl/adr/014-error-responses-via-middleware/) - nieautoryzowane/zabronione renderowane tutaj + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/014-error-responses-via-middleware/) | [Następny](/pl/adr/016-marten-and-wolverine-infrastructure/) diff --git a/Docs/content/pl/adr/016-marten-and-wolverine-infrastructure.md b/Docs/content/pl/adr/016-marten-and-wolverine-infrastructure.md new file mode 100644 index 0000000..202e581 --- /dev/null +++ b/Docs/content/pl/adr/016-marten-and-wolverine-infrastructure.md @@ -0,0 +1,51 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/015-keycloak-external-jwt-authority/) | [Następny]() + +# [ADR-016] Używanie Marten i Wolverine jako infrastruktury hosta + +*2026-08* | Status: accepted + +**Tag:** #adr_016 + +**Date:** 2026-08-26 + +**Scope:** Host.Configuration + +## Kontekst + +Host potrzebuje magazynu dokumentów dla danych trwałych (w tym magazynu kluczy z ADR-011 i dokumentów wtyczek) oraz szkieletu obsługi komunikatów/poleceń, który potrafi także odkrywać procedury obsługi wnoszone przez dynamicznie ładowane wtyczki (ADR-010). + +## Problem + +Wybór prymitywów utrwalania i przesyłania komunikatów wpływa na każdą warstwę: wtyczki muszą móc uczestniczyć w tym samym potoku poleceń i magazynie dokumentów, a walidacja powinna być częścią przetwarzania komunikatów, a nie być rozproszona. Ręczne budowanie dyspozytora lub mieszanie ORM-ów komplikuje tę integrację. + +## Decyzja + +Host standaryzuje Marten jako magazyn dokumentów oraz Wolverine jako szkielet przesyłania komunikatów/poleceń, zintegrowane ze sobą: + +- `ConfigureMarten` łączy z Marten (ciąg połączenia `Marten`), schemat `AutoCreate.All`, lekkie sesje oraz `IntegrateWithWolverine()`; `IDocumentSession` jest udostępniany jako usługa o zakresie (scoped). +- `ConfigureWolverine` używa Wolverine z FluentValidation zintegrowanym z przetwarzaniem komunikatów oraz `IncludeEventHandlers(plugins)`, dzięki czemu odkrywane są procedury obsługi ze złożenia Core i dynamicznie ładowanych złożeń wtyczek. + +### Uzasadnienie projektowe + +- Integracja Marten + Wolverine pozwala współdzielić transakcje między zapisami dokumentów a obsługą komunikatów oraz mieć jedną historię konfiguracji. +- Odkrywanie procedur obsługi ze złożeń wtyczek oznacza, że rozwiązania (np. DevTokens) wpinają się w ten sam potok poleceń bez zmian hosta. +- FluentValidation w potoku Wolverine centralizuje walidację poleceń przed uruchomieniem procedur obsługi. + +## Odrzucone + +- Entity Framework Core lub niestandardowy ORM jako główny magazyn. +- Ręcznie pisany dyspozytor poleceń zamiast Wolverine. +- Osobny magazyn zdarzeń/komunikatów odłączony od magazynu dokumentów. + +## Konsekwencje + +Wtyczki i Core współdzielą jeden model utrwalania i przesyłania komunikatów, co utrzymuje spójność procedur obsługi, dokumentów i magazynu kluczy. Kosztem jest wymagana zależność Postgres/Marten oraz powierzchnia nauki dwóch frameworków; logowanie infrastrukturalne dla Wolverine/Marten/Npgsql jest celowo wyciszone, aby ograniczyć szum. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - procedury obsługi wtyczek odkrywane przez Wolverine +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - załadowane złożenia zasilają infrastrukturę +- [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) - magazyn kluczy przechowywany w Marten +- [ADR-012](/pl/adr/012-token-key-bindings-persisted-in-marten/) - powiązania przechowywane w Marten + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/015-keycloak-external-jwt-authority/) | [Następny](/pl/adr/017-api-key-credential-extraction-strategies/) diff --git a/Docs/content/pl/adr/017-api-key-credential-extraction-strategies.md b/Docs/content/pl/adr/017-api-key-credential-extraction-strategies.md new file mode 100644 index 0000000..11d892f --- /dev/null +++ b/Docs/content/pl/adr/017-api-key-credential-extraction-strategies.md @@ -0,0 +1,59 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/016-marten-and-wolverine-infrastructure/) | [Następny](/pl/adr/018-security-scheme-contract-explicit-handling/) + +# [ADR-017] Wyodrębnianie poświadczeń klucza API poprzez strategie lokalizacji i formatu treści + +*2026-09* | Status: accepted + +**Tag:** #adr_017 + +**Date:** 2026-09-10 + +**Scope:** Host.Security + +## Kontekst + +Wtyczki eksponują mechanizmy uwierzytelniania jako niezależne od transportu metadane `AuthKitSecuritySchemeDescriptor` (ADR-009). Dla schematów klucza API deskryptor deklaruje, gdzie znajduje się poświadczenie, poprzez `AuthKitApiKeyLocation` (nagłówek, zapytanie, ciasteczko, metadane gRPC lub treść żądania). Host musi przekształcić te metadane w pobranie rzeczywistego poświadczenia z przychodzącego żądania asp.net, zweryfikować je i ustanowić uwierzytelnioną tożsamość bez wiązania autorów schematów z mechaniką HTTP. + +## Problem + +Pojedynczy ekstraktor/middleware, który wewnętrznie obsługuje wszystkie pięć lokalizacji oraz buforowanie treści, parsowanie JSON, parsowanie formularzy i normalizację wartości, staje się orkiestratorem i obiektem „boskim”. Dodanie nowej lokalizacji lub nowego formatu treści wymaga modyfikacji istniejącego kodu, a niskopoziomowa mechanika transportu (buforowanie, JSON, dekodowanie formularzy) jest splątana z przepływem orkiestracji (wyodrębnienie -> weryfikacja -> tożsamość). + +## Decyzja + +Pobieranie poświadczeń klucza API jest podzielone na małe strategie o pojedynczej odpowiedzialności, zarejestrowane w kontenerze DI hosta w `Host.Security`: + +- **Strategie lokalizacji** implementują `IApiKeyLocationExtractor`, po jednej na `AuthKitApiKeyLocation` (`Header`, `Query`, `Cookie`, `GrpcMetadata`, `Body`). Każda strategia umie czytać tylko własną lokalizację i normalizować wartość. +- **`IApiKeyLocationExtractorRegistry`** (oparty na DI) mapuje `AuthKitApiKeyLocation` -> strategia. Rejestr rzuca `NotSupportedException` dla lokalizacji bez zarejestrowanej strategii, więc niewspierane konfiguracje zawodzą szybko. +- **Parsery formatu treści** implementują `IApiKeyBodyParser` i są wybierane według typu zawartości żądania. Obecnie zarejestrowane są `JsonApiKeyBodyParser` i `FormUrlEncodedApiKeyBodyParser`; nowy format to nowa klasa plus rejestracja. +- **`ApiKeyCredentialExtractor`** to cienki middleware, który tylko orkiestruje: rozwiązuje schemat, wyodrębnia poprzez rejestr, weryfikuje poprzez `IApiKeyValidator`, a po sukcesie dołącza oświadczenia jednostki jako uwierzytelnioną tożsamość. Nie zawiera logiki parsowania ani buforowania. +- **`IApiKeyValidator`** pozostaje kontraktem skierowanym do wtyczek do weryfikacji wyodrębnionego klucza, utrzymując semantykę poświadczeń poza hostem. +- **`ApiKeyCredentialExtractorOptions`** centralizuje wartości domyślne (nazwy pól nagłówka/zapytania/ciasteczka, próg buforowania treści) i jest konsumowany poprzez `IOptions`. +- Wszystko to jest rejestrowane przez `AddApiKeyCredentialExtraction(...)`. + +Wyodrębnianie z treści buforuje żądanie poprzez `EnableBuffering`, odczytuje ładunek i przywraca pozycję strumienia, dzięki czemu dalsze middleware i kontrolery nadal widzą treść w stanie nienaruszonym. + +### Uzasadnienie projektowe + +- **Otwarte/Zamknięte**: nowa lokalizacja lub format treści dodaje klasę i rejestrację DI bez edytowania istniejącej strategii, parsera ani middleware. +- **Pojedyncza odpowiedzialność**: middleware jest właścicielem orkiestracji; każda strategia/parser jest właścicielem dokładnie jednego zagadnienia mechanicznego. +- **Odwrócenie zależności**: middleware zależy od abstrakcji rejestru i walidatora, a nie od parsowania `HttpContext` czy JSON. +- **Orkiestracja fail-open**: gdy nie wytworzono poświadczenia ani jednostki, potok jest kontynuowany, aby dalsze uwierzytelnianie zdecydowało o wyniku wyodrębnianie nigdy nie przerywa niepowiązanego żądania. + +## Odrzucone + +- Pojedynczy ekstraktor z instrukcjami switch/if i wbudowaną logiką treści oraz JSON każda nowa lokalizacja lub format modyfikuje orkiestrator. +- Opieranie decyzji parsowania na schemacie wewnątrz middleware wiąże orkiestrację z mechaniką formatu. +- Wymaganie od każdej wtyczki implementowania własnego wyodrębniania duplikuje parsowanie `HttpContext`, buforowanie i normalizację pomiędzy rozwiązaniami. +- Cicha konwersja niewspieranych lokalizacji (np. traktowanie `GrpcMetadata` jako zwykłych nagłówków HTTP bez zarejestrowanej strategii) ukrywa błędną konfigurację. + +## Konsekwencje + +`Host.Security` zawiera teraz wiele małych typów zamiast jednego dużego dodanie lokalizacji lub formatu kosztuje pliki i rejestrację, ale nigdy edycję istniejącego zachowania. Rejestr sprawia, że rzeczywiście niewspierane lokalizacje zawodzą szybko podczas rozwiązywania. Parsowanie treści jest selektywne względem typu zawartości, więc niejednoznaczne ładunki nie dają poświadczenia (fail-open), a nie błąd walidacja pozostaje zagadnieniem wtyczki za `IApiKeyValidator`, a host dołącza oświadczenia dopiero po pomyślnej weryfikacji. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - deskryptory i podłączane uwierzytelnianie wnoszone przez wtyczki +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - slot middleware wtyczek, w którym działa wyodrębnianie +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - transport metadanych gRPC reprezentowany jako nagłówki HTTP pisane małymi literami + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/016-marten-and-wolverine-infrastructure/) | [Następny](/pl/adr/018-security-scheme-contract-explicit-handling/) diff --git a/Docs/content/pl/adr/018-security-scheme-contract-explicit-handling.md b/Docs/content/pl/adr/018-security-scheme-contract-explicit-handling.md new file mode 100644 index 0000000..e6e2363 --- /dev/null +++ b/Docs/content/pl/adr/018-security-scheme-contract-explicit-handling.md @@ -0,0 +1,59 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/017-api-key-credential-extraction-strategies/) | [Następny](/pl/adr/019-plugin-metadata-attribute/) + +# [ADR-018] Rozszerzenie kontraktu schematu bezpieczeństwa o jawne wsparcie hosta i OpenAPI + +*2026-09* | Status: accepted + +**Tag:** #adr_018 + +**Date:** 2026-09-10 + +**Scope:** AuthKit.Plugins.Abstractions + +## Kontekst + +Wtyczki eksponują mechanizmy uwierzytelniania jako niezależne od transportu metadane `AuthKitSecuritySchemeDescriptor` (ADR-009). Pierwotny kontrakt wyliczenia `AuthKitSecuritySchemeType` obejmował wyłącznie `ApiKey`, `Http`, `OAuth2` oraz `OpenIdConnect`, przy czym `OpenIdConnect` był aliasem `OAuth2` dzielącym wartość liczbową `2`. `AuthKitApiKeyLocation` obejmował `Header`, `Query` oraz `Cookie`. Każdy inny mechanizm (wzajemny TLS, sesje, schematy definiowane przez wtyczki, HTTP Basic) lub transport (metadane gRPC, treść żądania) musiał być przybliżany ciągami znaków albo przeciążaniem istniejących wartości. + +## Problem + +Przybliżanie niszczy bezpieczeństwo typów i pozwala hostowi mylić odrębne mechanizmy: uwierzytelnianie sesyjne z kluczem API przenoszonym w ciasteczku, HTTP Basic z generycznym uwierzytelnianiem HTTP, metadane gRPC z nagłówkami HTTP oraz poświadczenie w treści z poświadczeniem w nagłówku lub parametrze zapytania. Ponadto dołączony serializator OpenAPI (Swashbuckle 9.x / Microsoft.OpenApi 1.6.x) nie potrafi reprezentować wzajemnego TLS, sesji, schematów niestandardowych, metadanych gRPC ani lokalizacji w treści w swoim wyjściu OpenAPI 3.0. Podstawienie generycznego schematu nie tylko ukryłoby błędną konfigurację, ale wygenerowałoby wprowadzającą w błąd dokumentację dla klientów i generowanych SDK. + +## Decyzja + +Oba wyliczenia rosną addytywnie, a każda wartość jest obsługiwana jawnie przez hosta i przez mapper OpenAPI: + +- `AuthKitSecuritySchemeType` zyskuje `MutualTls = 3`, `Session = 4`, `Custom = 5`, `Basic = 6`. Istniejące wartości pozostają nietknięte (`ApiKey = 0`, `Http = 1`, `OAuth2 = 2`). Historyczny alias zostaje usunięty: `OpenIdConnect` staje się odrębną wartością `7`, przy czym odstępstwo udokumentowano w uwagach; przenumerowanie istniejących wartości jest zabronione, ponieważ wartości liczbowe są częścią kontraktu wtyczki (`ApiKey`..`Basic` zajmują już `0`..`6`). +- `AuthKitApiKeyLocation` zyskuje `GrpcMetadata = 3` oraz `Body = 4`; istniejące wartości pozostają nietknięte. +- Wartości liczbowe są zadeklarowane jako część kontraktu wtyczki w obu wyliczeniach: nigdy nie wolno ich ponownie używać ani przenumerowywać. +- Host wylicza swoje możliwości jako `PluginContractValidator.SupportedSchemeTypes` oraz `SupportedApiKeyLocations`. `PluginContractValidator.Validate` sprawdza każdy zadeklarowany typ schematu i lokalizację względem tych zbiorów: wartości wspierane przechodzą, wartości zdefiniowane, lecz niewspierane oraz nieznane (przyszłe) zgłaszają `InvalidPluginContractException`. Nieznane wartości są identyfikowane po ich tożsamości liczbowej i nigdy nie są rozwiązywane do `Custom` ani żadnej znanej wartości. +- `AuthKitOpenApiSecuritySchemeMapper` mapuje każdą wartość jawnie: semantycznie poprawne reprezentacje OpenAPI dla `ApiKey`, `Http`, `OAuth2`, `OpenIdConnect` oraz `Basic` (jako uwierzytelnianie HTTP ze schematem `basic`); `NotSupportedException` dla wartości bez poprawnej reprezentacji 3.0 (`MutualTls`, `Session`, `Custom`; `GrpcMetadata` i `Body` jako lokalizacje klucza API); `ArgumentOutOfRangeException` dla wartości nieznanych. +- Wsparcie uruchomieniowe i reprezentowalność w OpenAPI są ortogonalne: host wspiera ekstrakcję poświadczeń `GrpcMetadata` i `Body` w czasie działania (ADR-017), mimo że OpenAPI 3.0 nie potrafi ich opisać. `RestfulConfiguration` przechwytuje błędy mappera, loguje ostrzeżenie i pomija definicję nigdy nie emituje generycznego zamiennika i nigdy nie przerywa generowania dokumentu. +- Do `Custom` powinna być dołączona opcjonalna, dostarczona przez wtyczkę `Description`; brak opisu generuje ostrzeżenie walidacji (nigdy mapowanie na schemat wbudowany). +- Host akceptuje wyłącznie `OpenApi:SpecVersion` `3.0`. `3.1`, która byłaby potrzebna do prawdziwej reprezentacji `mutualTLS`, jest odrzucana z `InvalidOperationException` zamiast cichego emitowania dokumentu 3.0. + +### Uzasadnienie projektowe + +- **Addytywny kontrakt**: stare wtyczki (w tym `DevTokens`) kompilują się i ładują bez zmian, a utrwalone deskryptory zachowują znaczenie. +- **Jawność zamiast sprytu**: każda wartość kontraktu ma nazwany przypadek w dokładnie dwóch miejscach (sprawdzenie możliwości hosta oraz mapper OpenAPI), zmuszając autorów do decyzji o wsparciu lub odrzuceniu każdej nowej wartości. +- **Szybkie zgłaszanie błędów**: niewspierany schemat kończy walidację wtyczki przy starcie, a niereprezentowalny jest pomijany w Swaggerze z zalogowanym powodem. +- **Żadnego fałszywego OpenAPI**: emitowanie `apiKey` dla wzajemnego TLS albo `Header` dla metadanych gRPC wygenerowałoby prawdopodobnie wyglądające, lecz błędne kontrakty klienckie. + +## Odrzucone + +- Przenumerowanie istniejących wartości wyliczeń dla czystszej sekwencji łamie każdą wydaną wtyczkę i utrwalony deskryptor; zabronione regułą niezmienności. +- Zachowanie aliasu `OpenIdConnect` = `OAuth2` dwa odrębne mechanizmy nie mogą dzielić tożsamości liczbowej; wtyczka deklarująca przepływ OIDC nie może deserializować się jako OAuth2. +- Generyczny mechanizm zapasowy w mapperze (nieznane -> `Custom`, `MutualTls` -> HTTP, `GrpcMetadata` -> `Header`, `Body` -> `Header`/`Query`/`Cookie`) ukrywa błędną konfigurację i emituje wprowadzającą w błąd dokumentację. +- Automatyczne podnoszenie generowanych dokumentów do OpenAPI 3.1 dla uzyskania `mutualTLS` dołączony stos serializatorów nie wspiera 3.1 host odrzuca ustawienie zamiast cichego obniżania wersji. +- Traktowanie `Session` jako klucza API w ciasteczku oraz `Basic` jako generycznego uwierzytelniania HTTP odtwarza niejednoznaczność, którą ten ADR usuwa. + +## Konsekwencje + +Dodawanie nowego mechanizmu uwierzytelniania lub transportu jest teraz addytywne: zdefiniuj wartość, rozszerz zbiór możliwości hosta, dodaj przypadek mappera i pokryj go testami pozytywnymi oraz testami braku mechanizmu zapasowego. Wartość OpenIdConnect znajduje się poza naturalną sekwencją `0`..`6` (udokumentowaną w uwagach wyliczenia). Wtyczki deklarujące niewspierane mechanizmy nie przechodzą walidacji kontraktu przy starcie; rozszerzenia hosta używają `PluginContractValidator.CreateCustom`. Wyjście Swaggera dla wtyczki mieszającej schematy reprezentowalne i niereprezentowalne zawiera wyłącznie definicje reprezentowalne, z zalogowanym ostrzeżeniem na pominięty schemat. Istnieją teraz dwie jawne gwarancje kontraktu: brak cichego mechanizmu zapasowego między schematami lub lokalizacjami oraz zawsze odrzucane nieznane przyszłe wartości. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - deskryptory schematów bezpieczeństwa wtyczek +- [ADR-017](/pl/adr/017-api-key-credential-extraction-strategies/) - ekstrakcja uruchomieniowa dla nagłówka/zapytania/ciasteczka/metadanych gRPC/treści +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - powierzchnia transportu gRPC + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/017-api-key-credential-extraction-strategies/) | [Następny](/pl/adr/019-plugin-metadata-attribute/) diff --git a/Docs/content/pl/adr/019-plugin-metadata-attribute.md b/Docs/content/pl/adr/019-plugin-metadata-attribute.md new file mode 100644 index 0000000..cd486ae --- /dev/null +++ b/Docs/content/pl/adr/019-plugin-metadata-attribute.md @@ -0,0 +1,53 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/018-security-scheme-contract-explicit-handling/) | [Następny](/pl/adr/020-devtools-plugin/) + +# [ADR-019] Deklarowanie tożsamości wtyczki poprzez atrybut PluginMetadata + +*2026-09* | Status: accepted + +**Tag:** #adr_019 + +**Date:** 2026-09-11 + +**Scope:** AuthKit.Plugins.Abstractions + +## Kontekst + +Każda implementacja `IAuthKitPlugin` (ADR-009) eksponowała swoją tożsamość poprzez nadpisywanie właściwości `Name`, `Version` oraz `Description` w kodzie. Wtyczki DevTokens i DevTools powielały ten szablon, a bogatsze informacje katalogowe stabilny identyfikator maszynowy, tagi, możliwości, zależności, autor, licencja, URL repozytorium nie miały w ogóle powierzchni kontraktu. + +## Problem + +Powtarzanie tożsamości jako właściwości kodu C# rozprasza tożsamość wtyczki po treści klasy, zamienia podbicie wersji w edycję kodu i nie pozostawia jednego strukturalnego miejsca, w którym przyszłe narzędzia (diagnostyka ładowania, panel administracyjny) mogłyby odczytać tożsamość i metadane katalogowe. Dodanie metadanych katalogowych wymagałoby nowych elementów kontraktu interfejsu, zmuszając każdą istniejącą wtyczkę do ich implementacji. + +## Decyzja + +Tożsamość wtyczki i metadane katalogowe przenoszą się do atrybutu `[PluginMetadata]` na klasie wtyczki: + +- `PluginMetadataAttribute` (przestrzeń nazw `AuthKit.Plugins.Abstractions.Contracts.Plugins`) deklaruje `Id`, `Version`, `Name`, `Tags`, `DependsOn`, `Capabilities`, `DisplayName`, `Description`, `Author`, `License`, `LicenseUrl`, `Homepage` oraz `RepositoryUrl`. Konstruktor to `(id, version, name, ...)` ze wszystkimi polami po `name` opcjonalnymi. +- `IAuthKitPlugin.Name`, `Version` oraz `Description` są teraz **domyślnymi elementami interfejsu**, które odczytują atrybut poprzez prywatną metodę pomocniczą `GetPluginMetadata()`. Wtyczki nie muszą ich już implementować: `Name` przyjmuje nazwę typu, a `Version` wartość `0.0.0`, gdy klasa nie ma atrybutu. +- Wtyczki mogą nadal nadpisywać te trzy właściwości, jeśli potrzebują wyliczanej tożsamości, lecz atrybut jest preferowanym punktem deklaracji. Obie dostarczone wtyczki (`DevTokens`, `DevTools`) deklarują swoją tożsamość wyłącznie poprzez `[PluginMetadata]`. +- `AttributeUsage` to `Class`, `Inherited = false`, `AllowMultiple = false` jeden atrybut na klasę wtyczki. +- Metadane tablicowe (`Tags`, `DependsOn`, `Capabilities`) są eksponowane jako `IReadOnlyList` i domyślnie przyjmują pustą listę, gdy ich brak, więc konsumenci nigdy nie widzą `null`. + +### Uzasadnienie projektowe + +- **Jeden punkt deklaracji**: tożsamość i katalogowanie znajdują się w jednym atrybucie, obok opisywanej klasy. +- **Zgodność wsteczna**: domyślne elementy interfejsu utrzymują kompilowalność i ładowalność starych klas wtyczek; żadna zmiana hosta, wtyczki ani `PluginLoader` nie była wymagana dla odkrywania ani wyjścia startowego. +- **Addytywne katalogowanie**: metadane tagów/możliwości/zależności/autorstwa zyskują powierzchnię kontraktu bez dotykania listy elementów interfejsu (bez łamiącej zmiany dla istniejących implementacji). +- **Deklaratywność zamiast imperatywności**: metadane jako atrybut są czytelne, wykrywalne poprzez refleksję i użyteczne przez narzędzia, które nigdy nie instancjonują klasy wtyczki. + +## Odrzucone + +- Dodanie `Tags`, `Capabilities`, `Dependencies` itd. jako nowych abstrakcyjnych elementów `IAuthKitPlugin` łamie każdą istniejącą implementację wtyczki (łamanie kontraktu w czasie kompilacji). +- Zachowanie tożsamości wyłącznie jako właściwości kodu obok osobnego atrybutu katalogowego rozdziela tożsamość na dwa mechanizmy. +- Plik metadanych (JSON/zasób osadzony) jako dodatek traci sprawdzanie w czasie kompilacji i wykrywalność przez refleksję przy niewielkim zysku. + +## Konsekwencje + +Nowe wtyczki deklarują jeden atrybut i otrzymują poprawne `Name`/`Version`/`Description` za darmo; program ładujący wtyczki hosta konsumuje atrybut poprzez domyślne elementy interfejsu, więc wyjście startowe `ServerHost` ("Loaded plugin 'DevTools' v1.0.0") odzwierciedla wartości atrybutu. Pola katalogowe są dostępne dla przyszłych powierzchni administracyjnych bez dalszych zmian kontraktu. Ponieważ domyślne elementy interfejsu można nadpisywać, wtyczka potrzebująca wyliczanej tożsamości zachowuje tę swobodę, lecz obie dostarczone wtyczki już z niej nie korzystają. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - kontrakt `IAuthKitPlugin` rozszerzany przez ten ADR +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - program ładujący odczytujący tożsamość wtyczki przy starcie + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/018-security-scheme-contract-explicit-handling/) | [Następny](/pl/adr/020-devtools-plugin/) diff --git a/Docs/content/pl/adr/020-devtools-plugin.md b/Docs/content/pl/adr/020-devtools-plugin.md new file mode 100644 index 0000000..5509c63 --- /dev/null +++ b/Docs/content/pl/adr/020-devtools-plugin.md @@ -0,0 +1,126 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/019-plugin-metadata-attribute/) | [Następny](/pl/adr/021-swagger-serving-via-reflection/) + +# [ADR-020] Hostowanie narzędzi deweloperskich poprzez dedykowaną wtyczkę DevTools + +*2026-09* | Status: accepted + +**Tag:** #adr_020 + +**Date:** 2026-09-11 + +**Scope:** Host + Plugins.Solutions.DevTools + +## Kontekst + +AuthKit potrzebuje narzędzi dla deweloperów do ćwiczenia własnych powierzchni: interaktywnej strony do wywoływania dowolnej eksponowanej metody gRPC oraz Swagger UI do przeglądania powierzchni REST/OpenAPI. Wcześniejsze prace eksponowały UI gRPC jako samodzielną wtyczkę `GrpcUI` i serwowały Swagger UI na samym hoście poprzez `UseSwagger` / `UseSwaggerUI` (bezpośredni middleware Swashbuckle). Oba narzędzia żyły w różnych domach architektonicznych: jedno było wtyczką, drugie było wbudowane na sztywno w potok żądań hosta. + +## Problem + +Narzędzie wbudowane w hosta może być włączone wyłącznie razem z hostem, wiąże hosta z middleware serwującym Swashbuckle i nie może być współdzielone między wariantami hosta ani usuwane bez edycji kodu hosta. Dedykowana wtyczka `GrpcUI` pokrywała gRPC, lecz pozostawiała narzędzia REST/OpenAPI poza granicą wtyczki dwa mechanizmy do tej samej pracy, dwa miejsca konfiguracji. Adresy URL narzędzi były też stałymi, niejawnymi ścieżkami hosta zamiast konfigurowalnych prefiksów należących do wtyczki. + +## Decyzja + +Oba narzędzia deweloperskie przenoszą się do jednej wtyczki `DevTools` (`src/Plugins/Solutions/DevTools`), zastępując samodzielną wtyczkę `GrpcUI` i usuwając serwowanie Swaggera z hosta: + +- Wtyczka posiada własną przestrzeń URL poprzez `DevToolsOptions`: UI gRPC pod `GrpcUiPathBase` (`/grpc-ui`), Swagger UI w sekcji `Swagger` (domyślny prefiks trasy `swagger`, nazwa dokumentu `v1`, tytuł `AuthKit API`) oraz strona startowa pod `PathBase` (`/devtools`). +- UI gRPC działa w procesie: `GrpcServiceCatalog` skanuje domyślny kontekst ładowania złożeń pod kątem statycznych właściwości `ServiceDescriptor`, `GrpcDynamicInvoker` wykonuje metody jednoodpowiedziowe dynamicznie przez `Grpc.Net.Client` bez generowanych stubów, a `DevToolsMiddleware` obsługuje `/grpc-ui` oraz jego endpointy `/api/services` + `/api/invoke`. +- Generowanie dokumentu Swagger pozostaje w hoście (`RestfulConfiguration` + `AddSwaggerGen`); wyłącznie middleware SERWUJĄCY Swagger przenosi się do `DevTools` poprzez `SwaggerHost`. +- Host nie wywołuje już `UseSwagger` / `UseSwaggerUI`; `AppMiddlewareConfiguration` zawiera wyłącznie slot wtyczki. Narzędzia deweloperskie są obecne we wdrożeniu dokładnie wtedy, gdy wtyczka jest wdrożona. +- Serwowanie Swagger UI jest bramkowane: domyślnie włączone tylko w środowisku deweloperskim (`Swagger.Enabled ?? environment.IsDevelopment()`), z przypięciem wersji specyfikacji OpenAPI serwowanego dokumentu. +- Host jest publikowany z domyślnie wybranym `DevTools` (plik rozwiązania i Dockerfile), więc domyślne wdrożenie zachowuje dostępność obu narzędzi. + +### Uzasadnienie projektowe + +- **Jedna powierzchnia narzędziowa**: REST (Swagger) i gRPC (UI w procesie) są obiema interaktywnymi reprezentacjami tego samego hosta jedna wtyczka posiada doświadczenie deweloperskie. +- **Spójna granica wtyczki**: wszystko, co odwiedza deweloper szablonu, jest wnoszone przez wtyczkę, pod prefiksami ścieżek należącymi do wtyczki, usuwalne poprzez niewdrażanie wtyczki. +- **W procesie zamiast proxy**: UI gRPC rozmawia z hostem bezpośrednio zamiast stawiać czoła osobnemu procesowi i używać refleksji gRPC, utrzymując odkrywanie lokalnie i konfigurację na minimalnym poziomie. +- **Bez potrzeby stubów**: dynamiczne wywoływanie na deskryptorach metod oznacza, że wtyczka nigdy nie potrzebuje generowanego kodu klienta dla renderowanych usług. + +## Odrzucone + +- Zachowanie serwowania Swaggera w hoście (`UseSwagger`/`UseSwaggerUI`) wiąże hosta z konkretnym narzędziem i konkretnym middleware serwującym. +- Samodzielna wtyczka `GrpcUI` z należącym do hosta Swaggerem dwa domy dla równoważnej funkcjonalności. +- Proces proxy gRPC (np. utrzymywany zewnętrzny binarny UI gRPC) dla wsparcia strumieni i kondycji dodatkowy proces wdrożeniowy i przeskok transportowy; dodatkowe wsparcie uznano za zbędne dla wewnętrznego narzędzia deweloperskiego. +- Serwowanie Swaggera z wtyczki przy jednoczesnym przeniesieniu tam generowania dokumentu powieliłoby konfigurację `AddSwaggerGen` generowanie pozostaje w hoście, serwowanie pozostaje we wtyczce. + +## Kontrakt HTTP API + +Wtyczka DevTools eksponuje dwa endpointy JSON API konsumowane przez frontend TypeScript: + +### `/api/services` GrpcCatalogResponse + +Zwraca odkryte usługi gRPC dla katalogu: + +```csharp +public sealed class GrpcCatalogResponse +{ + public required string Target { get; init; } + public required IEnumerable Services { get; init; } +} + +public sealed class GrpcServiceInfo +{ + public required string Name { get; init; } // Short service name + public required string FullName { get; init; } // Fully qualified name + public string? Description { get; init; } // Nullable proto doc comment (null = absent) + public required string Package { get; init; } + public required string FileName { get; init; } + public bool IsPlugin { get; init; } // Default: false (backward-compatible for host services) + public required IEnumerable Methods { get; init; } +} +``` + +- `Description`: wartość nullable typu string z dokumentacji proto. Nieobecna (`null`), gdy proto nie ma komentarza. +- `IsPlugin`: domyślnie `false` dla usług hosta, co zapewnia zgodność wsteczną ze złożeniami niebędącymi wtyczkami. + +### `/api/invoke` GrpcInvocationRequest → GrpcInvocationResult + +Wykonuje jednoodpowiedziową metodę gRPC: + +```csharp +public sealed class GrpcInvocationRequest +{ + public required string Service { get; init; } + public required string Method { get; init; } + public required string RequestJson { get; init; } + public IReadOnlyDictionary Headers { get; init; } = new Dictionary(); +} + +public sealed class GrpcInvocationResult +{ + public required bool Success { get; init; } + public required string StatusName { get; init; } + public required int StatusCode { get; init; } + public string? Detail { get; init; } + public string? ResponseJson { get; init; } + public string? ResponseBase64 { get; init; } // Success-only base64-encoded protobuf payload; null on failure + public double ElapsedMs { get; init; } + public IReadOnlyDictionary? Trailers { get; init; } +} +``` + +- `ResponseBase64`: wypełniane wyłącznie przy udanych wywołaniach (`Success == true`). Zawiera surowe bajty protobuf zakodowane jako base64. +- **Limit rozmiaru ładunku**: ładunek base64 jest ograniczony do `int.MaxValue - 1` bajtów (≈2 GB) z powodu ograniczeń rozmiaru protobuf. +- `ResponseJson`: obecne wyłącznie przy powodzeniu, zawierające odpowiedź sformatowaną jako JSON poprzez formater JSON protobuf. +- Nieudane wywołania zwracają `Success = false` z wypełnionymi `Detail` i `Trailers` do debugowania. + +### Serializacja JSON + +Wszystkie DTO są serializowane przy użyciu `System.Text.Json` z `JsonSerializerDefaults.Web` dla spójnej konwencji wielkości liter: + +- Nazwy właściwości w JSON w konwencji PascalCase (np. `"ResponseBase64"`, `"IsPlugin"`). +- Pola nullable są pomijane, gdy są null (domyślne zachowanie JSON ASP.NET Core). +- Pola boolowskie o wartości `false` są uwzględniane (nie pomijane). + +## Konsekwencje + +`AppMiddlewareConfiguration` hosta jest mniejsze i nie odwołuje się już do Swashbuckle. Rozwiązanie `DevTools` posiada kod narzędziowy przyjazny kompilatorowi (katalog, invoker, middleware, opcje i zasoby UI). Dostępność Swagger UI zależy od wdrożenia wtyczki i bramkowania środowiskowego zamiast konfiguracji budowania hosta. UI gRPC wspiera wyłącznie metody jednoodpowiedziowe metody strumieniowe są raportowane jako niewspierane zamiast przybliżane. Konfiguracja jest scentralizowana w `DevToolsOptions`, rozwiązywana ze zmiennymi środowiskowymi (`GRPC_UI_TARGET`, `DEV_CERT_PORT_GRPC`) do lokalnego dewelopmentu przeciw punktowi końcowemu HTTPS gRPC. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - kontrakt wtyczki i dynamiczne odkrywanie +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - slot middleware wtyczki używany przez DevToolsMiddleware +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - ćwiczone powierzchnie dualne REST + gRPC +- [ADR-021](/pl/adr/021-swagger-serving-via-reflection/) - jak SwaggerHost serwuje SwaggerUI poprzez refleksję + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/019-plugin-metadata-attribute/) | [Następny](/pl/adr/021-swagger-serving-via-reflection/) diff --git a/Docs/content/pl/adr/021-swagger-serving-via-reflection.md b/Docs/content/pl/adr/021-swagger-serving-via-reflection.md new file mode 100644 index 0000000..9223c74 --- /dev/null +++ b/Docs/content/pl/adr/021-swagger-serving-via-reflection.md @@ -0,0 +1,55 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/020-devtools-plugin/) | [Następny]() + +# [ADR-021] Serwowanie Swaggera poprzez opartego na refleksji SwaggerHost w DevTools + +*2026-09* | Status: accepted + +**Tag:** #adr_021 + +**Date:** 2026-09-11 + +**Scope:** Plugins.Solutions.DevTools + +## Kontekst + +ADR-020 przeniósł serwowanie Swagger UI z hosta do wtyczki `DevTools`. Wtyczka konsumowała już dostawcę dokumentu OpenAPI (`ISwaggerProvider`, rejestrowanego przez `RestfulConfiguration` + `AddSwaggerGen`), lecz faktyczna serializacja dokumentu i renderowanie HTML UI były wykonywane przez `SwaggerMiddleware` i `SwaggerUIMiddleware` Swashbuckle z których oba są **wewnętrzne** dla swoich pakietów NuGet, więc wtyczka nie może ich wywoływać tak, jak robił to wcześniej host. + +## Problem + +Wtyczka musi odtworzyć to, co host robił wcześniej publicznymi metodami rozszerzającymi `UseSwagger` / `UseSwaggerUI`, lecz stojące za tymi rozszerzeniami middleware nie są częścią publicznej powierzchni API. Wtyczka musi też kontrolować wersję specyfikacji OpenAPI przypiętą dla serwowanego dokumentu niezależnie od dokumentu, który `RestfulConfiguration` mógłby generować dla innych konsumentów. + +## Decyzja + +`DevTools` serwuje Swaggera przy użyciu opartego na refleksji `SwaggerHost`: + +- `SwaggerHost` rozwiązuje wewnętrzne typy `Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware` oraz `Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware` po nazwie kwalifikowanej złożeniem przy starcie, konstruuje jedną instancję na middleware poprzez `Activator.CreateInstance` ze standardowym kształtem konstruktora (notFound, options) i wywołuje wewnętrzne metody `Invoke` refleksyjnie na żądanie. +- Middleware dokumentu Swagger jest konfigurowane szablonem trasy pod skonfigurowanym prefiksem trasy Swagger oraz rozwiązaną wersją specyfikacji OpenAPI. +- Middleware Swagger UI otrzymuje opcje UI (prefiks trasy, tytuł dokumentu, `IndexStream` wskazujący osadzony zasób `index.html`) oraz punkt końcowy wskazujący trasę dokumentu. +- `DevToolsMiddleware` decyduje, czy ścieżka żądania należy do wtyczki (UI gRPC, Swagger, strona startowa) i dla segmentu Swagger deleguje do `SwaggerHost.TryServeAsync`; 404-not-found `RequestDelegate` jest przekazywany do middleware Swashbuckle, gdy ścieżka nie pasuje. +- Wersja specyfikacji OpenAPI serwowanego dokumentu jest rozwiązywana przez `SwaggerHost.ResolveSpecVersion`: nadpisanie `DevTools:Swagger:SpecVersion`, potem hostowe `OpenApi:SpecVersion`, domyślnie `3.0`. Wspierane wartości to `3.0.x` oraz `3.1.x`; nieznana wartość loguje ostrzeżenie i wraca do `3.0`. +- Ponieważ serwowany dokument używa wersji specyfikacji przypiętej dla DevTools, schematy wzajemnego TLS (ADR-018) pojawiają się natywnie (`mutualTLS`) wyłącznie wtedy, gdy dokument jest przypięty do OpenAPI 3.1. + +### Uzasadnienie projektowe + +- **Ponowne użycie zamiast reimplementacji**: wtyczka nie reimplementuje serializacji OpenAPI ani HTML UI steruje dokładnie tym middleware, którego używał host, poprzez refleksję, ponieważ typy są wewnętrzne. +- **Jednokrotna konstrukcja**: instancje middleware są budowane raz przy starcie wtyczki i używane ponownie dla każdego żądania; pracą na żądanie jest refleksyjne wywołanie, nie przebudowa. +- **Niezależne przypięcie**: DevTools kontroluje własną wersję specyfikacji dokumentu zamiast dziedziczyć stały dokument hosta, co pozwala działać w DevTools przypadkom mappera OpenAPI zależnym od 3.1 (ADR-018). + +## Odrzucone + +- Reimplementacja strony Swagger UI oraz serializacji OpenAPI wewnątrz wtyczki powiela dużą, utrzymywaną powierzchnię bez zysku architektonicznego. +- Zależność od wewnętrznych typów Swashbuckle jako twarde odwołanie biblioteczne są wewnętrzne z założenia; twarde odwołanie po prostu by się nie skompilowało. +- Kopiowanie/wysyłanie źródeł middleware Swashbuckle do wtyczki obciążenie licencyjne i utrzymaniowe oraz dryf względem poprawek upstream. +- Całkowite usunięcie serwowania Swaggera z DevTools (tylko dokument JSON pod znanym URL) traci interaktywne UI, które motywowało wtyczkę. + +## Konsekwencje + +`DevTools` pozostaje na wersji Swashbuckle dostarczającej wewnętrzne middleware; aktualizacja wersji Swashbuckle mogłaby zmienić sygnatury wewnętrznych typów/metod i złamać `SwaggerHost` przy starcie (fail-fast z opisowym wyjątkiem). Warstwa refleksji to celowy, widoczny koszt: dwa wyszukiwania `Type`/`MethodInfo` oraz `Invoke` na żądanie zamiast bezpośrednich wywołań. Nieznane wersje specyfikacji degradują się do ostrzeżenia + 3.0 w serwowaniu DevTools (więc UI nadal działa), co jest celowo bardziej pobłażliwe niż `RestfulConfiguration`, które twardo zgłasza błąd przy nieznanych wersjach specyfikacji w konfiguracji aplikacji. + +## Powiązane + +- [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) - powierzchnia OpenAPI serwowana przez DevTools +- [ADR-020](/pl/adr/020-devtools-plugin/) - dlaczego serwowanie Swaggera w ogóle żyje we wtyczce +- [ADR-018](/pl/adr/018-security-scheme-contract-explicit-handling/) - schematy wzajemnego TLS wymagają przypięcia 3.1, które dostarcza DevTools + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/020-devtools-plugin/) | [Następny]() diff --git a/Docs/content/pl/adr/022-plugin-configuration-context-and-builder.md b/Docs/content/pl/adr/022-plugin-configuration-context-and-builder.md new file mode 100644 index 0000000..e824885 --- /dev/null +++ b/Docs/content/pl/adr/022-plugin-configuration-context-and-builder.md @@ -0,0 +1,62 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/021-swagger-serving-via-reflection/) | [Następny](/pl/adr/023-plugin-application-pipeline-hooks/) + +# [ADR-022] Rozszerzenie konfiguracji wtyczki o builder hosta i zakresowy kontekst + +*2026-09* | Status: accepted + +**Tag:** #adr_022 + +**Date:** 2026-09-12 + +**Scope:** AuthKit.Plugins.Abstractions + Host + +## Kontekst + +Wtyczki konfigurowały wcześniej usługi poprzez `ConfigureServices(IServiceCollection, IConfiguration)`. To wystarczało do rejestracji, lecz nie eksponowało faktycznego buildera hosta ani stabilnego, specyficznego dla wtyczki kontekstu konfiguracji. + +## Problem + +Dodanie abstrakcyjnych elementów do `IAuthKitPlugin` złamałoby istniejące wtyczki. Przekazywanie kolejnych indywidualnych zależności hosta utrudniłoby też ewolucję kontraktu i zachęcałoby wtyczki do polegania na wewnętrznych mechanizmach hosta. + +## Decyzja + +Kontrakt wtyczki eksponuje addytywne domyślne elementy interfejsu: + +- `ConfigureServices(IHostApplicationBuilder, IConfiguration)` dla wtyczek potrzebujących prawdziwego buildera hosta AuthKit. +- `ConfigureServices(IServiceCollection, AuthKitPluginContext)` dla wtyczek potrzebujących stabilnej tożsamości wtyczki i kontekstu konfiguracji. +- Istniejące `ConfigureServices(IServiceCollection, IConfiguration)` pozostaje poprawne dla starszych wtyczek. + +`AuthKitPluginContext` żyje w główniej przestrzeni nazw `AuthKit.Plugins.Abstractions` i eksponuje: + +- stabilny `PluginId`; +- `PluginName`; +- zakresową dla wtyczki `Configuration` z `Plugins:{PluginId}` z rezerwą do nazwy; +- pełną `ApplicationConfiguration` tylko do odczytu dla ustawień poziomu hosta. + +Host używa jednego dyspozytora. Wybiera najpierw konfigurację kontekstową, potem konfigurację buildera hosta, a na końcu starsze przeciążenie. Dla wtyczki wywoływane jest tylko jedno przeciążenie, więc ścieżki zgodności nie mogą zarejestrować tych samych usług dwukrotnie. + +### Uzasadnienie projektowe + +- Domyślne implementacje interfejsu zachowują zgodność źródłową. +- Faktyczny `WebApplicationBuilder` jest przekazywany zamiast konstruowania izolowanego buildera. +- Zakresowa dla wtyczki konfiguracja zapobiega przypadkowemu odczytaniu ustawień innej wtyczki. +- Pełna konfiguracja aplikacji pozostaje dostępna jawnie bez tworzenia drugiego DI ani drugiego systemu konfiguracji. + +## Odrzucone + +- Uczynienie nowych przeciążeń abstrakcyjnymi złamałoby istniejące wtyczki. +- Konstruowanie osobnego buildera hosta odłączyłoby rejestracje od działającej aplikacji. +- Przekazywanie `IServiceProvider` przez kontekst wprowadziłoby zachowanie service-locator. +- Wywoływanie każdego przeciążenia powodowałoby podwójną rejestrację i niejednoznaczne zachowanie. + +## Konsekwencje + +Nowe wtyczki mogą optować za konfiguracją świadomą hosta albo zakresowymi danymi kontekstu. Istniejące wtyczki, takie jak DevTokens i DevTools, nadal używają swojej starszej implementacji bez zmian źródłowych. Dyspozytor jest zagadnieniem hosta, a publiczny kontrakt pozostaje niezależny od wewnętrznego programu ładującego wtyczki hosta. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - kontrakt wtyczki i dynamiczne odkrywanie +- [ADR-019](/pl/adr/019-plugin-metadata-attribute/) - deklaratywna tożsamość wtyczki używana przez kontekst +- [Issue #8](https://github.com/AuthKits/AuthKit.Server/issues/8) - wymagania buildera hosta i kontekstu wtyczki + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/021-swagger-serving-via-reflection/) | [Następny](/pl/adr/023-plugin-application-pipeline-hooks/) diff --git a/Docs/content/pl/adr/023-plugin-application-pipeline-hooks.md b/Docs/content/pl/adr/023-plugin-application-pipeline-hooks.md new file mode 100644 index 0000000..386c8e4 --- /dev/null +++ b/Docs/content/pl/adr/023-plugin-application-pipeline-hooks.md @@ -0,0 +1,60 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/022-plugin-configuration-context-and-builder/) | [Następny](/pl/adr/024-plugin-lifecycle-and-hosted-services/) + +# [ADR-023] Integracja endpointów i middleware wtyczek poprzez jawne hooki potoku hosta + +*2026-09* | Status: accepted + +**Tag:** #adr_023 + +**Date:** 2026-09-12 + +**Scope:** AuthKit.Plugins.Abstractions + Host + +## Kontekst + +Wtyczki muszą wnosić endpointy i middleware żądań, lecz kolejność middleware ASP.NET Core jest częścią zachowania aplikacji. Kolejność odkrywania, kolejność systemu plików ani kolejność ładowania złożeń nie mogą decydować, gdzie działa kod wtyczki. + +## Problem + +Pierwotny kontrakt eksponował wyłącznie `MiddlewareType`, co dawało jeden niejawny slot middleware i brak hooka rejestracji endpointów. Wtyczki nie mogły jawnie umieszczać middleware względem routingu, uwierzytelniania, autoryzacji ani wykonywania endpointów. + +## Decyzja + +Kontrakt dodaje opcjonalne domyślne hooki: + +- `MapEndpoints(IEndpointRouteBuilder)` dla normalnego routingu endpointów ASP.NET Core; +- `ConfigureApplication(IApplicationBuilder)` dla konfiguracji aplikacji wtyczki; +- `ConfigurePipeline(IApplicationBuilder, PluginPipelinePosition)` dla jawnie pozycjonowanego middleware; +- `PipelinePosition`, używające silnie typowanego wyliczenia `PluginPipelinePosition`. + +Wspierane pozycje to `BeforeRouting`, `AfterRouting`, `BeforeAuthentication`, `AfterAuthentication`, `BeforeAuthorization`, `AfterAuthorization`, `BeforeEndpoints` oraz `AfterEndpoints`. + +Host stosuje hooki do prawdziwego buildera aplikacji i buildera tras endpointów. Wtyczki na tej samej pozycji są porządkowane po stabilnym `Plugin.Id`, niezależnie od kolejności odkrywania. `AfterEndpoints` działa po mapowaniu endpointów REST i gRPC. + +Istniejące zachowanie `MiddlewareType` pozostaje dostępne w swoim pierwotnym slocie. Jeśli wtyczka implementuje `ConfigureApplication` lub `ConfigurePipeline`, host nie rejestruje dodatkowo jej `MiddlewareType`, zapobiegając przypadkowej podwójnej rejestracji middleware. Wyjątki hooków i nieprawidłowe pozycje są zgłaszane jawnie. + +### Uzasadnienie projektowe + +- Hooki endpointów używają normalnego systemu routingu ASP.NET Core, zachowując metadane endpointów, autoryzację, uwierzytelnianie, odkrywanie OpenAPI oraz selekcję endpointów. +- Skończone wyliczenie eksponuje znaczące etapy potoku bez czynienia każdej wewnętrznej implementacji middleware publiczną zależnością. +- Sortowanie po stabilnym ID wtyczki czyni porządek na równych pozycjach deterministycznym i testowalnym. +- Domyślne elementy interfejsu utrzymują zgodność źródłową wtyczek używających wyłącznie `MiddlewareType`. + +## Odrzucone + +- Utrzymywanie porządku middleware równego kolejności odkrywania wtyczek jest niedeterministyczne. +- Dowolne pozycje znakowe są słabo typowane i nie dają się wiarygodnie walidować. +- Równoległy router endpointów omijałby metadane i selekcję endpointów ASP.NET Core. +- Ciche przenoszenie nieprawidłowych pozycji na koniec ukrywałoby błędy konfiguracji wtyczek. + +## Konsekwencje + +Wtyczki mogą uczestniczyć w potoku endpointów i middleware hosta bez modyfikowania kodu startowego hosta. Umiejscowienie w potoku jest jawne i przeglądalne. Autorzy wtyczek muszą wybrać wspierany etap przy użyciu `ConfigurePipeline`; host posiada granice etapów i deterministyczny porządek. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - odkrywanie wtyczek i granica kontraktu +- [ADR-010](/pl/adr/010-plugin-loading-from-directory/) - ładowanie wtyczek i starszy slot middleware +- [Issue #9](https://github.com/AuthKits/AuthKit.Server/issues/9) - wymagania endpointów i potoku aplikacji + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/022-plugin-configuration-context-and-builder/) | [Następny](/pl/adr/024-plugin-lifecycle-and-hosted-services/) diff --git a/Docs/content/pl/adr/024-plugin-lifecycle-and-hosted-services.md b/Docs/content/pl/adr/024-plugin-lifecycle-and-hosted-services.md new file mode 100644 index 0000000..1349080 --- /dev/null +++ b/Docs/content/pl/adr/024-plugin-lifecycle-and-hosted-services.md @@ -0,0 +1,62 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/023-plugin-application-pipeline-hooks/) | [Następny]() + +# [ADR-024] Mostkowanie hooków cyklu życia wtyczek do standardowego cyklu życia hosta .NET + +*2026-09* | Status: accepted + +**Tag:** #adr_024 + +**Date:** 2026-09-12 + +**Scope:** AuthKit.Plugins.Abstractions + Host + +## Kontekst + +Wtyczki mogą musieć inicjalizować zasoby uruchomieniowe, wykonywać pracę po starcie, zwalniać zewnętrzne rejestracje podczas zamykania albo wnosić usługi tła. Statyczna rejestracja usług nie potrafi reprezentować tych operacji bezpiecznie. + +## Problem + +Bez jawnych hooków cyklu życia wtyczki potrzebowałyby kodu startowego specyficznego dla hosta albo własnych harmonogramów usług hostowanych. Ręczne wywoływanie usług tła wtyczek omijałoby też standardowy cykl życia hosta .NET i jego semantykę anulowania. + +## Decyzja + +`IAuthKitPlugin` eksponuje addytywne domyślne elementy: + +- `OnStartingAsync(CancellationToken)`; +- `OnStartedAsync(CancellationToken)`; +- `OnStoppingAsync(CancellationToken)`; +- `GetHostedServices()` zwracające nie-null `IReadOnlyList`. + +Host używa jednego mostka `PluginLifecycleHostedService` rejestrowanego poprzez normalny kontener DI. porządkuje wtyczki po stabilnym `Plugin.Id`: + +- `OnStartingAsync` działa w porządku rosnącym podczas startu usługi hostowanej; +- `OnStartedAsync` działa po `ApplicationStarted` i wyłącznie po udanym starcie; +- `OnStoppingAsync` działa w odwrotnym porządku, gdy zasygnalizowane jest `ApplicationStopping`. + +Dostarczone przez wtyczki usługi hostowane są rejestrowane jako singletonowe instancje `IHostedService` przed startem hosta. Ich metody `StartAsync` i `StopAsync` są więc wywoływane przez standardowego hosta .NET, a nie przez kod AuthKit. Wyniki null, instancje usług null, podwójna rejestracja oraz wyjątki cyklu życia są odrzucane jawnie. Błędy cyklu życia zawierają w rzucanym wyjątku ID wtyczki i etap cyklu życia. + +### Uzasadnienie projektowe + +- Standardowa integracja `IHostedService` zachowuje startowe, zamykające, anulujące i dispose'owe zachowanie frameworka. +- Jeden mostek cyklu życia zapobiega podwójnemu wywoływaniu hooków i unika własnego harmonogramu. +- Porządek po stabilnym ID czyni start i zamykanie deterministycznymi niezależnie od kolejności odkrywania. +- Domyślne elementy interfejsu zachowują zgodność dla wtyczek niepotrzebujących zachowania cyklu życia. + +## Odrzucone + +- Ręczne wywoływanie `StartAsync` i `StopAsync` usług hostowanych stworzyłoby drugą implementację cyklu życia. +- Tworzenie kolejnego dostawcy usług lub zakresu usług rozdzieliłoby zależności wtyczek od kontenera DI aplikacji. +- Ignorowanie wyjątków cyklu życia pozwoliłoby hostowi raportować wtyczkę jako zdrową, gdy inicjalizacja zawiodła. +- Używanie kolejności odkrywania uzależniałoby zachowanie cyklu życia od wyliczania systemu plików lub złożeń. + +## Konsekwencje + +Błędy cyklu życia wtyczek zgłaszane są jawnie poprzez ścieżkę startu/zamykania hosta. Autorzy wtyczek mogą używać hooków świadomych anulowania do inicjalizacji i czyszczenia, podczas gdy praca długotrwała należy do implementacji `IHostedService` zwracanych przez `GetHostedServices()`. Istniejące wtyczki niezwracające usług hostowanych i nieimplementujące hooków pozostają poprawne dzięki bezpiecznym domyślnym. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - odkrywanie wtyczek i granica kontraktu +- [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) - cykl życia infrastruktury hosta +- [Issue #10](https://github.com/AuthKits/AuthKit.Server/issues/10) - wymagania cyklu życia i usług hostowanych + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/023-plugin-application-pipeline-hooks/) | [Następny]() diff --git a/Docs/content/pl/adr/025-plugin-options-openapi-and-marten-integrations.md b/Docs/content/pl/adr/025-plugin-options-openapi-and-marten-integrations.md new file mode 100644 index 0000000..433bf4b --- /dev/null +++ b/Docs/content/pl/adr/025-plugin-options-openapi-and-marten-integrations.md @@ -0,0 +1,48 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/024-plugin-lifecycle-and-hosted-services/) | [Następny](/pl/adr/026-plugin-authentication-and-authorization-hooks/) + +# [ADR-025] Utrzymywanie jawnych integracji opcji, OpenAPI i Marten wtyczek + +*2026-09* | Status: accepted + +**Tag:** #adr_025 + +**Date:** 2026-09-12 + +**Scope:** AuthKit.Plugins.Abstractions + Host + optional plugin integrations + +## Kontekst + +Wtyczki potrzebują silnie typowanych opcji, wkładu do OpenAPI oraz opcjonalnej konfiguracji dokumentów Marten. Te integracje mają różne granice zależności: opcje należą do bazowego kontraktu, podczas gdy Swashbuckle i Marten są zagadnieniami infrastrukturalnymi. + +## Decyzja + +`IAuthKitPlugin.BindConfiguration` wiąże poprzez standardowy system opcji .NET z `Plugins:{Name}`. Wtyczki otrzymują więc normalne usługi `IOptions`, `IOptionsSnapshot` lub `IOptionsMonitor` bez własnego rejestru. + +Kontrakty integracji OpenAPI i Marten żyją w opcjonalnym projekcie `AuthKit.Plugins.Integrations`: + +- `IOpenApiPlugin.ConfigureOpenApi(SwaggerGenOptions)` otrzymuje faktyczne opcje Swagger należące do hosta; +- `IMartenPlugin.ConfigureMarten(StoreOptions)` otrzymuje faktyczne opcje Marten należące do hosta. + +Host wywołuje oba hooki w stabilnym porządku ID wtyczek. Hooki OpenAPI działają wewnątrz istniejącej konfiguracji `AddSwaggerGen`. Hooki Marten działają wewnątrz istniejącej konfiguracji `AddMarten`. Wyjątki mogą przerywać konfigurację hosta; wkłady nigdy nie są cicho odrzucane. + +## Uzasadnienie + +Bazowy kontrakt wtyczki pozostaje niezależny od opcjonalnej infrastruktury trwałości i dokumentacji. Wtyczki potrzebujące którejś integracji referencjonują opcjonalny projekt integracji, podczas gdy zwykłe wtyczki zachowują mniejszą zależność abstrakcji. + +## Odrzucone + +- Dodanie referencji Swashbuckle lub Marten do bazowego projektu abstrakcji zmusiłoby niepowiązane wtyczki do zależenia od opcjonalnej infrastruktury hosta. +- Własny rejestr opcji powieliłby standardowe mechanizmy opcji i DI .NET. +- Tworzenie osobnych instancji opcji Swagger lub Marten odłączyłoby wkłady wtyczek od faktycznej konfiguracji hosta. + +## Konsekwencje + +Konfiguracja wtyczek jest izolowana i silnie typowana. Wkłady OpenAPI i Marten są deterministyczne i dzielą obiekty konfiguracji należące do hosta. Hosty bez Marten nie muszą referencjonować kontraktu integracji ani wywoływać jego hooka. + +## Powiązane + +- [ADR-022](/pl/adr/022-plugin-configuration-context-and-builder/) - kontekst konfiguracji wtyczki +- [ADR-023](/pl/adr/023-plugin-application-pipeline-hooks/) - hooki integracji aplikacji +- [Issue #11](https://github.com/AuthKits/AuthKit.Server/issues/11) - wymagania integracji opcji, OpenAPI i Marten + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/024-plugin-lifecycle-and-hosted-services/) | [Następny](/pl/adr/026-plugin-authentication-and-authorization-hooks/) diff --git a/Docs/content/pl/adr/026-plugin-authentication-and-authorization-hooks.md b/Docs/content/pl/adr/026-plugin-authentication-and-authorization-hooks.md new file mode 100644 index 0000000..4830a8d --- /dev/null +++ b/Docs/content/pl/adr/026-plugin-authentication-and-authorization-hooks.md @@ -0,0 +1,49 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/025-plugin-options-openapi-and-marten-integrations/) | [Następny](/pl/adr/027-devtools-ui-typescript/) + +# [ADR-026] Konfigurowanie uwierzytelniania i autoryzacji wtyczek poprzez infrastrukturę bezpieczeństwa hosta + +*2026-09* | Status: accepted + +**Tag:** #adr_026 + +**Date:** 2026-09-12 + +**Scope:** AuthKit.Plugins.Abstractions + Host security configuration + +## Kontekst + +Wtyczki mogą musieć dodawać schematy uwierzytelniania i polityki autoryzacji. Te rejestracje muszą uczestniczyć w tej samej infrastrukturze bezpieczeństwa ASP.NET Core co host i muszą pozostać kompatybilne z istniejącym JWT, middleware, routingiem endpointów oraz metadanymi schematów bezpieczeństwa. + +## Decyzja + +`IAuthKitPlugin` eksponuje opcjonalne domyślne hooki: + +- `ConfigureAuthentication(AuthenticationBuilder)`; +- `ConfigureAuthorization(AuthorizationOptions)`. + +Host wywołuje hooki w stabilnym porządku ID wtyczek. Przekazuje prawdziwe, należące do hosta buildery/opcje po zarejestrowaniu istniejącego domyślnego Keycloak JWT i przed zbudowaniem aplikacji. Schematy wtyczek nie stają się automatycznie domyślnym schematem uwierzytelniania. Polityki wtyczek są dodawane do tych samych `AuthorizationOptions` używanych przez ASP.NET Core. + +Wyjątki hooków są propagowane. Nazwy schematów i polityk są globalnie znaczące; wtyczki powinny używać nazw z przestrzenią nazw, takich jak `plugin.read`. Host nie zmienia cicho nazw, nie zastępuje ani nie mapuje konfiguracji bezpieczeństwa. Zachowanie nowego transportu uwierzytelniania oraz deskryptora bezpieczeństwa OpenAPI pozostaje rządzone istniejącym kontraktem schematu bezpieczeństwa. + +## Uzasadnienie + +Używanie faktycznych builderów ASP.NET Core zachowuje standardową selekcję schematów, dostawców polityk, wyzwania uwierzytelniania, metadane autoryzacji endpointów oraz zachowanie middleware. Domyślne implementacje interfejsu utrzymują zgodność źródłową istniejących wtyczek. + +## Odrzucone + +- Osobny dostawca usług uwierzytelniania wtyczki odłączyłby schematy od hosta. +- Automatyczne czynienie schematów wtyczek domyślnymi mogłoby zmienić istniejące zachowanie hosta. +- Równoległy rejestr polityk omijałby `IAuthorizationPolicyProvider`. +- Przepisywanie deskryptorów schematów bezpieczeństwa na rejestracje uwierzytelniania myliłoby metadane dokumentacji z uruchomieniową konfiguracją bezpieczeństwa. + +## Konsekwencje + +Schematy i polityki wtyczek mogą chronić endpointy wtyczek poprzez normalne API ASP.NET Core. Kolidujące globalne nazwy pozostają błędami konfiguracji rządzonymi ścieżką konfiguracji hosta/frameworka i należy ich unikać poprzez przestrzenie nazw wtyczek. Istniejące zachowanie uwierzytelniania i autoryzacji JWT pozostaje domyślne, dopóki wtyczka jawnie nie wniesie dodatkowej konfiguracji. + +## Powiązane + +- [ADR-018](/pl/adr/018-security-scheme-contract-explicit-handling/) - metadane schematu bezpieczeństwa i mapowanie OpenAPI +- [ADR-023](/pl/adr/023-plugin-application-pipeline-hooks/) - endpointy wtyczek i potok middleware +- [Issue #12](https://github.com/AuthKits/AuthKit.Server/issues/12) - hooki uwierzytelniania i autoryzacji + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/025-plugin-options-openapi-and-marten-integrations/) | [Następny](/pl/adr/027-devtools-ui-typescript/) diff --git a/Docs/content/pl/adr/027-devtools-ui-typescript.md b/Docs/content/pl/adr/027-devtools-ui-typescript.md new file mode 100644 index 0000000..c4d4f47 --- /dev/null +++ b/Docs/content/pl/adr/027-devtools-ui-typescript.md @@ -0,0 +1,39 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/026-plugin-authentication-and-authorization-hooks/) | [Następny](/pl/adr/028-plugin-contract-and-dynamic-loading-architecture/) + +# [ADR-027] Kompiluj interfejs DevTools z modularnego TypeScript do pojedynczego zasobu osadzonego + +*2026-09* | Status: accepted + +**Tag:** #adr_027 + +**Date:** 2026-09-16 + +**Scope:** Plugins.Solutions.DevTools + +## Kontekst + +Wtyczka DevTools dostarcza webowe UI (Svelte 5 z Tailwindem) do eksploracji serwisów gRPC i wywoływania metod. Deploy takiego UI jako luźnych plików statycznych rozbiłby każde wydanie na dwa artefakty, które mogą się rozjechać: serwer i interfejs do jego inspekcji. + +## Problem + +Modularna aplikacja TypeScript nie deployuje się sama jako jeden plik. Bez kroku bundlowania UI wymagałoby historii hostingu plików statycznych (ścieżki, cache, dopasowanie wersji) na wierzchu assembly wtyczki, które i tak niesie wszystko inne. + +## Decyzja + +UI buduje się przez `vite build`, zwija do jednego samowystarczalnego pliku HTML przez `vite-plugin-singlefile` i jest finalizowane do osadzenia przez `scripts/finalize-ui.mjs`. Bezpieczeństwo typów jest egzekwowane z góry przez `svelte-check`. Wynikowy zasób podróżuje wewnątrz assembly wtyczki: jedno assembly, jedno UI, zawsze zgodne z backendem, z którym płynie. + +## Odrzucone + +- Serwowanie UI jako luźnych plików statycznych obok assembly wtyczki. +- Wersjonowanie UI niezależnie od inspekcjonowanego serwera. + +## Konsekwencje + +Deploy AuthKit nigdy nie wymaga osobnego kroku plików statycznych, a wersja UI nie może rozjechać się z inspekcjonowanym serwerem. Kosztem jest sprzężenie build-time: zmiany UI wymagają przebudowania assembly wtyczki. + +## Powiązane + +- [ADR-020](/pl/adr/020-devtools-plugin/) - wtyczka DevTools hostująca UI +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - odkrywanie wtyczek ładujące assembly + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/026-plugin-authentication-and-authorization-hooks/) | [Następny](/pl/adr/028-plugin-contract-and-dynamic-loading-architecture/) diff --git a/Docs/content/pl/adr/028-plugin-contract-and-dynamic-loading-architecture.md b/Docs/content/pl/adr/028-plugin-contract-and-dynamic-loading-architecture.md new file mode 100644 index 0000000..7c7d28e --- /dev/null +++ b/Docs/content/pl/adr/028-plugin-contract-and-dynamic-loading-architecture.md @@ -0,0 +1,190 @@ +# [ADR-028] Kontrakt wtyczek i architektura dynamicznego ładowania + +## Kontekst + +Projekt `AuthKit.Host` wymaga dynamicznego odkrywania i ładowania wtyczek podczas startu, zanim kontener DI i infrastruktura (Wolverine, Marten) zostaną w pełni skonfigurowane. Istniejący interfejs `IAuthKitPlugin` eksponował jedynie `Name`, `Version` (jako ciąg znaków) oraz `Description`, co było niewystarczające do właściwego zarządzania cyklem życia wtyczek, sprawdzania zgodności i rozwiązywania zależności. + +Sygnatura metody `PluginLoader.LoadPlugins()` zmieniła się z 2 na 3 wymagane parametry (`pluginsRootPath, ILogger logger, SemanticVersion hostVersion`), powodując błąd kompilacji, który trzeba było naprawić poprzez wyodrębnienie wersji hosta z metadanych złożenia. + +## Problem + +1. **Błąd kompilacji**: wywołanie `PluginLoader.LoadPlugins(pluginsPath, pluginLogger)` z 2 argumentami, podczas gdy metoda wymaga 3 wymaganych parametrów +2. **Brak świadomości wersji hosta**: wtyczki nie mogły być odrzucane na podstawie wymagań minimalnej wersji hosta (bramka `MinHostVersion` G3) +3. **Brak wsparcia manifestów**: brak walidacji metadanych wtyczki przed aktywacją (tagi, zależności, status włączenia, kontrole spójności) +4. **Brak stabilnej identyfikacji wtyczek**: brak unikalnego pola `Id` do deduplikacji, rozwiązywania zależności i unikalności w hoście +5. **Brak klasyfikacji możliwości**: brak zbioru `Capabilities` do kontroli hosta przed aktywacją + +## Decyzja + +### A1. Identyfikator wtyczki (`IAuthKitPlugin.Id`) +- Dodano `string Id { get; }` do interfejsu `IAuthKitPlugin` +- Autorzy wtyczek deklarują stabilne identyfikatory (np. `authkit.devtokens`) +- Host weryfikuje format i unikalność przed aktywacją +- **Odrzucono**: używanie `Guid` jako `Id` (słaba czytelność w manifestach, logach, CLI i konfiguracji) + +### A2. Wersja o silnym typowaniu (`IAuthKitPlugin.Version`) +- Zastąpiono `string Version` przez `SemanticVersion Version` +- Parsowanie, równość i porównywanie SemVer 2.0.0 z poprawnym pierwszeństwem +- Metadane kompilacji ignorowane dla pierwszeństwa (`1.0.0+abc == 1.0.0+xyz`) +- **Zmiana przełomowa**: istniejące implementacje `string Version => "1.2.3"` muszą zostać zmigrowane do `SemanticVersion Version` + +### A3-A8. Opisowa powierzchnia metadanych +- `string? Author`, `string? License`, `string? LicenseUrl`, `string? Homepage`, `string? RepositoryUrl` +- `IReadOnlyList Tags` dowolna klasyfikacja, elementy null/zawierające tylko białe znaki są nieprawidłowe. Domyślnie `Array.Empty`. +- `int Priority` niższa wartość = wcześniejsza aktywacja wśród wtyczek w innych aspektach niezależnych. Zależności zawsze mają pierwszeństwo przed `Priority`. Domyślnie `0`. +- `bool IsEnabled` domyślnie `true`. Gdy `IsEnabled` pochodzi z manifestu, wyłączone wtyczki są pomijane przed aktywacją złożenia. +- `string? DisplayName` UI pokazuje regułę rezerwową `DisplayName ?? Name`. Domyślnie `null`. +- `IReadOnlyList DependsOn` deklaruje wartości `Id` wtyczek (nigdy nazw wyświetlanych). Domyślnie `Array.Empty`. + +### A9. MinHostVersion +- **Odroczone**: `MinHostVersion` nie jest częścią bieżącego kontraktu wtyczki, ale jest planowane w przyszłej implementacji. +- **Uwaga**: kontrole zgodności hosta (G3) nie są obecnie egzekwowane. Funkcja zostanie przywrócona, gdy `MinHostVersion` zostanie dodane do kontraktu w przyszłej iteracji. + +### A10. DependsOn +- `IReadOnlyList DependsOn` deklaruje wartości `Id` wtyczek (nigdy nazw wyświetlanych) +- **Wykrywanie cykli**: cykle w zależnościach są wykrywane algorytmem **przeszukiwania w głąb (DFS)** ze zbiorem `visiting` śledzącym bieżącą ścieżkę przechodzenia. W przypadku wykrycia cyklu wszystkie wtyczki zaangażowane w cykl są odrzucane jako błąd startu. +- **Rozstrzyganie priorytetów**: pole `Priority` (A3-A8) rozstrzyga remisy **wyłącznie w ramach poprawnego porządku topologicznego** i nie przesłania krawędzi zależności (`DependsOn`). +- G7 weryfikuje: brakujące → błąd startu, własne → odrzucenie, duplikat → odrzucenie, cykl → błąd startu + +### A11. Capabilities +- `IReadOnlySet Capabilities` równość zbiorów porządkowa bez uwzględniania wielkości liter. Domyślnie niemodyfikowalny pusty zbiór. +- Używane do kontroli możliwości hosta przed aktywacją oraz walidacji kontraktu w czasie działania. + +### A12. PluginMetadata +- Niemutowalna migawka uruchomieniowa poprzez `PluginMetadataExtensions.GetMetadata()` +- Agreguje metadane kontraktu wtyczki w pojedynczą niemutowalną migawkę uruchomieniową +- Kontrola spójności między manifestem a instancją uruchomieniową niezgodność → odrzucenie +- **Uwaga**: walidacja spójności koncentruje się na metadanych niezwiązanych z wersją (np. `Tags`, `DependsOn`, `Capabilities`). + +### A13. DisplayName +- `string? DisplayName` dostarcza czytelną dla człowieka nazwę wtyczki dla UI i diagnostyki. +- Gdy nie podano, rezerwowo używane jest `Name`. + +### B. Projekcja manifestu wtyczki przed aktywacją +- `PluginManifest` odzwierciedla wybrane elementy uruchomieniowe `IAuthKitPlugin` do użycia przed aktywacją (G2) +- Wyszukiwane w katalogach wtyczek: `plugin.manifest.json`, `manifest.json`, `{pluginName}.manifest.json` +- **Przyszły kierunek manifestów**: choć manifesty są obecnie opcjonalne dla zgodności wstecznej, długoterminowym celem jest egzekwowanie obowiązkowych manifestów dla pełnej walidacji spójności (G2). Wtyczki bez manifestów ładują się bez walidacji, co może prowadzić do nieoczekiwanego zachowania w przyszłych wydaniach. +- Jeśli nie znaleziono manifestu: `manifest` to `null`, wtyczka ładuje się bez walidacji spójności (ścieżka rezerwowa) +- Jeśli znaleziono manifest: weryfikowane tagi, depends-on, IsEnabled, kontrola duplikatów Id +- Kontrola spójności między manifestem a instancją uruchomieniową po załadowaniu. + +### C. Walidacja i ładowanie + +#### Walidacja przed aktywacją (gdy manifest istnieje) +1. **Odkrywanie wtyczek**: skanowanie `pluginsRootPath` w poszukiwaniu podkatalogów +2. **Kontrola wejściowego złożenia**: każdy katalog musi zawierać `{pluginName}.dll` +3. **Parsowanie manifestu**: próba `plugin.manifest.json` → `manifest.json` → `{pluginName}.manifest.json` + +**Uwaga**: host wywodzi swój `SemanticVersion` z metadanych złożenia i przekazuje go jawnie do `PluginLoader`. Wartość ta jest obecnie informacyjna i nie jest używana do walidacji zgodności wtyczek. Bramkowanie zgodności poprzez `MinHostVersion` jest odroczone. + +5. **Walidacja przed aktywacją** (gdy manifest istnieje): + - Walidacja składni i struktury manifestu + - Walidacja `Tags` + - Walidacja `DependsOn` (brakujące, własne, duplikaty, cykl) + - Walidacja `IsEnabled` + - Walidacja duplikatów `Id` + - Wyłączone wtyczki (`IsEnabled = false`) są pomijane przed aktywacją złożenia. + +6. **Ładowanie złożeń**: `AssemblyLoadContext.Default.LoadFromAssemblyPath()` z resolverem zależności + +#### Walidacja uruchomieniowa (po załadowaniu złożenia) +7. **Tworzenie instancji wtyczki**: `Activator.CreateInstance(pluginType)` → `IAuthKitPlugin` +8. **Kontrola duplikatów `Id` w czasie ładowania** +9. **Walidacja spójności** między manifestem a instancją uruchomieniową (jeśli manifest istnieje) + - Weryfikuje metadane niezwiązane z wersją (np. `Tags`, `DependsOn`, `Capabilities`). +10. **Utworzenie `PluginMetadata`** jako niemutowalnej migawki kontraktu uruchomieniowego +11. **Aktywacja wtyczki** + +**Uwagi:** +- `MinHostVersion` jest planowane w przyszłej implementacji w celu egzekwowania zgodności wersji hosta (G3). +- Walidacja spójności manifestu koncentruje się na metadanych niezwiązanych z wersją, w tym `Tags`, `DependsOn` i `Capabilities`. +- Manifesty pozostają opcjonalne dla zgodności wstecznej; wtyczki bez manifestów podążają rezerwową ścieżką ładowania bez walidacji spójności. + +### Tagi +#PluginContract #DynamicLoading #G2 #G7 + +### Data +2026-09-04 + +### Zakres +Plugins + +### Poprzedni +ADR-027: Kompiluj interfejs DevTools z modularnego TypeScript do pojedynczego zasobu osadzonego + +### Następny +ADR-029: Eksponowanie ustrukturyzowanych i anulowalnych wyników kondycji wtyczek + +## Konsekwencje + +### Pozytywne +- Wtyczki mogą być referencjonowane poprzez stabilny unikalny identyfikator (`Id`) +- Metadane wtyczki mogą być walidowane przed aktywacją, gdy manifest jest dostępny +- Wyłączone wtyczki mogą być pomijane przed aktywacją złożenia, gdy zadeklaruje to manifest +- Metadane kontraktu wtyczki są dostępne jako niemutowalna migawka `PluginMetadata` +- Deklaracje zależności mogą być walidowane i rozwiązywane deterministycznie +- Niespójności manifestu/czasu działania mogą być wykrywane przed aktywacją +- Metadane wtyczki są dostępne przed konfiguracją kontenera DI +- Nowi kontrybutorzy mogą zrozumieć kontrakt wtyczki i decyzje dotyczące ładowania + +### Negatywne +- Zmiana `Version` z `string` na `SemanticVersion` jest przełomowa (wymaga migracji) +- Wtyczki bez manifestu nadal ładują się bez walidacji spójności manifestu/czasu działania +- Zgodność wersji hosta (`MinHostVersion`) jest planowana w przyszłej implementacji +- Egzekwowanie manifestów jest odroczone do przyszłej iteracji +- Autorzy wtyczek muszą wykonywać więcej walidacji w czasie kompilacji i kontraktu + +### Diagram konsekwencji + +```mermaid +flowchart TD + A["Plugin directory
plugin.json / manifest"] --> B["IPluginDiscoverer"] + B --> C["DiscoveredPlugin
Manifest + Location"] + C --> D{"Pre-activation Gate"} + D -->|Disabled| X["SKIP"] + D -->|Invalid manifest| Y["REJECT"] + D -->|Duplicate Id| Y + D -->|Accepted| E["IPluginLoader"] + E --> F["AssemblyLoadContext.Default
+ dependency resolver"] + F --> G["LoadedPlugin
Manifest + Instance"] + G --> H["Plugin Contract
Validation"] + G -->|No manifest| L["ACTIVATION"] + H --> I["Manifest ↔ Runtime
Consistency Check"] + I --> J["PluginMetadata
Immutable Runtime Snapshot"] + J --> K["Dependency Resolution
+ Ordering"] + K --> L + I -.->|Mismatch| Y + H -.->|Invalid contract| Y + K -.->|Missing / self / duplicate / cycle| Y + + subgraph Discovery["DISCOVERY"] + B + C + end + + subgraph Validation["VALIDATION"] + D + H + I + K + end + + subgraph Loading["LOADING"] + E + F + G + end + + subgraph Runtime["RUNTIME"] + J + L + end +``` + +**Wyjaśnienie diagramu**: +- **Odkrywanie**: `IPluginDiscoverer` skanuje katalogi wtyczek i parsuje manifesty. +- **Bramka przed aktywacją**: weryfikuje składnię manifestu, `Tags`, `DependsOn`, `IsEnabled` oraz duplikaty `Id`. +- **Ładowanie**: ładuje złożenia i tworzy instancje `IAuthKitPlugin`. +- **Walidacja**: zapewnia spójność kontraktu między manifestem a instancją uruchomieniową. +- **Rozwiązywanie zależności**: weryfikuje i porządkuje wtyczki na podstawie `DependsOn` i `Priority`. +- **Aktywacja**: ostatni krok po pomyślnej walidacji i rozwiązaniu. diff --git a/Docs/content/pl/adr/029-structured-plugin-health-contract.md b/Docs/content/pl/adr/029-structured-plugin-health-contract.md new file mode 100644 index 0000000..a030dc2 --- /dev/null +++ b/Docs/content/pl/adr/029-structured-plugin-health-contract.md @@ -0,0 +1,74 @@ +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/028-plugin-contract-and-dynamic-loading-architecture/) | [Następny]() + +# [ADR-029] Eksponowanie ustrukturyzowanych i anulowalnych wyników kondycji wtyczek + +*2026-09* | Status: accepted + +**Tag:** #adr_025 + +**Date:** 2026-09-13 + +**Scope:** AuthKit.Plugins.Abstractions + Host + +## Kontekst + +Wtyczki mogą zależeć od kilku niezależnych komponentów, takich jak baza danych, cache, +zewnętrzne API albo kolejka komunikatów. Pojedyncza boolowska wartość kondycji nie zachowuje +informacji, który komponent jest zdegradowany ani dlaczego kontrola zawiodła. Kontrole kondycji mogą też wykonywać +asynchroniczne I/O i muszą zatrzymywać się, gdy żądanie lub host jest anulowany. + +## Problem + +Pierwotny kontrakt wtyczki zwracał `Task CheckHealthAsync(IServiceProvider)`. +Ten kształt traci pośrednie stany kondycji, informacje diagnostyczne, wielokrotne +obserwacje oraz anulowanie. Zastąpienie go bez ścieżki migracji +złamałoby istniejące implementacje wtyczek. + +## Decyzja + +`IAuthKitPlugin.CheckHealthAsync` zwraca: + +```csharp +Task> CheckHealthAsync( + IServiceProvider services, + CancellationToken cancellationToken = default) +``` + +`PluginHealthResult` zawiera silnie typowany `PluginHealthStatus`, opcjonalny +powód oraz opcjonalne dane diagnostyczne należące do wtyczki. `Healthy`, `Degraded` i +`Unhealthy` pozostają odrębne. Wtyczka może zwrócić jeden wynik albo wiele wyników, +przy czym każdy wynik reprezentuje niezależną obserwację. + +Domyślna implementacja interfejsu zwraca jeden wynik `Healthy`, więc wtyczki, które +nie dostarczają własnej kontroli, pozostają poprawne. Host zachowuje listę wyników i +używa dostarczonego tokenu anulowania żądania. Anulowanie jest propagowane, a nie +zamieniane na spreparowany wynik kondycji. + +## Odrzucone + +- Zachowanie `bool` odrzuciłoby stan zdegradowany i diagnostykę. +- Zwinięcie wielu wyników wewnątrz wtyczki uczyniłoby agregację hosta stratną. +- Wnioskowanie statusu z `Reason` lub `Data` uczyniłoby kontrakt słabo typowanym. +- Ciche zastępowanie anulowania przez `Healthy` lub `Unhealthy` ukryłoby + niekompletną kontrolę. +- Dodanie drugiej metody kondycji pozostawiłoby dwa konkurujące publiczne kontrakty. + +## Konsekwencje + +Konsumenci kondycji muszą obsługiwać listę ustrukturyzowanych wyników i definiować agregację +jawnie. Endpoint kondycji hosta raportuje najwyższy status istotności, zachowując +każdy wynik wtyczki w odpowiedzi. Klucze diagnostyczne specyficzne dla wtyczki +pozostają rozszerzalne, lecz nie nadpisują `Status`. + +Zmiana jest łamiąca źródłowo dla wtyczek implementujących starą metodę `Task`; +dostarczone wtyczki i przykładowy manifest są migrowane razem. Walidator +kontraktu wywołuje nową metodę i odrzuca pustą kolekcję wyników. + +## Powiązane + +- [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) - kontrakt wtyczki i dynamiczne ładowanie +- [ADR-024](/pl/adr/024-plugin-lifecycle-and-hosted-services/) - integracja cyklu życia wtyczki +- [Issue #14](https://github.com/AuthKits/AuthKit.Server/issues/14) - ustrukturyzowany wynik kondycji wtyczki +- [Issue #15](https://github.com/AuthKits/AuthKit.Server/issues/15) - wiele wyników i anulowanie + +[/pl/](/pl/) | [Indeks kategorii](/pl/adr/) | [Poprzedni](/pl/adr/028-plugin-contract-and-dynamic-loading-architecture/) | [Następny]() diff --git a/Docs/content/pl/adr/README.md b/Docs/content/pl/adr/README.md new file mode 100644 index 0000000..faa40c6 --- /dev/null +++ b/Docs/content/pl/adr/README.md @@ -0,0 +1,109 @@ +# Rejestr Decyzji Architektonicznych + +Ten katalog przechowuje decyzje architektoniczne AuthKit.Server w formie ADR. Nie jest to dziennik zmian ani przepisana historia commitów. Jest to wyselekcjonowany zbiór decyzji technicznych, który wyjaśnia, dlaczego system ma obecny kształt oraz jakie ograniczenia nakłada to na przyszłe prace. + +Rekordy ADR są pogrupowane według obszarów architektury. Numeracja jest globalna, więc identyfikator decyzji nie zależy od pliku, w którym się znajduje. Przeniesienie pliku do innego obszaru nie zmienia jego numeru, a numer należy traktować jako stabilny identyfikator decyzji. + +## Jak czytać ten zbiór + +Zacznij od obszaru odpowiadającego temu, co zmieniasz: + +- jeśli zmiana dotyczy zarządzania kluczami, powiązań kluczy tokenów lub kontraktów podstawowej domeny, przeczytaj poniższe decyzje `AuthKit.Core` +- jeśli dotyczy powierzchni REST lub gRPC, CLI, konfiguracji albo sposobu składania i hostowania serwera, zobacz decyzje Host +- jeśli dotyczy systemu wtyczek, rozwiązań lub abstrakcji wtyczek, zobacz decyzje Plugins + +Każdy ADR zawiera: + +- `Context`: + warstwę i architektoniczne umiejscowienie decyzji +- `Problem`: + konkretne napięcie techniczne, które decyzja rozwiązuje +- `Decision`: + wybrany kierunek i granicę odpowiedzialności +- `Rejected`: + realistyczne alternatywy, które celowo nie zostały wybrane +- `Consequences`: + wpływ na utrzymanie, ograniczenia, efekty uboczne oraz praktyczne konsekwencje dla przyszłego kodu + +## Jak używać ADR-ów podczas zmian + +ADR-y nie zastępują czytania kodu, ale obniżają koszt zrozumienia decyzji, które zostały już podjęte. Gdy zmieniasz dany obszar: + +1. znajdź pasujący obszar +2. przeczytaj 2–4 najbliższe ADR-y, nie tylko jeden +3. sprawdź, czy nowa zmiana rozszerza bieżący model, czy faktycznie go łamie +4. jeśli decyzja nie jest już prawdziwa, dodaj nowy ADR zamiast po cichu odchodzić od bieżącego kierunku + +Ten zbiór ma zachować spójność pomiędzy Core, Host i Plugins. W AuthKit.Server znaczna część kosztu zmian wynika z kontraktów pomiędzy warstwami, a nie z pojedynczej klasy. + +## Mapa kategorii + +Poniższa tabela przedstawia obszary architektury i ich bieżący zakres. + +| Area | Scope | +| --- | --- | +| Core | Współdzielony model domeny: zarządzanie kluczami podpisującymi, powiązania kluczy tokenów, kontrakty błędów oraz interfejsy Core. | +| Host | Kompozycja aplikacji i powierzchnia zewnętrzna: REST, gRPC, CLI, konfiguracja oraz hosting materiału kluczy. | +| Plugins | System wtyczek: rozwiązania, abstrakcje wtyczek oraz granice rozszerzeń. | + +## Bieżące ADR-y + +| ID | Title | Area | Status | Date | +|----|-------|------|--------|------| +| [ADR-001](/pl/adr/001-centralize-signing-key-management/) | Scentralizuj zarządzanie kluczami podpisującymi poprzez abstrakcję głównego magazynu kluczy w Core | Core | accepted | 2026-08-26 | +| [ADR-002](/pl/adr/002-encrypt-keystore-at-rest/) | Szyfruj utrwalony materiał magazynu kluczy w spoczynku poprzez wymienialny szyfrator | Core | accepted | 2026-08-26 | +| [ADR-003](/pl/adr/003-signing-key-lifecycle-immutable-transitions/) | Modeluj cykl życia klucza podpisującego jako niezmienne przejścia stanu | Core | accepted | 2026-08-26 | +| [ADR-004](/pl/adr/004-token-key-bindings-domain/) | Traktuj powiązania tokenów deweloperskich z kluczami podpisującymi jako domenę Core | Core | accepted | 2026-08-26 | +| [ADR-005](/pl/adr/005-public-keys-via-jwks/) | Publikuj klucze publiczne poprzez JWKS, ujawniając wyłącznie klucze nieunieważnione | Core | accepted | 2026-08-26 | +| [ADR-006](/pl/adr/006-kid-as-generated-guid/) | Wyznaczaj identyfikator klucza JWT jako generowany GUID | Core | accepted | 2026-08-26 | +| [ADR-007](/pl/adr/007-default-signing-algorithm-rsa-4096/) | Domyślnym algorytmem podpisywania jest RSA-4096 z RS256 | Core | accepted | 2026-08-26 | +| [ADR-008](/pl/adr/008-standardized-error-response/) | Standaryzuj błędy API poprzez kontrakt odpowiedzi na błąd w Core | Core | accepted | 2026-08-26 | +| [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) | Odkrywaj i ładuj wtyczki dynamicznie poprzez kontrakt IAuthKitPlugin | Plugins | accepted | 2026-08-26 | +| [ADR-010](/pl/adr/010-plugin-loading-from-directory/) | Ładuj wtyczki z konfigurowalnego katalogu podczas startu | Host | accepted | 2026-08-26 | +| [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/) | Utrwalaj zaszyfrowany magazyn kluczy jako dokument singleton w Marten | Host | accepted | 2026-08-26 | +| [ADR-012](/pl/adr/012-token-key-bindings-persisted-in-marten/) | Utrwalaj powiązania kluczy tokenów w Marten | Host | accepted | 2026-08-26 | +| [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/) | Udostępniaj powierzchnie transportowe REST i gRPC | Host | accepted | 2026-08-26 | +| [ADR-014](/pl/adr/014-error-responses-via-middleware/) | Renderuj błędy HTTP jako szczegóły problemu RFC 7807 poprzez oprogramowanie pośredniczące | Host | accepted | 2026-08-26 | +| [ADR-015](/pl/adr/015-keycloak-external-jwt-authority/) | Używaj Keycloak jako zewnętrznego urzędu JWT | Host | accepted | 2026-08-26 | +| [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/) | Używaj Marten i Wolverine jako infrastruktury hosta | Host | accepted | 2026-08-26 | +| [ADR-017](/pl/adr/017-api-key-credential-extraction-strategies/) | Zdefiniuj strategie ekstrakcji poświadczeń klucza API | Host | accepted | 2026-09-11 | +| [ADR-018](/pl/adr/018-security-scheme-contract-explicit-handling/) | Obsługuj wartości kontraktu schematu bezpieczeństwa wprost | Plugins | accepted | 2026-09-11 | +| [ADR-019](/pl/adr/019-plugin-metadata-attribute/) | Deklaruj tożsamość wtyczki poprzez atrybut PluginMetadata | Plugins | accepted | 2026-09-11 | +| [ADR-020](/pl/adr/020-devtools-plugin/) | Hostuj narzędzia deweloperskie poprzez dedykowaną wtyczkę DevTools | Plugins | accepted | 2026-09-11 | +| [ADR-021](/pl/adr/021-swagger-serving-via-reflection/) | Serwuj Swagger poprzez oparty na refleksji SwaggerHost w DevTools | Plugins | accepted | 2026-09-11 | +| [ADR-022](/pl/adr/022-plugin-configuration-context-and-builder/) | Rozszerz konfigurację wtyczek o builder hosta i zakresowy kontekst | Plugins | accepted | 2026-09-12 | +| [ADR-023](/pl/adr/023-plugin-application-pipeline-hooks/) | Integruj punkty końcowe i oprogramowanie pośredniczące wtyczek poprzez jawne haki potoku hosta | Plugins | accepted | 2026-09-12 | +| [ADR-024](/pl/adr/024-plugin-lifecycle-and-hosted-services/) | Połącz haki cyklu życia wtyczek ze standardowym cyklem życia hosta .NET | Plugins | accepted | 2026-09-12 | +| [ADR-025](/pl/adr/025-plugin-options-openapi-and-marten-integrations/) | Utrzymuj integracje opcji wtyczek, OpenAPI i Marten wprost | Plugins | accepted | 2026-09-12 | +| [ADR-026](/pl/adr/026-plugin-authentication-and-authorization-hooks/) | Konfiguruj uwierzytelnianie i autoryzację wtyczek poprzez infrastrukturę bezpieczeństwa hosta | Plugins | accepted | 2026-09-12 | +| [ADR-027](/pl/adr/027-devtools-ui-typescript/) | Kompiluj interfejs DevTools z modularnego TypeScript do pojedynczego zasobu osadzonego | Plugins | accepted | 2026-09-16 | +| [ADR-028](/pl/adr/028-plugin-contract-and-dynamic-loading-architecture/) | Zdefiniuj kontrakt wtyczek i architekturę dynamicznego ładowania | Plugins | accepted | 2026-09-11 | +| [ADR-029](/pl/adr/029-structured-plugin-health-contract/) | Eksponowanie ustrukturyzowanych i anulowalnych wyników kondycji wtyczek | Plugins | accepted | 2026-09-13 | + +## Relacje pomiędzy obszarami + +Najczęstszy przepływ architektoniczny w AuthKit.Server wygląda tak: + +`Core -> Host -> Plugins` + +Nie jest to ścisły diagram zależności projektu, ale użyteczna mapa do czytania decyzji. W praktyce: + +- `Core` definiuje, co system uznaje za dane domenowe oraz kontrakty kryptograficzne (klucze, powiązania, błędy) +- `Host` definiuje, jak ta domena jest udostępniana i składana w działający serwer (powierzchnie API, CLI, konfiguracja) +- `Plugins` rozszerzają zachowanie na bazie stabilnych kontraktów Core i Host + +## Kiedy dodać nowy ADR + +Nowy ADR warto dodać, gdy zmiana: + +- przesuwa granice odpowiedzialności pomiędzy warstwami +- wprowadza nowy kontrakt danych lub nowy trwały artefakt +- zmienia model wykonywania zarządzania kluczami, hostingu lub ładowania wtyczek +- dodaje nowe zachowanie dostawcy lub wtyczki, które nie mieści się już w bieżącym modelu +- zastępuje wcześniejszą decyzję innym świadomym kompromisem + +ADR-u zwykle nie warto dodawać dla: + +- zwykłego refaktoryzowania bez architektonicznej zmiany kierunku +- kosmetycznej lokalnej zmiany API ograniczonej do jednego pliku lub klasy +- zmiany wyłącznie dokumentacyjnej lub testowej, która nie zmienia kontraktów systemu From 28c77cf95be0204b31937b5bf51581388161d1a3 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:29:25 +0200 Subject: [PATCH 03/17] docs: add English and Polish infrastructure guides --- Docs/content/en/infrastructure/docker.md | 121 ++++++++++++++++++++ Docs/content/en/infrastructure/keycloak.md | 59 ++++++++++ Docs/content/en/infrastructure/marten.md | 98 ++++++++++++++++ Docs/content/en/infrastructure/wolverine.md | 57 +++++++++ Docs/content/pl/infrastructure/docker.md | 121 ++++++++++++++++++++ Docs/content/pl/infrastructure/keycloak.md | 59 ++++++++++ Docs/content/pl/infrastructure/marten.md | 98 ++++++++++++++++ Docs/content/pl/infrastructure/wolverine.md | 57 +++++++++ 8 files changed, 670 insertions(+) create mode 100644 Docs/content/en/infrastructure/docker.md create mode 100644 Docs/content/en/infrastructure/keycloak.md create mode 100644 Docs/content/en/infrastructure/marten.md create mode 100644 Docs/content/en/infrastructure/wolverine.md create mode 100644 Docs/content/pl/infrastructure/docker.md create mode 100644 Docs/content/pl/infrastructure/keycloak.md create mode 100644 Docs/content/pl/infrastructure/marten.md create mode 100644 Docs/content/pl/infrastructure/wolverine.md diff --git a/Docs/content/en/infrastructure/docker.md b/Docs/content/en/infrastructure/docker.md new file mode 100644 index 0000000..d299b1e --- /dev/null +++ b/Docs/content/en/infrastructure/docker.md @@ -0,0 +1,121 @@ +# Docker + Kestrel + +The whole stack runs from one compose file: AuthKit, PostgreSQL, and Keycloak. This page walks the full lifecycle first run, daily use, debugging, and what changes on the way to production. + +## Prerequisites + +- [Docker](https://docs.docker.com/get-docker/) with Compose v2. +- Ports `5000`, `5001`, `8081`, `5433`, `5434` free on your machine. +- A dev HTTPS certificate in `./certs` (see [Certificates](#certificates)). + +## First Run + +```bash +cp .env.example .env +docker compose up --build +``` + +What happens, in order: + +1. Images build (`auth` from the root `Dockerfile`, `keycloak` from `Deploy/Keycloak/Dockerfile`) databases pull `postgres:15`. +2. Named volumes `AuthDev-data` and `Auth-data` are created your data survives container restarts. +3. `authdev-db` must report `healthy` (`pg_isready`) before `auth` even starts. +4. `auth` runs storage migration, maps REST + gRPC endpoints, and starts listening. + +Verify with the health endpoint: + +```bash +curl -k https://localhost:5000/health +``` + +## Services + +| Service | Image / Build | Ports | Purpose | +|---------|---------------|-------|---------| +| `auth` | `Dockerfile` (repo root) | `5000` REST, `5001` gRPC | AuthKit host (HTTPS) | +| `authdev-db` | `postgres:15` | `5434` → `5432` | AuthKit database (`AuthDev-data` volume) | +| `keycloak` | `Deploy/Keycloak/Dockerfile` | `8081` → `8080` | Identity provider, realm auto-imported | +| `keycloak-db` | `postgres:15` | `5433` → `5432` | Keycloak database (`Auth-data` volume) | + +`auth` mounts `./certs` for the dev HTTPS certificate and reads `.env` plus `ConnectionStrings__DefaultConnection` pointing at `authdev-db`. Everything talks over the `db_net` bridge network services reach each other by name (`authdev-db`, `keycloak-db`). + +## Keycloak Profile + +`keycloak` and `keycloak-db` sit behind the `keycloak` compose profile: the base `up` starts AuthKit with its own database, while `docker compose --profile keycloak up` adds the identity stack. The realm file is mounted readonly and imported on boot (`--import-realm`) bootstrap admin is `admin` / `admin`. + +After the first start, open http://localhost:8081 and confirm the `authz` realm exists. Client credentials come from `.env` (`KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET`). + +## Environment + +Copy of what `.env.example` declares set these before the first `up`: + +| Variable | Meaning | +|----------|---------| +| `DEV_CERT_PATH` / `DEV_CERT_PASSWORD` | Dev HTTPS certificate and its password | +| `DEV_CERT_PORT_REST` / `DEV_CERT_PORT_GRPC` | Ports the certificate covers (`5000` / `5001`) | +| `KEYCLOAK_URL` / `KEYCLOAK_REALM` | Where the host finds Keycloak and which realm | +| `KEYCLOAK_CLIENT_ID` / `KEYCLOAK_CLIENT_SECRET` | Client credentials (secret is required) | +| `JWT__KEY` / `JWT__ISSUER` / `JWT__AUDIENCE` | Developer-token signing and validation | +| `ERRORMETADATA__DOCSBASEURL` | Base URL rendered into error metadata links | + +At minimum, change `DEV_CERT_PASSWORD` and `KEYCLOAK_CLIENT_SECRET` the example values are public. + +## Certificates + +HTTPS terminates on a dev certificate from `./certs` (`DEV_CERT_PATH`, `DEV_CERT_PASSWORD` in `.env`). Mount your own `.pfx` there for a trusted local chain never commit the real password. `curl -k` in examples skips verification precisely because this is a dev cert. + +:::warning[Never commit secrets] +`.env` holds passwords and keys. It is git-ignored for a reason leaked `DEV_CERT_PASSWORD` or `KEYCLOAK_CLIENT_SECRET` means rotating credentials everywhere. +::: + +## Health & Logs + +`auth` carries a healthcheck (`curl -k https://localhost:5000/health`, 30s interval, 3 retries) databases use `pg_isready` (5s interval). Useful commands: + +```bash +docker compose ps # anything not healthy/running fails fast +docker compose logs -f auth # host output (Wolverine/Marten/Npgsql silenced to None by default) +docker compose logs -f authdev-db +``` + +If `auth` never becomes healthy, check the database first non healthy `authdev-db` blocks the host by design (`service_healthy` condition). + +## Rebuilding & Cleanup + +```bash +docker compose up --build # rebuild after code changes +docker compose down # stop, keep volumes (data stays) +docker compose down -v # stop AND drop volumes (fresh database) +``` + +Use `down -v` when you want to replay storage migration from scratch or discard a broken dev database. + +:::danger[down -v destroys data] +Dropping volumes wipes the encrypted keystore previously issued tokens stop verifying and must be reissued. There is no undo. +::: + +## Troubleshooting + +- **Port already in use** another Postgres on `5434`/`5433` or something on `5000`/`8081`: stop it or remap the left side of the `ports` entry. +- **Keycloak realm missing** the profile wasn't enabled (`--profile keycloak`) or the realm file wasn't mounted check `Deploy/Keycloak/realms/realm-authz.json` exists. +- **`auth` exits immediately** usually `.env` missing or `DEV_CERT_PASSWORD` wrong so Kestrel can't load the certificate read `docker compose logs auth`. +- **Token calls fail after restart** with fresh volume the keystore is new, so previously issued tokens no longer verify. Expected: rotate or reissue. + +## Without Docker + +The host is plain ASP.NET Core on Kestrel: + +```bash +dotnet restore AuthKit.slnx +dotnet build AuthKit.slnx --configuration Release +dotnet run --project src/Host/Host.csproj +``` + +Default listen address: `http://0.0.0.0:8080` (HTTP/2). You still need PostgreSQL and Keycloak reachable see [Quick Start](/guide/quick-start/#option-2-run-locally). + +## Toward Production + +- Put real secrets in vault or the platform's secret store, never in `.env` files. +- Terminate TLS at the edge (reverse proxy / ingress) with a proper certificate instead of the dev `.pfx`. +- Back up the `AuthDev-data` volume it holds the encrypted keystore and token bindings. +- Pin image tags (`postgres:15` floats) and set explicit resource limits per service. diff --git a/Docs/content/en/infrastructure/keycloak.md b/Docs/content/en/infrastructure/keycloak.md new file mode 100644 index 0000000..da4a8ac --- /dev/null +++ b/Docs/content/en/infrastructure/keycloak.md @@ -0,0 +1,59 @@ +# Keycloak + +Keycloak is the external JWT authority developers sign in through. AuthKit never stores developer passwords it validates Keycloak-issued access tokens and mints its own SDK tokens from them. See [ADR-015](/adr/015-keycloak-external-jwt-authority/). + +## How It Works + +The flow has three steps with a clean split of responsibilities: + +1. **Sign in** the developer authenticates with Keycloak through a standard OIDC flow and receives a JWT (bearer). +2. **Validate** the host validates the token via ASP.NET Core JWT bearer against the realm (`AddKeycloakServices`): issuer and audience must match, `NameClaimType` is `preferred_username`. +3. **Roles** an `OnTokenValidated` hook maps the client's `resource_access` roles into standard `ClaimTypes.Role` claims, so ordinary authorization policies work with no Keycloak-specific code in handlers. + +Rejected alternatives: local user store, self issued host tokens, custom role database all of them would couple the host to identity logic it should not own. + +## Setup + +1. Open http://localhost:8081, log in with `admin` / `admin`. +2. Import the realm from `Deploy/Keycloak/realms/realm-authz.json` (mounted read-only with auto-import in compose). +3. Set the client secret in `.env` (`KEYCLOAK_CLIENT_SECRET`). + +## Environment + +| Variable | Meaning | Default | +|----------|---------|---------| +| `KEYCLOAK_URL` | Keycloak base URL (`Authority`) | `http://keycloak:8080` | +| `KEYCLOAK_REALM` | Keycloak realm | `authz` | +| `KEYCLOAK_CLIENT_ID` | Keycloak client ID (`Audience`) | `workspace-authz` | +| `KEYCLOAK_CLIENT_SECRET` | Keycloak client secret | _required_ | + +The same configuration carries dev, test, and production values change, code doesn't. + +## Using the Token + +Every API call carries the Keycloak token in the header: + +```http +Authorization: Bearer +``` + +From it, AuthKit mints its own developer tokens (`X-Developer-Token`) details in the [REST API Reference](/reference/rest-api/). + +## Dev vs Production + +Deliberate development concessions, to be tightened before production: + +- `RequireHttpsMetadata = false`; +- a backchannel with `DangerousAcceptAnyServerCertificateValidator`. + +:::danger[Before production] +Both of the above must be tightened before any production deployment otherwise tokens travel over HTTP and certificate validation doesn't exist. +::: + +## Troubleshooting + +- **401 with a valid-looking token** check `KEYCLOAK_URL`/`KEYCLOAK_REALM`/`KEYCLOAK_CLIENT_ID`: issuer or audience doesn't match the token's issuer. +- **Missing roles in claims** roles must live in the client's `resource_access`, not at realm level the hook only maps client roles. +- **No realm after startup** the `keycloak` profile wasn't enabled or the realm file wasn't mounted see [Docker + Kestrel](/infrastructure/docker/). + +Full settings reference: [Configuration](/guide/configuration/). diff --git a/Docs/content/en/infrastructure/marten.md b/Docs/content/en/infrastructure/marten.md new file mode 100644 index 0000000..e0fa7ea --- /dev/null +++ b/Docs/content/en/infrastructure/marten.md @@ -0,0 +1,98 @@ +# Marten + PostgreSQL + +Marten is the PostgreSQL document/event store behind AuthKit persistence: the keystore, token bindings, plugin documents, and the message outbox. One Postgres, many roles configured in one place. + +## What Lives There + +- **Keystore** the encrypted singleton holding signing key material (see [ADR-011](/adr/011-keystore-persisted-as-singleton-marten-document/)) +- **Token bindings** developer token key bindings (see [ADR-012](/adr/012-token-key-bindings-persisted-in-marten/)) +- **Plugin documents** every plugin implementing `IMartenPlugin` brings its own documents +- **Outbox** the Wolverine message store shared with handlers (`IntegrateWithWolverine`). + +All of it is plain JSONB documents in one cluster plain Postgres client is enough for inspection, no Marten tooling required. + +## Connection and Schema + +```json +{ + "ConnectionStrings": { + "Marten": "Host=authdev-db;Port=5432;Database=AuthDev;Username=postgres;Password=postgres" + } +} +``` + +Schema objects auto-create on startup (`AutoCreate.All`) in dev you never write migrations by hand. + +:::warning[AutoCreate in production] +Automatic schema creation is a developer convenience. For production, generate migration scripts ahead of time and apply them deliberately instead of letting the app modify the schema on startup. +::: + +## Plugin Documents + +A plugin contributes documents with a single hook: + +```csharp +public interface IMartenPlugin +{ + void ConfigureMarten(StoreOptions options); +} +``` + +The rules are strict and few: + +- the hook runs **once**, while the host builds its single document store, before the store is opened +- plugins are processed in ascending plugin-ID order ordering is deterministic and independent of discovery order +- the hook configures **only** `StoreOptions` it must not reach for `IDocumentStore` or `IDocumentSession`, which exist only after the provider is built +- the plugin's `ConfigureServices` services are already registered when the hook runs you may assume their presence, but not sessions. + +## Sessions and Outbox + +Marten works on lightweight sessions (`UseLightweightSessions`) integrated with Wolverine: a handler writes documents and publishes messages in the same unit of work. If the handler fails, both the write and the send roll back there are no "saved but not sent" states. + +It works the other way too: a message in the outbox without a matching write doesn't exist. Consistency between "what the system remembered" and "what the system sent" is a transactional property, not a gentlemen's agreement. + +## Operations + +- **Backup** back up the `AuthDev` database (keys + tokens + outbox are one consistent set) losing the keystore invalidates every issued token. +- **Fresh start** `docker compose down -v` wipes everything including the schema the next start rebuilds from zero. +- **Inspection** plain Postgres client is enough: documents are JSONB, readable without Marten tooling. + +## Diagnostics + + + +Check the `Marten` connection string and that `authdev-db` is `healthy` (`docker compose ps`) the host only starts after healthy database. + + + + + +Someone changed document without migrating in dev drop the volume (`down -v`), in production apply the generated script. + + + + + +Sessions are lightweight and short lived long transaction usually means handler doing too much split it into messages. + + + + + +In `MediatorOnly` mode (`SkipStorageMigrationOnStartup: true`) there is no message storage everything in flight dies on restart. If you lose calls locally, check that flag before debugging handlers. + + + + + +A fresh volume means a new keystore previously issued tokens have nothing to verify against. That's key rotation semantics, not a bug: reissue tokens or restore from backup. + + + + + +Documents are JSONB filtering unindexed fields hurts as data grows. Add indexes in the same `ConfigureMarten` where you define documents measure on real data, not an empty dev database. + + + +See [ADR-016](/adr/016-marten-and-wolverine-infrastructure/). diff --git a/Docs/content/en/infrastructure/wolverine.md b/Docs/content/en/infrastructure/wolverine.md new file mode 100644 index 0000000..7a1f097 --- /dev/null +++ b/Docs/content/en/infrastructure/wolverine.md @@ -0,0 +1,57 @@ +# Wolverine + +Wolverine handles commands and queries inside the host. It runs as an in-process mediator: instead of calling each other directly, code sends messages and Wolverine routes them to handlers with validation, durability, and logging applied uniformly around every execution. + +## Mediator, Not Broker + +There is no external transport or queue to configure: messages never leave the process. Wolverine is an in-memory call director with a uniform pipeline (middleware) around every handler. You get architectural order (commands/queries instead of tangled calls) without a broker's operational price. + +## Discovery + +Handlers are discovered, not registered. At startup the host includes exactly two sources: + +- the **Core assembly** (anchored at `JwtKeyStore`) domain commands and queries +- **each loaded plugin assembly** plugins ship handlers with their own code, and the host never references plugin assemblies directly. + +Consequence: adding handler means adding a class in the right assembly. There is no central registry file to update and forget. + +## Writing Handlers + +Command/query types and handlers land in Core (domain behavior) or in the plugin assembly (plugin behavior). Pair every command with a validator DevTokens keeps them in `UseCase/Commands/Validations/` next to `UseCase/Commands/Requests/`. + +## Validation + +FluentValidation runs as Wolverine middleware, so invalid messages fail before handlers execute. Validation is a pipeline property, never a manual call inside each handler it cannot be forgotten. + +## Durability and Outbox + +```json +{ + "AuthKit": { + "SkipStorageMigrationOnStartup": false + } +} +``` + +- Default keeps full durability: message storage is built on startup and Marten integrates as the outbox (`IntegrateWithWolverine`) handlers and persistence share the transactional outbox. +- With `SkipStorageMigrationOnStartup: true`, Wolverine drops to `MediatorOnly` mode (in-memory, no message storage) and skips storage migration. Use it for fast local iterations where losing in-flight messages on restart doesn't matter. + +## Plugins Bring Handlers + +This is the key property of the model: plugin logic doesn't end at endpoints. A plugin can define its own commands, queries, and handlers in its own assembly the host includes them in discovery just like Core. A plugin endpoint typically just translates HTTP/gRPC into a message and sends it to Wolverine all logic lives in handlers. + +## Logging and Observability + +The pipeline is silent by default: message execution/success levels and the `Wolverine`, `Marten`, and `Npgsql` categories are set to `None`. + +:::tip[Debugging the pipeline] +Raise these categories temporarily when handler misbehaves silent pipeline hides both the message flow and the SQL behind it. +::: + +## Configuration + +| Option | Default | Meaning | +|--------|---------|---------| +| `AuthKit:SkipStorageMigrationOnStartup` | `false` | `true` → `MediatorOnly` mode, no storage migration | + +See [ADR-016](/adr/016-marten-and-wolverine-infrastructure/). diff --git a/Docs/content/pl/infrastructure/docker.md b/Docs/content/pl/infrastructure/docker.md new file mode 100644 index 0000000..2080166 --- /dev/null +++ b/Docs/content/pl/infrastructure/docker.md @@ -0,0 +1,121 @@ +# Docker + Kestrel + +Cały stos jedzie z jednego pliku compose: AuthKit, PostgreSQL i Keycloak. Ta strona prowadzi przez pełny cykl pierwszy start, codzienność, debugowanie i to, co zmienia się w drodze na produkcję. + +## Wymagania + +- [Docker](https://docs.docker.com/get-docker/) z Compose v2. +- Wolne porty `5000`, `5001`, `8081`, `5433`, `5434`. +- Deweloperski certyfikat HTTPS w `./certs` (zobacz [Certyfikaty](#certyfikaty)). + +## Pierwszy start + +```bash +cp .env.example .env +docker compose up --build +``` + +Co dzieje się po kolei: + +1. Budują się obrazy (`auth` z rootowego `Dockerfile`, `keycloak` z `Deploy/Keycloak/Dockerfile`) bazy ciągną `postgres:15`. +2. Powstają nazwane volumy `AuthDev-data` i `Auth-data` dane przeżywają restarty kontenerów. +3. `authdev-db` musi zgłosić `healthy` (`pg_isready`), zanim `auth` w ogóle ruszy. +4. `auth` robi migrację storage, mapuje endpointy REST + gRPC i zaczyna słuchać. + +Zweryfikuj endpointem health: + +```bash +curl -k https://localhost:5000/health +``` + +## Usługi + +| Usługa | Obraz / Build | Porty | Cel | +|--------|---------------|-------|-----| +| `auth` | `Dockerfile` (root repo) | `5000` REST, `5001` gRPC | Host AuthKit (HTTPS) | +| `authdev-db` | `postgres:15` | `5434` → `5432` | Baza AuthKit (volume `AuthDev-data`) | +| `keycloak` | `Deploy/Keycloak/Dockerfile` | `8081` → `8080` | Dostawca tożsamości, realm auto-importowany | +| `keycloak-db` | `postgres:15` | `5433` → `5432` | Baza Keycloak (volume `Auth-data`) | + +`auth` montuje `./certs` na deweloperski certyfikat HTTPS i czyta `.env` plus `ConnectionStrings__DefaultConnection` wskazujący na `authdev-db`. Wszystko gada po sieci mostkowej `db_net` serwisy widzą się po nazwach (`authdev-db`, `keycloak-db`). + +## Profil Keycloak + +`keycloak` i `keycloak-db` siedzą za profilem `keycloak` w compose: bazowy `up` stawia AuthKit z własną bazą, a `docker compose --profile keycloak up` dokłada stos tożsamości. Plik realm jest montowany read-only i importowany przy starcie (`--import-realm`) bootstrap admin to `admin` / `admin`. + +Po pierwszym starcie otwórz http://localhost:8081 i potwierdź, że realm `authz` istnieje. Credentiale klienta biorą się z `.env` (`KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET`). + +## Zmienne środowiskowe + +Kopia tego, co deklaruje `.env.example` ustaw przed pierwszym `up`: + +| Zmienna | Znaczenie | +|---------|-----------| +| `DEV_CERT_PATH` / `DEV_CERT_PASSWORD` | Deweloperski certyfikat HTTPS i hasło do niego | +| `DEV_CERT_PORT_REST` / `DEV_CERT_PORT_GRPC` | Porty pokrywane certyfikatem (`5000` / `5001`) | +| `KEYCLOAK_URL` / `KEYCLOAK_REALM` | Gdzie host znajduje Keycloak i który realm | +| `KEYCLOAK_CLIENT_ID` / `KEYCLOAK_CLIENT_SECRET` | Credentiale klienta (sekret wymagany) | +| `JWT__KEY` / `JWT__ISSUER` / `JWT__AUDIENCE` | Podpisywanie i walidacja tokenów deweloperskich | +| `ERRORMETADATA__DOCSBASEURL` | Bazowy URL renderowany w linkach metadanych błędów | + +Minimum: zmień `DEV_CERT_PASSWORD` i `KEYCLOAK_CLIENT_SECRET` przykładowe wartości są publiczne. + +## Certyfikaty + +HTTPS terminuje na dev-cercie z `./certs` (`DEV_CERT_PATH`, `DEV_CERT_PASSWORD` w `.env`). Podmontuj tam własny `.pfx` dla zaufanego lokalnego łańcucha prawdziwego hasła nigdy nie commituj. `curl -k` w przykładach pomija weryfikację dokładnie dlatego, że to dev-cert. + +:::warning[Nigdy nie commituj sekretów] +`.env` trzyma hasła i klucze. Jest w gitignore nie bez powodu wyciek `DEV_CERT_PASSWORD` albo `KEYCLOAK_CLIENT_SECRET` znaczy rotację credentiali wszędzie. +::: + +## Health i logi + +`auth` niesie healthcheck (`curl -k https://localhost:5000/health`, co 30s, 3 próby) bazy używają `pg_isready` (co 5s). Przydatne komendy: + +```bash +docker compose ps # cokolwiek nie healthy/running pada szybko +docker compose logs -f auth # output hosta (Wolverine/Marten/Npgsql domyślnie wyciszone do None) +docker compose logs -f authdev-db +``` + +Jeśli `auth` nigdy nie robi się healthy, sprawdź najpierw bazę niezdrowa `authdev-db` blokuje hosta z założenia (warunek `service_healthy`). + +## Przebudowa i sprzątanie + +```bash +docker compose up --build # przebuduj po zmianach w kodzie +docker compose down # stop, volumy zostają (dane zostają) +docker compose down -v # stop I wywalenie volumów (świeża baza) +``` + +`down -v` użyj, kiedy chcesz odtworzyć migrację storage od zera albo wyrzucić zepsutą dev-bazę. + +:::danger[down -v niszczy dane] +Wywalenie volumów kasuje szyfrowany magazyn kluczy wcześniej wydane tokeny przestają się weryfikować i trzeba je wydać od nowa. Nie ma cofnięcia. +::: + +## Rozwiązywanie problemów + +- **Port zajęty** inny Postgres na `5434`/`5433` albo coś na `5000`/`8081`: zatrzymaj albo przemapuj lewą stronę wpisu `ports`. +- **Brak realm w Keycloak** profil nie włączony (`--profile keycloak`) albo plik realm nie zamontowany sprawdź, czy `Deploy/Keycloak/realms/realm-authz.json` istnieje. +- **`auth` wychodzi od razu** zwykle brak `.env` albo złe `DEV_CERT_PASSWORD`, więc Kestrel nie ładuje certyfikatu czytaj `docker compose logs auth`. +- **Wołania tokenami padają po restarcie** ze świeżym volumem magazyn kluczy jest nowy, więc wcześniej wydane tokeny już się nie weryfikują. Oczekiwane: rotuj albo wydaj od nowa. + +## Bez Dockera + +Host to zwykły ASP.NET Core na Kestrelu: + +```bash +dotnet restore AuthKit.slnx +dotnet build AuthKit.slnx --configuration Release +dotnet run --project src/Host/Host.csproj +``` + +Domyślny adres: `http://0.0.0.0:8080` (HTTP/2). PostgreSQL i Keycloak muszą być i tak osiągalne zobacz [Szybki start](/pl/guide/quick-start/#option-2-run-locally). + +## W stronę produkcji + +- Prawdziwe sekrety trzymaj w vaulcie albo secret store platformy, nigdy w plikach `.env`. +- Terminuj TLS na brzegu (reverse proxy / ingress) z prawidłowym certyfikatem zamiast dev-`.pfx`. +- Backupuj volume `AuthDev-data` leży tam szyfrowany magazyn kluczy i powiązania tokenów. +- Przypnij tagi obrazów (`postgres:15` pływa) i ustaw jawne limity zasobów na serwis. diff --git a/Docs/content/pl/infrastructure/keycloak.md b/Docs/content/pl/infrastructure/keycloak.md new file mode 100644 index 0000000..96c7a88 --- /dev/null +++ b/Docs/content/pl/infrastructure/keycloak.md @@ -0,0 +1,59 @@ +# Keycloak + +Keycloak to zewnętrzny urząd JWT, przez który logują się deweloperzy. AuthKit nigdy nie przechowuje haseł deweloperów weryfikuje tokeny dostępowe wydane przez Keycloak i na ich podstawie bije własne tokeny SDK. Zobacz [ADR-015](/pl/adr/015-keycloak-external-jwt-authority/). + +## Jak to działa + +Przepływ ma trzy kroki i jasny podział odpowiedzialności: + +1. **Logowanie** deweloper uwierzytelnia się w Keycloak standardowym przepływem OIDC i dostaje JWT (bearer). +2. **Weryfikacja** host waliduje token przez ASP.NET Core JWT bearer względem realm (`AddKeycloakServices`): issuer i audience muszą się zgadzać, `NameClaimType` to `preferred_username`. +3. **Role** hook `OnTokenValidated` mapuje role klienta z `resource_access` na standardowe `ClaimTypes.Role`, więc zwykłe polityki autoryzacji działają bez kodu specyficznego dla Keycloak w handlerach. + +Odrzucone alternatywy: własny lokalny magazyn użytkowników, tokeny self-issued w hoście, własna baza ról wszystko to wiązałoby host z logiką tożsamości, której nie powinien posiadać. + +## Konfiguracja + +1. Otwórz http://localhost:8081, zaloguj `admin` / `admin`. +2. Zaimportuj realm z `Deploy/Keycloak/realms/realm-authz.json` (w compose montowany read-only z auto-importem). +3. Ustaw sekret klienta w `.env` (`KEYCLOAK_CLIENT_SECRET`). + +## Zmienne środowiskowe + +| Zmienna | Znaczenie | Domyślnie | +|---------|-----------|-----------| +| `KEYCLOAK_URL` | Bazowy URL Keycloak (`Authority`) | `http://keycloak:8080` | +| `KEYCLOAK_REALM` | Realm Keycloak | `authz` | +| `KEYCLOAK_CLIENT_ID` | ID klienta Keycloak (`Audience`) | `workspace-authz` | +| `KEYCLOAK_CLIENT_SECRET` | Sekret klienta Keycloak | _wymagane_ | + +Ta sama konfiguracja niesie dev, test i produkcję zmieniają się wartości, nie kod. + +## Używanie tokenu + +Każde wywołanie API niesie token Keycloak w nagłówku: + +```http +Authorization: Bearer +``` + +Na jego podstawie AuthKit wydaje własne tokeny deweloperskie (`X-Developer-Token`) szczegóły w [REST API Reference](/pl/reference/rest-api/). + +## Dev a produkcja + +Świadome ustępstwa deweloperskie, do zaciśnięcia przed produkcją: + +- `RequireHttpsMetadata = false`; +- backchannel z `DangerousAcceptAnyServerCertificateValidator`. + +:::danger[Przed produkcją] +Oba powyższe muszą zostać zaciśnięte przed jakimkolwiek produkcyjnym deploymentem inaczej tokeny lecą po HTTP i walidacja certyfikatów nie istnieje. +::: + +## Rozwiązywanie problemów + +- **401 mimo poprawnego tokenu** sprawdź `KEYCLOAK_URL`/`KEYCLOAK_REALM`/`KEYCLOAK_CLIENT_ID`: issuer albo audience nie zgadza się z wystawcą tokenu. +- **Brak ról w claimach** role muszą siedzieć w `resource_access` klienta, nie na poziomie realm hook mapuje tylko role klienta. +- **Brak realm po starcie** profil `keycloak` nie włączony albo plik realm nie zamontowany zobacz [Docker + Kestrel](/pl/infrastructure/docker/). + +Pełna referencja ustawień: [Konfiguracja](/pl/guide/configuration/). diff --git a/Docs/content/pl/infrastructure/marten.md b/Docs/content/pl/infrastructure/marten.md new file mode 100644 index 0000000..1f5cadd --- /dev/null +++ b/Docs/content/pl/infrastructure/marten.md @@ -0,0 +1,98 @@ +# Marten + PostgreSQL + +Marten to dokumentowo-eventowy magazyn PostgreSQL stojący za trwałością AuthKit: magazynem kluczy, powiązaniami tokenów, dokumentami wtyczek i outboxem wiadomości. Jeden Postgres, wiele ról konfigurowany w jednym miejscu. + +## Co tam mieszka + +- **Magazyn kluczy** zaszyfrowany singleton z materiałem kluczy podpisujących (zobacz [ADR-011](/pl/adr/011-keystore-persisted-as-singleton-marten-document/)) +- **Powiązania tokenów** powiązania kluczy tokenów deweloperskich (zobacz [ADR-012](/pl/adr/012-token-key-bindings-persisted-in-marten/)) +- **Dokumenty wtyczek** każda wtyczka implementująca `IMartenPlugin` wnosi własne dokumenty +- **Outbox** magazyn wiadomości Wolverine dzielony z handlerami (`IntegrateWithWolverine`). + +Wszystko to zwykłe dokumenty JSONB w jednym klastrze do podglądu wystarczy plain klient Postgres, bez narzędzi Marten. + +## Połączenie i schemat + +```json +{ + "ConnectionStrings": { + "Marten": "Host=authdev-db;Port=5432;Database=AuthDev;Username=postgres;Password=postgres" + } +} +``` + +Obiekty schematu tworzą się same przy starcie (`AutoCreate.All`) w dev nie piszesz migracji ręcznie. + +:::warning[AutoCreate na produkcji] +Automatyczne tworzenie schematu to wygoda deweloperska. Produkcyjnie generuj skrypty migracji z wyprzedzeniem i aplikuj je kontrolowanie zamiast pozwalać aplikacji modyfikować schemat przy starcie. +::: + +## Dokumenty wtyczek + +Wtyczka wnosi dokumenty jednym hakiem: + +```csharp +public interface IMartenPlugin +{ + void ConfigureMarten(StoreOptions options); +} +``` + +Zasady są twarde i jest ich mało: + +- hak wołany jest **raz**, podczas budowania pojedynczego document store hosta, zanim store zostanie otwarty +- wtyczki przetwarzane są w rosnącym porządku id kolejność jest deterministyczna i nie zależy od kolejności discovery +- hak konfiguruje **tylko** `StoreOptions` nie wolno w nim sięgać po `IDocumentStore` ani `IDocumentSession`, te powstają dopiero po zbudowaniu providera +- usługi wtyczki z `ConfigureServices` są już zarejestrowane, kiedy hak leci możesz zakładać ich obecność, ale nie sesje. + +## Sesje i outbox + +Marten pracuje na lekkich sesjach (`UseLightweightSessions`) zintegrowanych z Wolverine: handler zapisuje dokumenty i publikuje wiadomości w tej samej jednostce pracy. Jeśli handler padnie, wycofuje się i zapis, i wysyłka nie ma stanów „zapisane, ale nie wysłane". + +W drugą stronę działa to tak samo: wiadomość w outboxie bez odpowiadającego zapisu nie istnieje. Spójność między „co system zapamiętał" a „co system wysłał" nie jest umową dżentelmeńską, tylko własnością transakcji. + +## Operacje + +- **Backup** backupuj bazę `AuthDev` (klucze + tokeny + outbox to jeden spójny zestaw) utrata magazynu kluczy unieważnia wszystkie wydane tokeny. +- **Świeży start** `docker compose down -v` kasuje wszystko łącznie ze schematem następny start odbudowuje od zera. +- **Podgląd** zwykły klient Postgres wystarczy: dokumenty to JSONB, czytelne bez narzędzi Marten. + +## Diagnostyka + + + +Sprawdź connection string `Marten` i to, czy `authdev-db` jest `healthy` (`docker compose ps`) host startuje dopiero po zdrowej bazie. + + + + + +Ktoś zmienił dokument bez migracji w dev usuń volume (`down -v`), produkcyjnie aplikuj wygenerowany skrypt. + + + + + +Sesje są lightweight i krótkie długa transakcja zwykle znaczy handler robiący za dużo podziel go na wiadomości. + + + + + +W trybie `MediatorOnly` (`SkipStorageMigrationOnStartup: true`) nie ma magazynu wiadomości wszystko w locie przepada przy restarcie. Jeśli gubisz wywołania lokalnie, sprawdź najpierw tę flagę, zanim zaczniesz debugować handlery. + + + + + +Świeży volume to nowy magazyn kluczy wcześniej wydane tokeny nie mają czym się zweryfikować. To nie błąd, tylko własność rotacji kluczy: wydaj tokeny od nowa albo odtwórz bazę z backupu. + + + + + +Dokumenty to JSONB filtrowanie po polach bez indeksów boli wraz ze wzrostem. Indeksy dokładasz w tym samym `ConfigureMarten`, w którym definiujesz dokumenty mierz na prawdziwych danych, nie na pustej dev-bazie. + + + +Zobacz [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/). diff --git a/Docs/content/pl/infrastructure/wolverine.md b/Docs/content/pl/infrastructure/wolverine.md new file mode 100644 index 0000000..1d28006 --- /dev/null +++ b/Docs/content/pl/infrastructure/wolverine.md @@ -0,0 +1,57 @@ +# Wolverine + +Wolverine obsługuje komendy i zapytania wewnątrz hosta. Działa jako mediator w procesie: zamiast wołać się bezpośrednio, kod wysyła wiadomości, a Wolverine kieruje je do handlerów z walidacją, trwałością i logowaniem nakładanymi jednolicie wokół każdego wykonania. + +## Mediator, nie broker + +Nie ma tu zewnętrznego transportu ani kolejek do konfigurowania: wiadomości nie opuszczają procesu. Wolverine to reżyser wywołań w pamięci z jednolitym potokiem (middleware) wokół każdego handlera. Dostajesz porządek architektury (komendy/zapytania zamiast plątaniny wywołań) bez operacyjnej ceny brokera. + +## Odkrywanie + +Handlery są odkrywane, nie rejestrowane. Przy starcie host włącza dokładnie dwa źródła: + +- **assembly Core** (zakotwiczone w `JwtKeyStore`) komendy i zapytania domenowe +- **assembly każdej załadowanej wtyczki** wtyczka wiezie handlery z własnym kodem, a host nigdy nie referencjonuje assembly wtyczek wprost. + +Konsekwencja: dodanie handlera to dodanie klasy we właściwym assembly. Nie ma centralnego rejestru do zaktualizowania i zapomnienia. + +## Pisanie handlerów + +Typy komend/zapytań i handlery lądują w Core (zachowanie domenowe) albo w assembly wtyczki (zachowanie wtyczki). Każdą komendę paruj z walidatorem DevTokens trzyma je w `UseCase/Commands/Validations/` obok `UseCase/Commands/Requests/`. + +## Walidacja + +FluentValidation działa jako middleware Wolverine, więc niepoprawne wiadomości odpadają przed handlerami. Walidacja nie jest wołana ręcznie w każdym handlerze jest własnością potoku, więc nie da się jej zapomnieć. + +## Trwałość i outbox + +```json +{ + "AuthKit": { + "SkipStorageMigrationOnStartup": false + } +} +``` + +- Domyślnie pełna trwałość: magazyn wiadomości budowany jest przy starcie, a Marten integruje się jako outbox (`IntegrateWithWolverine`) handlery i persystencja dzielą transakcyjny outbox. +- Z `SkipStorageMigrationOnStartup: true` Wolverine spada do trybu `MediatorOnly` (in-memory, bez magazynu wiadomości) i pomija migrację storage. Używaj do szybkich lokalnych iteracji, gdzie utrata wiadomości w locie przy restarcie nie ma znaczenia. + +## Wtyczki wnoszą handlery + +To kluczowa własność modelu: logika wtyczki nie kończy się na endpointach. Wtyczka może definiować własne komendy, zapytania i handlery we własnym assembly host włącza je do discovery tak samo jak Core. Endpoint wtyczki zwykle tylko tłumaczy HTTP/gRPC na wiadomość i wysyła ją do Wolverine cała logika żyje w handlerach. + +## Logowanie i obserwowalność + +Potok domyślnie milczy: poziomy wykonania/sukcesu wiadomości oraz kategorie `Wolverine`, `Marten` i `Npgsql` ustawione są na `None`. + +:::tip[Debugowanie potoku] +Podnieś te kategorie tymczasowo, kiedy handler zachowuje się dziwnie cichy potok ukrywa zarówno przepływ wiadomości, jak i SQL za nim. +::: + +## Konfiguracja + +| Opcja | Domyślnie | Znaczenie | +|-------|------------|-----------| +| `AuthKit:SkipStorageMigrationOnStartup` | `false` | `true` → tryb `MediatorOnly`, brak migracji storage | + +Zobacz [ADR-016](/pl/adr/016-marten-and-wolverine-infrastructure/). From a166a72ac3b045a951fcc8a1dc2b45a0c6479ada Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:48:01 +0200 Subject: [PATCH 04/17] docs: document plugin contracts and built-in plugins --- Docs/content/en/plugins/README.md | 9 +++ Docs/content/en/plugins/custom.md | 75 ++++++++++++++++++++++++ Docs/content/en/plugins/devtokens.md | 31 ++++++++++ Docs/content/en/plugins/devtools.md | 87 ++++++++++++++++++++++++++++ Docs/content/pl/plugins/README.md | 9 +++ Docs/content/pl/plugins/custom.md | 75 ++++++++++++++++++++++++ Docs/content/pl/plugins/devtokens.md | 31 ++++++++++ Docs/content/pl/plugins/devtools.md | 87 ++++++++++++++++++++++++++++ 8 files changed, 404 insertions(+) create mode 100644 Docs/content/en/plugins/README.md create mode 100644 Docs/content/en/plugins/custom.md create mode 100644 Docs/content/en/plugins/devtokens.md create mode 100644 Docs/content/en/plugins/devtools.md create mode 100644 Docs/content/pl/plugins/README.md create mode 100644 Docs/content/pl/plugins/custom.md create mode 100644 Docs/content/pl/plugins/devtokens.md create mode 100644 Docs/content/pl/plugins/devtools.md diff --git a/Docs/content/en/plugins/README.md b/Docs/content/en/plugins/README.md new file mode 100644 index 0000000..d4f23b3 --- /dev/null +++ b/Docs/content/en/plugins/README.md @@ -0,0 +1,9 @@ +# Plugins + +Extend AuthKit without forking it. Pick plugin to learn what it does, or write your own behind the stable contract. + +- [DevTokens](/plugins/devtokens/) issues and validates developer tokens for SDK access. +- [DevTools](/plugins/devtools/) Swagger, gRPC exploration, and an embedded UI inside the running server. +- [Custom plugins](/plugins/custom/) ship your own behavior behind `IAuthKitPlugin`. + +New to AuthKit? Start with [Introduction](/guide/introduction/). diff --git a/Docs/content/en/plugins/custom.md b/Docs/content/en/plugins/custom.md new file mode 100644 index 0000000..b4c45cc --- /dev/null +++ b/Docs/content/en/plugins/custom.md @@ -0,0 +1,75 @@ +# Custom Plugins + +Every behavior in AuthKit that isn't Core domain or host plumbing arrives as a plugin including the built-in [DevTokens](/plugins/devtokens/) and [DevTools](/plugins/devtools/). Writing your own follows the same path the built-ins took: implement one contract, declare metadata, drop the assembly in a directory. The host does the rest. + +## Why Plugins Instead of Forks + +> AuthKit's cost center is contracts between layers, not single classes. Forking the host to add behavior would tangle your code with ours on every update. The plugin contract inverts that: the host exposes stable slots, and your assembly fills them without referencing host internals. When the host evolves, the contract is what stays still. + +## The Contract + +`IAuthKitPlugin` is partial interface one facet per concern, grouped in `IAuthKitPlugin*.cs` files: base identity and metadata accessors, host requirements, configuration, health, pipeline, security, and lifecycle hooks. You implement the facets you need the rest comes with defaults derived from your metadata. + +In practice a minimal plugin looks like the bundled example: + +```csharp +[PluginMetadata( + id: "acme.audit", + version: "1.0.0", + tags: ["audit"], + dependsOn: [], + capabilities: ["audit"], + name: "Audit", + displayName: "Audit Trail", + description: "Appends audit entries for token operations.", + author: "Acme", + license: "MIT")] +public sealed class AuditPlugin : IAuthKitPlugin +{ + public void ConfigureServices(IServiceCollection services, AuthKitPluginContext context) + { + // register plugin services here and only here + } +} +``` + +Two rules keep the model honest: + +- **Stay inside the contract** keep host integration limited to what the contract exposes reach past it and you own the breakage. +- **Register in ConfigureServices** register every plugin-specific dependency inside `ConfigureServices` the host never wires your internals for you. + +## Metadata Is Load-Bearing + +`[PluginMetadata]` is not decoration. The host reads it before loading anything and uses it for: + +- **identity** `Id` must be non-empty, stable across restarts, and host-unique (format and uniqueness are validated before activation) `Version` is real SemVer with parsing and precedence +- **presentation** `DisplayName ?? Name` plus `Description` surface in startup output, diagnostics, and UIs +- **capabilities** case insensitive feature names (`plugin.Supports("auth")`) used for pre-activation checks and post load consistency validation +- **tags** case sensitive classification for filtering in catalogs and UIs. + +A plugin class without the attribute fails fast with `InvalidOperationException` loud at startup instead of mysterious at runtime. + +:::warning[Don't bypass the contract] +Reaching past the contract (reflection into host internals, private APIs) is the one way to void the stability the plugin model buys you. If slot you need doesn't exist, extend the contract instead of routing around it. +::: + +## From Directory to Running Code + +Dropping an assembly in the configured directory starts a pipeline (see [ADR-009](/adr/009-dynamic-plugin-discovery/) and [ADR-010](/adr/010-plugin-loading-from-directory/)): + +1. **Discovery** the host scans the directory at startup nothing needs a host reference or recompilation. +2. **Manifest & gates** metadata is read into a manifest. `IsEnabled: false` skips the plugin before loading (no consistency check runs for it) accepted manifests go through format, uniqueness, and consistency validation. +3. **Activation order** dependencies first (topological sort wins over everything), then `Priority` ascending among the ready set. Lower numbers start earlier the default is `0`. +4. **Configuration** each plugin receives its scoped configuration section plus host-builder access through the plugin configuration context ([ADR-022](/adr/022-plugin-configuration-context-and-builder/)). +5. **Pipeline & lifecycle** endpoints and middleware attach through explicit host hooks ([ADR-023](/adr/023-plugin-application-pipeline-hooks/)) startup and shutdown follow the standard .NET host lifecycle ([ADR-024](/adr/024-plugin-lifecycle-and-hosted-services/)). +6. **Health & OpenAPI** structured health checks ([ADR-029](/adr/029-structured-plugin-health-contract/)) and security schemes flow into monitoring and the DevTools Swagger automatically. + +## Start From the Example + +:::tip[Copy, don't start blank] +`src/Plugins/Solutions/ExamplePlugin/` is a minimal greeting plugin (`authkit.example.ExampleGreeter` over gRPC) exercising exactly this path: metadata, discovery, configuration, endpoint. Copy the directory, rename the id, and grow from something that already loads. +::: + +## gRPC Services + +Plugins are not limited to REST: plugin can expose its own gRPC services next to the host ones, mapped through the same discovery. The example plugin does exactly that with `ExampleGreeter/SayHello` see the [gRPC surface](/reference/grpc/) and [plugin services](/reference/grpc/#Plugin-Services). diff --git a/Docs/content/en/plugins/devtokens.md b/Docs/content/en/plugins/devtokens.md new file mode 100644 index 0000000..efe3f9f --- /dev/null +++ b/Docs/content/en/plugins/devtokens.md @@ -0,0 +1,31 @@ +# DevTokens + +The `DevTokens` plugin (`authkit.devtokens`) issues, validates, and authorizes developer tokens for SDK access. Signing keys and token-to-key bindings come from the Host core the plugin owns the token lifecycle, not the key infrastructure. + +## Token Lifecycle + +1. **Create** `POST /sdk/developer-tokens` with name, scopes, and lifetime. Returns a signed JWT plus a `rk_live_…` key. +2. **Persist** tokens are stored in Marten with metadata (scopes, expiry). +3. **Verify** `POST /sdk/tokens/verify` validates without a database round-trip where possible. +4. **Revoke & rotate** `POST /sdk/tokens/{tokenId}/revoke-rotate` replaces a token in one call. + +Full endpoint shapes: [REST API Reference](/reference/rest-api/). + +## Scopes + +Tokens carry scopes (eg. `write:packages`). Requests are authorized against the scopes the token was issued with a token never grows permissions beyond its issue set. + +## Using Tokens + +SDK calls present two credentials: + +```http +Authorization: Bearer +X-Developer-Token: +``` + +The pipeline validates both and enforces scope access. See [Using Tokens in SDK Requests](/reference/rest-api/#Using-Tokens-in-SDK-Requests). + +## Validation + +Request models are validated with FluentValidation before anything touches the store malformed payloads fail fast with RFC 7807 problem details. diff --git a/Docs/content/en/plugins/devtools.md b/Docs/content/en/plugins/devtools.md new file mode 100644 index 0000000..495fee9 --- /dev/null +++ b/Docs/content/en/plugins/devtools.md @@ -0,0 +1,87 @@ +# DevTools + +When AuthKit runs, you don't want to guess what it exposes you want to see it. The `DevTools` plugin is the server's built-in inspection hatch: it hosts developer tooling inside the running process, so the same binary that serves your SDK clients also answers the question "what is actually mapped right now?". + +That question is harder than it sounds. AuthKit composes its surface at startup from the host plus every discovered plugin: REST endpoints, gRPC services, OpenAPI security schemes, health checks. A checked-in spec file would rot within a week. DevTools avoids that by generating everything from the composed application at runtime what you browse is always what is really there. + +## What You Get + +Open a running AuthKit and three doors are waiting (all paths configurable, see [Options](#Options)): + + + + + +A typical session flows like this: + +1. Start the stack, open `/devtools/swagger`, and walk the token endpoints from the [REST API Reference](/reference/rest-api/) issue developer token, then verify it, without writing a single line of client code. +2. When something behaves unexpectedly, switch to `/grpc-ui` and invoke the underlying `jwks` or `monitoring` calls directly. +3. Compare the two: if gRPC answers cleanly, the problem sits in the transport if not, it lives deeper. + +## Swagger via Reflection + +Behind `/devtools/swagger` stands `SwaggerHost`. The host already generates an OpenAPI document through its generation pipeline (SwaggerGen) the plugin's job is to serve that document and the UI from inside the plugin, contributed back into the host pipeline like any other middleware. + +Two details matter here. First, the document covers plugin-contributed endpoints and security schemes as well your own plugin declaring an OpenAPI scheme shows up in Swagger with zero extra work. Second, the reflection-based middleware instances are constructed once and reused for every request, so serving docs doesn't pay a per-request reflection tax. See [ADR-021](/adr/021-swagger-serving-via-reflection/). + +:::tip[Free for your plugin] +If you write your own plugin, you do nothing to land in Swagger just declare schemes through the contract. Details: [Custom plugins](/plugins/custom/). +::: + +## Exploring gRPC Without Clients + +gRPC is powerful but awkward to poke at: you normally need generated stubs in your language before you can call anything. `GrpcServiceCatalog` removes that friction. It tracks every mapped gRPC service host services like `jwks` and `monitoring` as well as plugin-contributed ones together with their protobuf descriptors and the doc comments from the `.proto` files. That catalog is what the [gRPC surface](/reference/grpc/) documentation is derived from, and what the UI browses. + +`GrpcDynamicInvoker` goes one step further: it actually executes unary calls discovered through the catalog. Messages are marshaled using the server-provided descriptors, so no compiled client code is needed anywhere in the loop, and the outcome comes back as serializable `GrpcInvocationResult` carrying `Success`, `StatusCode`, `StatusName`, `Detail`, and the payload. + +Every tool has edges know these three before you lean on the invoker: + +- **unary only**: client streaming and server streaming methods are reported as unsupported rather than half executed +- **unknown methods fail cleanly**: a wrong `service/method` pair returns `NotFound` in the result instead of throwing +- **relaxed TLS**: certificate validation is loosened because the host runs on development certificate exactly what you want locally, and exactly what you don't want to copy into production tooling. + +:::warning[Local only] +The invoker deliberately relaxes TLS for the host's development certificate. Calling remote production services over the same channel misses the point use full verification there. +::: + +## UI That Ships With the Plugin + +The DevTools frontend (`src/Plugins/Solutions/DevTools/UI/`) is modular TypeScript application Svelte 5 with Tailwind compiled down to single embedded resource. In practice that means the UI travels inside the plugin assembly: deploying AuthKit never involves separate static file step, and the UI version can never drift from the server version it inspects. + +### What the UI Does + +- **Service tree** sidebar with every cataloged gRPC service, browsable by package and service +- **Method invocation** pick unary method, fill the request payload, and execute it through the same `GrpcDynamicInvoker` the backend exposes +- **Proto docs** request/response shapes rendered from the server provided descriptors and doc comments, so you read the contract you actually call. + +### How It Is Built + +`vite build` bundles the app, `vite-plugin-singlefile` collapses it into one self-contained HTML file, and `scripts/finalize-ui.mjs` prepares it for embedding. Type safety is enforced up front with `svelte-check`. No separate web server, no CDN assets, no version skew: one assembly, one UI, always matching the backend it ships with. + +## How It Attaches + +`DevToolsMiddleware` follows the same rule as all plugin middleware: it answers only the paths that belong to it and lets everything else pass through untouched. Attachment happens through the host's explicit pipeline hooks, so enabling or disabling DevTools never changes how the core request path behaves see [ADR-023](/adr/023-plugin-application-pipeline-hooks/). + +## Options + +Everything above is driven by `DevToolsOptions` in the plugin's scoped configuration section: + +| Option | Default | Description | +|--------|---------|-------------| +| `PathBase` | `/devtools` | Base path for the UI and Swagger | +| `GrpcUiPathBase` | `/grpc-ui` | Base path for the gRPC UI | +| `GrpcTarget` | Override for the invoked gRPC target | +| `Swagger.RoutePrefix` | `swagger` | Swagger UI route under `PathBase` | +| `Swagger.DocumentName` | `v1` | Served OpenAPI document name | +| `Swagger.DocumentTitle` | `AuthKit API` | Swagger UI title | +| `Swagger.Enabled` | `null` (Swagger only in Development) | Toggle for the Swagger UI | + +Change path when it collides with your own routes point `GrpcTarget` elsewhere when the UI should invoke a different host than the one serving it. diff --git a/Docs/content/pl/plugins/README.md b/Docs/content/pl/plugins/README.md new file mode 100644 index 0000000..793c334 --- /dev/null +++ b/Docs/content/pl/plugins/README.md @@ -0,0 +1,9 @@ +# Wtyczki + +Rozszerzaj AuthKit bez forkowania. Wybierz wtyczkę, żeby poznać co robi, albo napisz własną za stabilnym kontraktem. + +- [DevTokens](/pl/plugins/devtokens/) wydaje i weryfikuje tokeny deweloperskie do dostępu SDK. +- [DevTools](/pl/plugins/devtools/) Swagger, eksploracja gRPC i osadzony UI w działającym serwerze. +- [Własne wtyczki](/pl/plugins/custom/) dostarczaj własne zachowanie za `IAuthKitPlugin`. + +Nowy w AuthKit? Zacznij od [Wprowadzenia](/pl/guide/introduction/). diff --git a/Docs/content/pl/plugins/custom.md b/Docs/content/pl/plugins/custom.md new file mode 100644 index 0000000..6c2931f --- /dev/null +++ b/Docs/content/pl/plugins/custom.md @@ -0,0 +1,75 @@ +# Własne wtyczki + +Każde zachowanie w AuthKit, które nie jest domeną Core ani hydrauliką hosta, przyjeżdża jako wtyczka łącznie z wbudowanymi [DevTokens](/pl/plugins/devtokens/) i [DevTools](/pl/plugins/devtools/). Napisanie własnej idzie tą samą ścieżką, co wbudowane: zaimplementuj jeden kontrakt, zadeklaruj metadane, wrzuć assembly do katalogu. Resztą zajmuje się host. + +## Dlaczego wtyczki zamiast forków + +> Centrum kosztów AuthKit to kontrakty między warstwami, nie pojedyncze klasy. Fork hosta pod własne zachowanie splątałby Twój kod z naszym przy każdej aktualizacji. Kontrakt wtyczek odwraca to: host wystawia stabilne sloty, a Twoje assembly je wypełnia bez referencji do wnętrzności hosta. Kiedy host ewoluuje, to kontrakt stoi w miejscu. + +## Kontrakt + +`IAuthKitPlugin` to interfejs partial jeden facet na zagadnienie, pogrupowane w pliki `IAuthKitPlugin*.cs`: bazowa tożsamość i akcesory metadanych, wymagania hosta, konfiguracja, health, potok, bezpieczeństwo i haki cyklu życia. Implementujesz facety, których potrzebujesz reszta przychodzi z defaultami wyliczonymi z metadanych. + +W praktyce minimalna wtyczka wygląda jak dołączony przykład: + +```csharp +[PluginMetadata( + id: "acme.audit", + version: "1.0.0", + tags: ["audit"], + dependsOn: [], + capabilities: ["audit"], + name: "Audit", + displayName: "Audit Trail", + description: "Appends audit entries for token operations.", + author: "Acme", + license: "MIT")] +public sealed class AuditPlugin : IAuthKitPlugin +{ + public void ConfigureServices(IServiceCollection services, AuthKitPluginContext context) + { + // register plugin services here and only here + } +} +``` + +Dwie reguły trzymają model w ryzach: + +- **Trzymaj się kontraktu** integrację z hostem ogranicz do tego, co wystawia kontrakt sięgniesz poza, a pęknięcie jest Twoje. +- **Rejestruj w ConfigureServices** każdą własną zależność rejestruj w `ConfigureServices` host nigdy nie podpina Twoich wnętrzności za Ciebie. + +## Metadane są nośne + +`[PluginMetadata]` to nie dekoracja. Host czyta je przed załadowaniem czegokolwiek i używa do: + +- **tożsamości** `Id` musi być niepuste, stabilne między restartami i unikalne w hoście (format i unikalność są walidowane przed aktywacją) `Version` to prawdziwy SemVer z parsowaniem i precedencją +- **prezentacji** `DisplayName ?? Name` plus `Description` lądują w outputcie startowym, diagnostyce i UI +- **możliwości** case insensitive nazwy ficzerów (`plugin.Supports("auth")`) do checków przed aktywacją i walidacji spójności po załadowaniu +- **tagów** case sensitive klasyfikacja do filtrowania w katalogach i UI. + +Klasa wtyczki bez atrybutu pada szybko z `InvalidOperationException` głośno przy starcie zamiast tajemniczo w runtime. + +:::warning[Nie omijaj kontraktu] +Sięganie poza kontrakt (refleksja we wnętrzności hosta, prywatne API) to jedyny sposób, żeby unieważnić stabilność, którą kupuje model wtyczek. Jeśli brakuje Ci slotu, rozszerz kontrakt zamiast go obchodzić. +::: + +## Z katalogu do działającego kodu + +Wrzucenie assembly do konfigurowanego katalogu startuje potok (zobacz [ADR-009](/pl/adr/009-dynamic-plugin-discovery/) i [ADR-010](/pl/adr/010-plugin-loading-from-directory/)): + +1. **Odkrycie** host skanuje katalog przy starcie nic nie wymaga referencji hosta ani rekompilacji. +2. **Manifest i bramki** metadane lądują w manifeście. `IsEnabled: false` pomija wtyczkę przed ładowaniem (żaden check spójności dla niej nie leci) przyjęte manifesty przechodzą walidację formatu, unikalności i spójności. +3. **Kolejność aktywacji** najpierw zależności (sortowanie topologiczne bije wszystko), potem `Priority` rosnąco wśród gotowych. Niższe liczby startują wcześniej default to `0`. +4. **Konfiguracja** każda wtyczka dostaje swoją zakresową sekcję konfiguracji plus dostęp do buildera hosta przez kontekst konfiguracji wtyczek ([ADR-022](/pl/adr/022-plugin-configuration-context-and-builder/)). +5. **Potok i cykl życia** endpointy i middleware wpinają się przez jawne haki ([ADR-023](/pl/adr/023-plugin-application-pipeline-hooks/)) start i stop podążają za standardowym cyklem życia hosta .NET ([ADR-024](/pl/adr/024-plugin-lifecycle-and-hosted-services/)). +6. **Health i OpenAPI** strukturalne health checki ([ADR-029](/pl/adr/029-structured-plugin-health-contract/)) i schematy bezpieczeństwa płyną do monitoringu i Swaggera DevTools automatycznie. + +## Zacznij od przykładu + +:::tip[Skopiuj, nie zaczynaj od zera] +`src/Plugins/Solutions/ExamplePlugin/` to minimalna wtyczka powitalna (`authkit.example.ExampleGreeter` przez gRPC) ćwicząca dokładnie tę ścieżkę: metadane, odkrycie, konfiguracja, endpoint. Skopiuj katalog, zmień nazwę id i rośnij z czegoś, co już się ładuje. +::: + +## Serwisy gRPC + +Wtyczki nie ograniczają się do REST: wtyczka może wystawiać własne serwisy gRPC obok hostowych, mapowane przez to samo odkrywanie. Przykładowa wtyczka robi dokładnie to z `ExampleGreeter/SayHello` zobacz [powierzchnię gRPC](/pl/reference/grpc/) i [serwisy wtyczek](/pl/reference/grpc/#Serwisy-wtyczek). diff --git a/Docs/content/pl/plugins/devtokens.md b/Docs/content/pl/plugins/devtokens.md new file mode 100644 index 0000000..dbd6bdc --- /dev/null +++ b/Docs/content/pl/plugins/devtokens.md @@ -0,0 +1,31 @@ +# DevTokens + +Wtyczka `DevTokens` (`authkit.devtokens`) wydaje, weryfikuje i autoryzuje tokeny deweloperskie do dostępu SDK. Klucze podpisujące i powiązania tokenów z kluczami pochodzą z Core hosta wtyczka jest właścicielem cyklu życia tokenów, nie infrastruktury kluczy. + +## Cykl życia tokenu + +1. **Utwórz** `POST /sdk/developer-tokens` z nazwą, zakresami i czasem życia. Zwraca podpisany JWT plus klucz `rk_live_…`. +2. **Utrwal** tokeny lądują w Marten z metadanymi (zakresy, wygaśnięcie). +3. **Zweryfikuj** `POST /sdk/tokens/verify` weryfikuje w miarę możliwości bez zapytań do bazy. +4. **Unieważnij i rotuj** `POST /sdk/tokens/{tokenId}/revoke-rotate` podmienia token jednym wywołaniem. + +Pełne kształty endpointów: [REST API Reference](/pl/reference/rest-api/). + +## Zakresy + +Tokeny niosą zakresy (np. `write:packages`). Żądania są autoryzowane względem zakresów z momentu wydania token nigdy nie rośnie ponad nie. + +## Używanie tokenów + +Wywołania SDK przedstawiają dwa poświadczenia: + +```http +Authorization: Bearer +X-Developer-Token: +``` + +Potok weryfikuje oba i egzekwuje dostęp do zakresów. Zobacz [Używanie tokenów w żądaniach SDK](/pl/reference/rest-api/#Używanie-tokenów-w-żądaniach-SDK). + +## Walidacja + +Modele żądań są walidowane przez FluentValidation zanim cokolwiek dotknie magazynu błędne payloady odpadają szybko ze szczegółami problemu RFC 7807. diff --git a/Docs/content/pl/plugins/devtools.md b/Docs/content/pl/plugins/devtools.md new file mode 100644 index 0000000..428bfca --- /dev/null +++ b/Docs/content/pl/plugins/devtools.md @@ -0,0 +1,87 @@ +# DevTools + +Kiedy AuthKit działa, nie chcesz zgadywać, co wystawia chcesz to zobaczyć. Wtyczka `DevTools` to wbudowany właz inspekcyjny serwera: hostuje narzędzia deweloperskie w działającym procesie, więc ten sam binarek, który obsługuje klientów SDK, odpowiada też na pytanie „co jest teraz naprawdę zmapowane?". + +To pytanie jest trudniejsze, niż brzmi. AuthKit składa swoją powierzchnię przy starcie z hosta i każdej odkrytej wtyczki: endpointy REST, serwisy gRPC, schematy bezpieczeństwa OpenAPI, health checki. Zameldowany plik specyfikacji zgniótłby w tydzień. DevTools omija ten problem, generując wszystko z połączonej aplikacji w runtime to, co przeglądasz, zawsze jest tym, co naprawdę tam jest. + +## Co dostajesz + +Uruchom AuthKit, a czekają trzy drzwi (wszystkie ścieżki konfigurowalne, zobacz [Opcje](#Opcje)): + + + + + +Typowa sesja płynie tak: + +1. Startujesz stos, otwierasz `/devtools/swagger` i przechodzisz endpointy tokenów z [REST API Reference](/pl/reference/rest-api/) wydajesz token deweloperski, potem go weryfikujesz, nie pisząc ani linii kodu klienta. +2. Kiedy coś zachowuje się dziwnie, przełączasz się na `/grpc-ui` i wywołujesz bazowe metody `jwks` albo `monitoring` bezpośrednio. +3. Porównujesz oba: jeśli gRPC odpowiada czysto, problem siedzi w transporcie jeśli nie głębiej. + +## Swagger z refleksji + +Za `/devtools/swagger` stoi `SwaggerHost`. Host i tak generuje dokument OpenAPI przez swój potok generowania (SwaggerGen) rolą wtyczki jest serwowanie tego dokumentu i UI z własnego wnętrza, wniesionych z powrotem do potoku hosta jak każde inne middleware. + +Liczą się tu dwa szczegóły. Po pierwsze, dokument obejmuje też endpointy i schematy bezpieczeństwa od wtyczek własna wtyczka deklarująca schemat OpenAPI pojawia się w Swaggerze bez żadnej dodatkowej pracy. Po drugie, oparte na refleksji instancje middleware budowane są raz i używane ponownie przy każdym żądaniu, więc serwowanie dokumentacji nie płaci podatku refleksji na żądanie. Zobacz [ADR-021](/pl/adr/021-swagger-serving-via-reflection/). + +:::tip[Za darmo dla Twojej wtyczki] +Jeśli piszesz własną wtyczkę, nic nie musisz robić, żeby trafiła do Swaggera wystarczy, że zadeklaruje schematy przez kontrakt. Szczegóły: [Własne wtyczki](/pl/plugins/custom/). +::: + +## Eksploracja gRPC bez klientów + +gRPC jest potężne, ale niezręczne w macaniu: zwykle potrzebujesz wygenerowanych stubów w swoim języku, zanim cokolwiek wywołasz. `GrpcServiceCatalog` usuwa to tarcie. Śledzi każdy zmapowany serwis gRPC hostowe `jwks` i `monitoring` oraz wtyczkowe wraz z deskryptorami protobuf i komentarzami dokumentacyjnymi z plików `.proto`. Z tego katalogu wywodzi się dokumentacja [powierzchni gRPC](/pl/reference/grpc/) i to po nim chodzi UI. + +`GrpcDynamicInvoker` idzie o krok dalej: realnie wykonuje unarne wywołania odkryte przez katalog. Wiadomości są marszalowane przez deskryptory dostarczone przez serwer, więc nigdzie w pętli nie potrzeba kompilowanego kodu klienta, a wynik wraca jako serializowalny `GrpcInvocationResult` z `Success`, `StatusCode`, `StatusName`, `Detail` i payloadem. + +Każde narzędzie ma krawędzie poznaj te trzy, zanim oprzesz się na invokerze: + +- **tylko unarne**: metody strumieniowe klient/serwer zgłaszane są jako niewspierane zamiast być wykonane do połowy +- **nieznane metody padają czysto**: zła para `serwis/metoda` zwraca `NotFound` w wyniku zamiast rzucać +- **poluzowany TLS**: walidacja certyfikatów jest poluzowana, bo host jedzie na certyfikacie deweloperskim dokładnie to, czego chcesz lokalnie, i dokładnie to, czego nie chcesz kopiować do produkcyjnych narzędzi. + +:::warning[Tylko lokalnie] +Invoker celowo luzuje TLS pod certyfikat deweloperski hosta. Wołanie zdalnych, produkcyjnych serwisów tym samym kanałem mija się z celem — tam używaj pełnej weryfikacji. +::: + +## UI podróżujące z wtyczką + +Frontend DevTools (`src/Plugins/Solutions/DevTools/UI/`) to modularna aplikacja TypeScript Svelte 5 z Tailwindem kompilowana do pojedynczego osadzonego zasobu. W praktyce znaczy to, że UI podróżuje wewnątrz assembly wtyczki: deploy AuthKit nigdy nie wymaga osobnego kroku plików statycznych, a wersja UI nie może rozjechać się z wersją serwera, który inspekcjonuje. + +### Co potrafi UI + +- **Drzewo serwisów** sidebar z każdym skatalogowanym serwisem gRPC, przeglądany po pakietach i serwisach +- **Wywoływanie metod** wybierz metodę unarną, wypełnij payload żądania i wykonaj przez ten sam `GrpcDynamicInvoker`, który wystawia backend +- **Dokumentacja proto** kształty żądań i odpowiedzi renderowane z deskryptorów i komentarzy serwera, więc czytasz kontrakt, który realnie wołasz. + +### Jak jest budowane + +`vite build` bundluje aplikację, `vite-plugin-singlefile` zwija ją do jednego samowystarczalnego pliku HTML, a `scripts/finalize-ui.mjs` przygotowuje go do osadzenia. Bezpieczeństwo typów jest egzekwowane z góry przez `svelte-check`. Żadnego osobnego serwera www, żadnych assetów z CDN, żadnego dryfu wersji: jedno assembly, jedno UI, zawsze zgodne z backendem, z którym płynie. + +## Jak to się podpina + +`DevToolsMiddleware` podąża za tą samą regułą co każde middleware wtyczek: odpowiada tylko na należące do niego ścieżki, resztę przepuszcza dalej nietkniętą. Podpięcie dzieje się przez jawne haki potoku hosta, więc włączanie i wyłączanie DevTools nigdy nie zmienia zachowania bazowej ścieżki żądań zobacz [ADR-023](/pl/adr/023-plugin-application-pipeline-hooks/). + +## Opcje + +Wszystkim powyżej steruje `DevToolsOptions` w zakresowej sekcji konfiguracji wtyczki: + +| Opcja | Domyślnie | Opis | +|-------|------------|------| +| `PathBase` | `/devtools` | Bazowa ścieżka UI i Swaggera | +| `GrpcUiPathBase` | `/grpc-ui` | Bazowa ścieżka UI gRPC | +| `GrpcTarget` | — | Nadpisanie docelowego adresu gRPC | +| `Swagger.RoutePrefix` | `swagger` | Ścieżka Swagger UI pod `PathBase` | +| `Swagger.DocumentName` | `v1` | Nazwa serwowanego dokumentu OpenAPI | +| `Swagger.DocumentTitle` | `AuthKit API` | Tytuł Swagger UI | +| `Swagger.Enabled` | `null` (Swagger tylko w Development) | Przełącznik Swagger UI | + +Zmień ścieżkę, kiedy koliduje z Twoimi trasami wskaż `GrpcTarget` gdzie indziej, kiedy UI ma wołać innego hosta niż ten, który je serwuje. From aaf7eab60b52dc89d89576ccb50f0a451e907e8f Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:57:47 +0200 Subject: [PATCH 05/17] docs: add AuthKit introduction and quick-start guides --- Docs/content/en/guide/configuration.md | 113 +++++++++++++++++++++ Docs/content/en/guide/introduction.md | 121 ++++++++++++++++++++++ Docs/content/en/guide/quick-start.md | 134 +++++++++++++++++++++++++ Docs/content/pl/guide/configuration.md | 113 +++++++++++++++++++++ Docs/content/pl/guide/introduction.md | 121 ++++++++++++++++++++++ Docs/content/pl/guide/quick-start.md | 134 +++++++++++++++++++++++++ 6 files changed, 736 insertions(+) create mode 100644 Docs/content/en/guide/configuration.md create mode 100644 Docs/content/en/guide/introduction.md create mode 100644 Docs/content/en/guide/quick-start.md create mode 100644 Docs/content/pl/guide/configuration.md create mode 100644 Docs/content/pl/guide/introduction.md create mode 100644 Docs/content/pl/guide/quick-start.md diff --git a/Docs/content/en/guide/configuration.md b/Docs/content/en/guide/configuration.md new file mode 100644 index 0000000..23d00bd --- /dev/null +++ b/Docs/content/en/guide/configuration.md @@ -0,0 +1,113 @@ +# Configuration + +AuthKit is configured through environment variables and `appsettings.json`. + +## Environment Variables + +| Variable | Description | Default | +|----------|-------------|---------| +| `KEYCLOAK_URL` | Keycloak base URL | `http://keycloak:8080` | +| `KEYCLOAK_REALM` | Keycloak realm | `authz` | +| `KEYCLOAK_CLIENT_ID` | Keycloak client ID | `workspace-authz` | +| `KEYCLOAK_CLIENT_SECRET` | Keycloak client secret | _required_ | +| `DEV_CERT_PATH` | Path to dev HTTPS certificate (pfx) | `/root/certs/devcert.pfx` | +| `DEV_CERT_PASSWORD` | Password for dev certificate | _empty_ | +| `DEV_CERT_PORT_REST` | Kestrel REST listener port | `5000` | +| `DEV_CERT_PORT_GRPC` | Kestrel gRPC listener port | `5001` | + +## Key Configuration Sections + +### Connection Strings + +```json +{ + "ConnectionStrings": { + "Marten": "Host=authdev-db;Port=5432;Database=AuthDev;Username=postgres;Password=postgres" + } +} +``` + +### Encryption + +```json +{ + "Encryption": { + "AES_MASTER_KEY": "your-256-bit-base64-encoded-aes-master-key" + } +} +``` + +### Server + +```json +{ + "Server": { + "Host": "http://0.0.0.0:8080", + "Issuer": "https://authkit.local" + } +} +``` + +### AuthKit Settings + +Per-plugin scoped sections under `Plugins` (e.g. DevTokens): + +```json +{ + "Plugins": { + "authkit.devtokens": { + "MaxDeveloperTokens": 3 + } + }, + "AuthKit": { + "PluginsPath": "./plugins" + } +} +``` + +### Service Discovery + +```json +{ + "ServiceDiscovery": { + "EnableLogging": false, + "AllowedNamespaces": [".Services", ".Repositories"], + "ExcludedNamespaces": [".DTO", ".Entity"], + "AllowedLayers": ["Core", "Host"], + "SkipInterfaces": true, + "SkipExceptions": true, + "Lifetime": "Scoped" + } +} +``` + +## Wolverine + +Command/query handling, validation, and durability live on their own page: [Wolverine](/infrastructure/wolverine/). + +## Marten + +Document store, plugin schemas, and sessions live on their own page: [Marten + PostgreSQL](/infrastructure/marten/). + +## Custom Configuration + +Create an `appsettings.Production.json` for production settings: + +```json +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "Plugins": { + "authkit.devtokens": { + "MaxDeveloperTokens": 10 + } + } +} +``` + +:::note +The `appsettings.json` in the project root provides sensible defaults for development. +::: \ No newline at end of file diff --git a/Docs/content/en/guide/introduction.md b/Docs/content/en/guide/introduction.md new file mode 100644 index 0000000..94f2e81 --- /dev/null +++ b/Docs/content/en/guide/introduction.md @@ -0,0 +1,121 @@ +# Introduction + +AuthKit is a **plugin-based service** for handling **developer authentication, SDK token issuance, and access verification**. + +It ensures that only authorized developers can access SDK methods and provides a secure, auditable token-based authentication mechanism. + + + + + +## How AuthKit Works + + + +## Transports + +Pick how SDK clients talk to AuthKit. + + + +## Infrastructure + +AuthKit stands on proven building blocks, composed by the Host. + + + +## Plugins & Tools + +Extend behavior or inspect the running server. + + + +## Quick Start + +1. Start the AuthKit service with Docker +2. Configure Keycloak +3. Create developer tokens for SDK access +4. Use tokens to authenticate SDK requests + +:::tip[Recommended path] +Continue to the [Quick Start](/guide/quick-start/) guide to get running in minutes. +::: + +## Architecture + +AuthKit is composed of three layers: + +### Core + +Shared domain, JWT signing-key management (RSA key generation, AES encryption, on-disk keystore), token key bindings, and core options. + +### Host + +ASP.NET Core host running on Kestrel. Provides Wolverine (command/query handling), Marten (PostgreSQL event/document store), RESTful and gRPC endpoints, Keycloak integration, CLI, and dynamic plugin loading. + +### Plugins + +Extensions discovered and loaded dynamically from the `plugins/` directory. Plugins contribute services, middleware, health checks, and OpenAPI security schemes through the `IAuthKitPlugin` contract. + +```text +src/ +├── Core/ # Domain, key management, options +├── Host/ # Web host, REST/gRPC, CLI, plugin loader +│ ├── Configuration/ # Auth, Keycloak, Kestrel, Marten, ServiceDiscovery +│ ├── Grpc/ # gRPC services and protos +│ ├── KeyManagement/ # JWKS endpoint, key store initializer +│ ├── Restful/ # Host-level middleware +│ └── ServiceDiscovery/ # Automatic DI registration +└── Plugins/ + ├── Abstractions/ # IAuthKitPlugin contract + └── Solutions/ # Plugin implementations (e.g. DevTokens) +``` + +## Built-in Plugins + +### DevTokens + +Issues and validates developer tokens for SDK access. + +## REST API Reference + +| Method | Route | Description | +|--------|-------|-------------| +| `POST` | `sdk/developer-tokens` | Create a developer token | +| `GET` | `sdk/developer-tokens` | List developer tokens | +| `GET` | `sdk/developer-tokens/{tokenId}` | Get a token by ID | +| `DELETE` | `sdk/developer-tokens/{tokenId}` | Delete a token | +| `POST` | `sdk/tokens/verify` | Verify a developer token | +| `POST` | `sdk/tokens/{tokenId}/revoke-rotate` | Revoke and rotate a token | + +## Next Steps + +1. [Quick Start](/guide/quick-start/) +2. [REST API Reference](/reference/rest-api/) +3. [Configuration](/guide/configuration/) diff --git a/Docs/content/en/guide/quick-start.md b/Docs/content/en/guide/quick-start.md new file mode 100644 index 0000000..eb7c306 --- /dev/null +++ b/Docs/content/en/guide/quick-start.md @@ -0,0 +1,134 @@ +# Quick Start + +Get AuthKit up and running in minutes — from zero to a verified token. If you prefer the big picture first, start with [Introduction](/guide/introduction/). + +## Prerequisites + +- [Docker](https://docs.docker.com/get-docker/) installed (the recommended path). +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) — only for local development without Docker. +- Free ports: `5000`, `5001`, `8081`, `5433`, `5434`. + +## Step 0: The .env File + +All secret configuration lives in `.env`, which is never committed: + +```bash +cp .env.example .env +``` + +Minimum to change before the first start: + +- `DEV_CERT_PASSWORD` — password for the dev HTTPS certificate; +- `KEYCLOAK_CLIENT_SECRET` — Keycloak client secret. + +The rest works on defaults. Full variable map: [Docker + Kestrel](/infrastructure/docker/). + +## Option 1: Run with Docker (Recommended) + +```bash +docker compose up --build +``` + +This starts AuthKit with PostgreSQL (Keycloak joins via the `keycloak` profile). The first start builds images and runs storage migration — it takes a while; later starts are fast. + +### Ports + +| Service | Port | Purpose | +|---------|------|---------| +| AuthKit REST | `5000` | REST API (HTTPS) | +| AuthKit gRPC | `5001` | gRPC API (HTTPS) | +| Keycloak | `8081` | Identity provider (HTTP) | +| PostgreSQL (AuthKit) | `5434` | AuthKit database | + +### Keycloak Setup + +1. Open http://localhost:8081 +2. Login with admin/admin +3. Import the realm from `Deploy/Keycloak/realms/realm-authz.json` +4. Confirm the `authz` realm exists with the `workspace-authz` client + +Without the imported realm, developer sign-in won't work — the most common cause of 401s on a fresh stack. + +## Option 2: Run Locally + +For development without Docker: + +```bash +# Restore dependencies +dotnet restore AuthKit.slnx + +# Build +dotnet build AuthKit.slnx --configuration Release + +# Run the host +dotnet run --project src/Host/Host.csproj +``` + +Default listen address: `http://0.0.0.0:8080` (HTTP/2). PostgreSQL and Keycloak must be reachable separately — easiest is to run just the databases from compose and the host locally. + +For code iteration use the watcher: + +```bash +dotnet watch run --project src/Host/Host.csproj +``` + +## Verify Everything Works + +Check the health endpoint: + +```bash +curl -k https://localhost:5000/health +``` + +Expected response: +```json +{ + "status": "Healthy", + "totalDuration": "00:00:00.1234560", + "componentDurations": { + "AuthKitPlugins": "Healthy", + "Marten": "Healthy" + } +} +``` + +Also glance at `docker compose ps` — every service should be `healthy` or `running`. + +## First End-to-End Session + +With health green, close the full loop in 5 minutes: + +1. Open Swagger on the running host: `https://localhost:5000/devtools/swagger`. +2. Sign in to Keycloak (http://localhost:8081, `admin` / `admin`) and copy your access token. +3. In Swagger, call `POST /sdk/developer-tokens` with the Keycloak token in `Authorize` — you get a developer JWT plus an `rk_live_…` key. +4. Call `POST /sdk/tokens/verify` with that JWT — a `"valid": true` response closes the loop. + +Only now do you have the working chain: Keycloak → AuthKit → SDK token → verification. + +## Stopping and Cleaning + +```bash +docker compose stop # stop, everything stays +docker compose down # stop, containers gone, data stays +docker compose down -v # stop + wipe volumes (fresh database, new keys!) +``` + +:::warning[down -v wipes keys] +After dropping volumes the keystore is new — previously issued tokens stop verifying. +::: + +## Troubleshooting + +- **Containers are up but health doesn't answer** — wait for `healthy` in `docker compose ps`; `auth` only starts after a healthy database. +- **Keycloak empty after startup** — the `keycloak` profile wasn't enabled (`docker compose --profile keycloak up`) or the realm file is missing. +- **Certificate error on startup** — wrong `DEV_CERT_PASSWORD` or missing `./certs`; read the `auth` logs. +- **401 from Swagger** — missing or wrong Keycloak token in `Authorize`; SDK tokens don't replace the Keycloak bearer. +- **Port in use** — something sits on `5000`/`8081`/`5434`; stop it or remap the left side of `ports`. +- **Clean reset** — `docker compose down -v` wipes the databases and starts everything from zero (tokens go too). + +## Next Steps + +1. [Configure Keycloak](/guide/configuration/) +2. [Create a developer token](/reference/rest-api/) +3. [Explore the REST API](/reference/rest-api/) +4. [Docker + Kestrel](/infrastructure/docker/) — full stack lifecycle diff --git a/Docs/content/pl/guide/configuration.md b/Docs/content/pl/guide/configuration.md new file mode 100644 index 0000000..bc8f303 --- /dev/null +++ b/Docs/content/pl/guide/configuration.md @@ -0,0 +1,113 @@ +# Konfiguracja + +AuthKit konfiguruje się przez zmienne środowiskowe i `appsettings.json`. + +## Zmienne środowiskowe + +| Zmienna | Opis | Domyślnie | +|---------|------|-----------| +| `KEYCLOAK_URL` | Bazowy URL Keycloak | `http://keycloak:8080` | +| `KEYCLOAK_REALM` | Realm Keycloak | `authz` | +| `KEYCLOAK_CLIENT_ID` | ID klienta Keycloak | `workspace-authz` | +| `KEYCLOAK_CLIENT_SECRET` | Sekret klienta Keycloak | _wymagany_ | +| `DEV_CERT_PATH` | Ścieżka do deweloperskiego certyfikatu HTTPS (pfx) | `/root/certs/devcert.pfx` | +| `DEV_CERT_PASSWORD` | Hasło do certyfikatu deweloperskiego | _puste_ | +| `DEV_CERT_PORT_REST` | Port nasłuchu Kestrel REST | `5000` | +| `DEV_CERT_PORT_GRPC` | Port nasłuchu Kestrel gRPC | `5001` | + +## Kluczowe sekcje konfiguracji + +### Connection Strings + +```json +{ + "ConnectionStrings": { + "Marten": "Host=authdev-db;Port=5432;Database=AuthDev;Username=postgres;Password=postgres" + } +} +``` + +### Szyfrowanie + +```json +{ + "Encryption": { + "AES_MASTER_KEY": "twój-256-bitowy-klucz-aes-zakodowany-base64" + } +} +``` + +### Serwer + +```json +{ + "Server": { + "Host": "http://0.0.0.0:8080", + "Issuer": "https://authkit.local" + } +} +``` + +### Ustawienia AuthKit + +Sekcje zakresowe per plugin pod `Plugins` (np. DevTokens): + +```json +{ + "Plugins": { + "authkit.devtokens": { + "MaxDeveloperTokens": 3 + } + }, + "AuthKit": { + "PluginsPath": "./plugins" + } +} +``` + +### Service Discovery + +```json +{ + "ServiceDiscovery": { + "EnableLogging": false, + "AllowedNamespaces": [".Services", ".Repositories"], + "ExcludedNamespaces": [".DTO", ".Entity"], + "AllowedLayers": ["Core", "Host"], + "SkipInterfaces": true, + "SkipExceptions": true, + "Lifetime": "Scoped" + } +} +``` + +## Wolverine + +Obsługa komend/zapytań, walidacja i trwałość żyją na osobnej stronie: [Wolverine](/pl/infrastructure/wolverine/). + +## Marten + +Magazyn dokumentów, schematy wtyczek i sesje żyją na osobnej stronie: [Marten + PostgreSQL](/pl/infrastructure/marten/). + +## Własna konfiguracja + +Utwórz `appsettings.Production.json` dla ustawień produkcyjnych: + +```json +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "Plugins": { + "authkit.devtokens": { + "MaxDeveloperTokens": 10 + } + } +} +``` + +:::note +`appsettings.json` w katalogu głównym projektu zawiera sensowne wartości domyślne do rozwoju. +::: diff --git a/Docs/content/pl/guide/introduction.md b/Docs/content/pl/guide/introduction.md new file mode 100644 index 0000000..2c63167 --- /dev/null +++ b/Docs/content/pl/guide/introduction.md @@ -0,0 +1,121 @@ +# Wprowadzenie + +AuthKit to **wtyczkowa usługa** do **uwierzytelniania deweloperów, wydawania tokenów SDK oraz weryfikacji dostępu**. + +Zapewnia, że tylko autoryzowani deweloperzy mają dostęp do metod SDK, oraz dostarcza bezpieczny, audytowalny mechanizm uwierzytelniania oparty na tokenach. + + + + + +## Jak działa AuthKit + + + +## Transporty + +Wybierz, jak klienci SDK komunikują się z AuthKit. + + + +## Infrastruktura + +AuthKit stoi na sprawdzonych klockach, składanych przez host. + + + +## Wtyczki i narzędzia + +Rozszerzaj zachowanie albo podglądaj działający serwer. + + + +## Szybki start + +1. Uruchom usługę AuthKit z Dockerem +2. Skonfiguruj Keycloak +3. Utwórz tokeny deweloperskie do dostępu SDK +4. Używaj tokenów do uwierzytelniania żądań SDK + +:::tip[Rekomendowana ścieżka] +Przejdź do przewodnika [Szybki start](/pl/guide/quick-start/), aby ruszyć w kilka minut. +::: + +## Architektura + +AuthKit składa się z trzech warstw: + +### Core + +Współdzielona domena, zarządzanie kluczami podpisującymi JWT (generowanie kluczy RSA, szyfrowanie AES, magazyn na dysku), powiązania kluczy tokenów oraz opcje Core. + +### Host + +Host ASP.NET Core na Kestrelu. Dostarcza Wolverine (obsługa komend/zapytań), Marten (magazyn eventów/dokumentów PostgreSQL), endpointy REST i gRPC, integrację Keycloak, CLI oraz dynamiczne ładowanie wtyczek. + +### Plugins + +Rozszerzenia odkrywane i ładowane dynamicznie z katalogu `plugins/`. Wtyczki wnoszą usługi, oprogramowanie pośredniczące, health checki oraz schematy bezpieczeństwa OpenAPI poprzez kontrakt `IAuthKitPlugin`. + +```text +src/ +├── Core/ # Domena, zarządzanie kluczami, opcje +├── Host/ # Host webowy, REST/gRPC, CLI, ładowanie wtyczek +│ ├── Configuration/ # Auth, Keycloak, Kestrel, Marten, ServiceDiscovery +│ ├── Grpc/ # Usługi i protos gRPC +│ ├── KeyManagement/ # Endpoint JWKS, inicjalizacja magazynu kluczy +│ ├── Restful/ # Oprogramowanie pośredniczące hosta +│ └── ServiceDiscovery/ # Automatyczna rejestracja DI +└── Plugins/ + ├── Abstractions/ # Kontrakt IAuthKitPlugin + └── Solutions/ # Implementacje wtyczek (np. DevTokens) +``` + +## Wbudowane wtyczki + +### DevTokens + +Wydaje i weryfikuje tokeny deweloperskie do dostępu SDK. + +## REST API Reference + +| Method | Route | Description | +|--------|-------|-------------| +| `POST` | `sdk/developer-tokens` | Utwórz token deweloperski | +| `GET` | `sdk/developer-tokens` | Lista tokenów deweloperskich | +| `GET` | `sdk/developer-tokens/{tokenId}` | Pobierz token po ID | +| `DELETE` | `sdk/developer-tokens/{tokenId}` | Usuń token | +| `POST` | `sdk/tokens/verify` | Zweryfikuj token deweloperski | +| `POST` | `sdk/tokens/{tokenId}/revoke-rotate` | Unieważnij i rotuj token | + +## Następne kroki + +1. [Szybki start](/pl/guide/quick-start/) +2. [REST API Reference](/pl/reference/rest-api/) +3. [Konfiguracja](/pl/guide/configuration/) diff --git a/Docs/content/pl/guide/quick-start.md b/Docs/content/pl/guide/quick-start.md new file mode 100644 index 0000000..6737f30 --- /dev/null +++ b/Docs/content/pl/guide/quick-start.md @@ -0,0 +1,134 @@ +# Szybki start + +Uruchom AuthKit w kilka minut — od zera do zweryfikowanego tokenu. Jeśli wolisz najpierw zrozumieć całość, zacznij od [Wprowadzenia](/pl/guide/introduction/). + +## Wymagania wstępne + +- Zainstalowany [Docker](https://docs.docker.com/get-docker/) (zalecana ścieżka). +- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) — tylko do rozwoju lokalnego bez Dockera. +- Wolne porty: `5000`, `5001`, `8081`, `5433`, `5434`. + +## Krok 0: Plik .env + +Cała konfiguracja sekretów żyje w `.env`, którego nigdy nie commitujesz: + +```bash +cp .env.example .env +``` + +Minimum do zmiany przed pierwszym startem: + +- `DEV_CERT_PASSWORD` — hasło do deweloperskiego certyfikatu HTTPS; +- `KEYCLOAK_CLIENT_SECRET` — sekret klienta Keycloak. + +Reszta działa na defaultach. Pełna mapa zmiennych: [Docker + Kestrel](/pl/infrastructure/docker/). + +## Opcja 1: Uruchomienie przez Docker (zalecane) + +```bash +docker compose up --build +``` + +Stawia AuthKit wraz z PostgreSQL (Keycloak dokłada profil `keycloak`). Pierwszy start buduje obrazy i robi migrację storage — potrwa chwilę, kolejne starty są szybkie. + +### Porty + +| Usługa | Port | Przeznaczenie | +|--------|------|---------------| +| AuthKit REST | `5000` | REST API (HTTPS) | +| AuthKit gRPC | `5001` | gRPC API (HTTPS) | +| Keycloak | `8081` | Dostawca tożsamości (HTTP) | +| PostgreSQL (AuthKit) | `5434` | Baza danych AuthKit | + +### Konfiguracja Keycloak + +1. Otwórz http://localhost:8081 +2. Zaloguj się admin/admin +3. Zaimportuj realm z `Deploy/Keycloak/realms/realm-authz.json` +4. Potwierdź, że realm `authz` istnieje i ma klienta `workspace-authz` + +Bez zaimportowanego realm logowanie deweloperów nie zadziała — to najczęstszy powód 401 na świeżym stosie. + +## Opcja 2: Uruchomienie lokalne + +Do rozwoju bez Dockera: + +```bash +# Przywróć zależności +dotnet restore AuthKit.slnx + +# Zbuduj +dotnet build AuthKit.slnx --configuration Release + +# Uruchom hosta +dotnet run --project src/Host/Host.csproj +``` + +Domyślny adres nasłuchu: `http://0.0.0.0:8080` (HTTP/2). PostgreSQL i Keycloak muszą być osiągalne osobno — najprościej postawić same bazy z compose, a hosta lokalnie. + +Do iteracji nad kodem użyj watchera: + +```bash +dotnet watch run --project src/Host/Host.csproj +``` + +## Sprawdź, czy wszystko działa + +Sprawdź endpoint health: + +```bash +curl -k https://localhost:5000/health +``` + +Oczekiwana odpowiedź: +```json +{ + "status": "Healthy", + "totalDuration": "00:00:00.1234560", + "componentDurations": { + "AuthKitPlugins": "Healthy", + "Marten": "Healthy" + } +} +``` + +Zerknij też na `docker compose ps` — każdy serwis ma być `healthy` albo `running`. + +## Pierwsza sesja end-to-end + +Skoro health jest zielony, zrób pełne kółko w 5 minut: + +1. Otwórz Swagger na działającym hoście: `https://localhost:5000/devtools/swagger`. +2. Zaloguj się do Keycloak (http://localhost:8081, `admin` / `admin`) i skopiuj swój token dostępowy. +3. W Swaggerze wywołaj `POST /sdk/developer-tokens` z tokenem Keycloak w `Authorize` — dostaniesz JWT deweloperski plus klucz `rk_live_…`. +4. Wywołaj `POST /sdk/tokens/verify` z tym JWT — odpowiedź `"valid": true` zamyka pętlę. + +Dopiero teraz masz działający łańcuch: Keycloak → AuthKit → token SDK → weryfikacja. + +## Zatrzymywanie i czyszczenie + +```bash +docker compose stop # stop, wszystko zostaje +docker compose down # stop, kontenery precz, dane zostają +docker compose down -v # stop + kasowanie volumów (świeża baza, nowe klucze!) +``` + +:::warning[down -v kasuje klucze] +Po wywaleniu volumów magazyn kluczy jest nowy — wcześniej wydane tokeny przestają się weryfikować. +::: + +## Rozwiązywanie problemów + +- **Kontenery wstają, ale health nie odpowiada** — poczekaj na `healthy` w `docker compose ps`; `auth` startuje dopiero po zdrowej bazie. +- **Keycloak pusty po starcie** — profil `keycloak` nie włączony (`docker compose --profile keycloak up`) albo brak pliku realm. +- **Błąd certyfikatu przy starcie** — złe `DEV_CERT_PASSWORD` albo brak `./certs`; szczegóły w logach `auth`. +- **401 ze Swaggera** — brak lub zły token Keycloak w `Authorize`; tokeny SDK nie zastępują bearer Keycloak. +- **Port zajęty** — coś siedzi na `5000`/`8081`/`5434`; zatrzymaj albo przemapuj lewą stronę `ports`. +- **Czysty reset** — `docker compose down -v` kasuje bazy i stawia wszystko od zera (tokeny też przepadają). + +## Następne kroki + +1. [Skonfiguruj Keycloak](/pl/guide/configuration/) +2. [Utwórz token deweloperski](/pl/reference/rest-api/) +3. [Poznaj REST API](/pl/reference/rest-api/) +4. [Docker + Kestrel](/pl/infrastructure/docker/) — pełny cykl życia stosu From 863dfe224aa29fbadd048c51168e5b7dd1756b0e Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:58:54 +0200 Subject: [PATCH 06/17] docs: add REST and gRPC API references --- Docs/content/en/reference/grpc.md | 90 +++++++++++ Docs/content/en/reference/rest-api.md | 219 ++++++++++++++++++++++++++ Docs/content/pl/reference/grpc.md | 90 +++++++++++ Docs/content/pl/reference/rest-api.md | 219 ++++++++++++++++++++++++++ 4 files changed, 618 insertions(+) create mode 100644 Docs/content/en/reference/grpc.md create mode 100644 Docs/content/en/reference/rest-api.md create mode 100644 Docs/content/pl/reference/grpc.md create mode 100644 Docs/content/pl/reference/rest-api.md diff --git a/Docs/content/en/reference/grpc.md b/Docs/content/en/reference/grpc.md new file mode 100644 index 0000000..996b289 --- /dev/null +++ b/Docs/content/en/reference/grpc.md @@ -0,0 +1,90 @@ +# gRPC Reference + +AuthKit exposes a gRPC surface next to REST from the same host pipeline (see [ADR-013](/adr/013-dual-rest-and-grpc-transport/)). Use it for backend-to-backend calls where contract-first protobuf and streaming-friendly transport pay off. + +Proto sources live in `src/Host/Grpc/protos/` (`jwks.proto`, `monitoring.proto`); plugins can contribute their own services the same way. + +## Services + +| Service | Package | Description | +|---------|---------|-------------| +| [`Jwks`](#Jwks-Service) | `jwks` | Public signing keys, single-key lookup, health and stats | +| [`Monitoring`](#Monitoring-Service) | `monitoring` | Aggregate host health and process metrics | + +## Jwks Service + +Public signing keys in JWKS shape — the same data the REST layer serves, projected through protobuf. + +```proto +service Jwks { + rpc GetJwks (google.protobuf.Empty) returns (JwksResponse); + rpc GetKeyByKid (KeyLookupRequest) returns (SingleKeyResponse); + rpc GetJwksHealth (google.protobuf.Empty) returns (HealthResponse); + rpc GetJwksStats (google.protobuf.Empty) returns (KeyStoreStatsResponse); +} +``` + +### GetJwks + +Returns all active (non-revoked) public signing keys. + +**Request:** `google.protobuf.Empty` + +**Response:** `JwksResponse` with repeated `Jwk` (`kty`, `use`, `kid`, `alg`, `n`, `e`, `x5c`). + +### GetKeyByKid + +Returns a single key by its key ID together with lifecycle metadata. + +**Request:** + +```proto +message KeyLookupRequest { + string kid = 1; +} +``` + +**Response:** `SingleKeyResponse` (`Jwk key`, `KeyMetadata metadata` with `kid`, `created_at`, `revoked`, `algorithm`, `purpose`). + +### GetJwksHealth + +Health status of the JWKS key store: `status`, `available_keys`, `active_key_id`, `details` map, `timestamp`. + +### GetJwksStats + +Key store statistics for monitoring: `total_keys`, oldest/newest key age, `key_ids`, `timestamp`. + +## Monitoring Service + +```proto +service Monitoring { + rpc GetHealth (google.protobuf.Empty) returns (MonitoringHealthResponse); + rpc GetMetrics (google.protobuf.Empty) returns (MetricsResponse); +} +``` + +### GetHealth + +Aggregate health of the host and its plugins: `status`, `time`, `jwt_key_store_healthy`, repeated `PluginHealth` (name + check results with status, reason, tags, data). + +### GetMetrics + +Process metrics: `uptime_seconds`, `process_start_unix_time`, `time`. + +## Calling with grpcurl + +```bash +grpcurl --insecure localhost:5001 list +grpcurl --insecure localhost:5001 jwks.Jwks/GetJwks +grpcurl --insecure -d '{"kid": ""}' localhost:5001 jwks.Jwks/GetKeyByKid +``` + +Replace `localhost:5001` with your Kestrel endpoint from [Configuration](/guide/configuration/). Kestrel serves HTTPS by default when a dev certificate exists (`DEV_CERT_PATH`); use `--insecure` for the dev cert, or plain `-plaintext` only when no certificate is configured (HTTP fallback). + +## Authentication + +gRPC calls go through the same global interceptors as the rest of the pipeline. Pass the Keycloak JWT the same way the REST surface expects it (bearer token) — see [Authentication](/reference/rest-api/#authentication). + +## Plugin Services + +Plugins can expose their own gRPC services next to the host ones (eg. the example `authkit.example.ExampleGreeter` with `SayHello`). They are discovered and mapped together with host endpoints — see [ADR-009](/adr/009-dynamic-plugin-discovery/). diff --git a/Docs/content/en/reference/rest-api.md b/Docs/content/en/reference/rest-api.md new file mode 100644 index 0000000..3bd1779 --- /dev/null +++ b/Docs/content/en/reference/rest-api.md @@ -0,0 +1,219 @@ +# REST API Reference + +AuthKit exposes both REST and gRPC endpoints for token management and verification. + +## Authentication + +All API endpoints require authentication via **Keycloak JWT bearer token** in the `Authorization` header. + +```http +Authorization: Bearer +``` + +## Developer Tokens API + +### Create Developer Token + +Creates a new developer token for the authenticated user. + +**Endpoint:** `POST /sdk/developer-tokens` + +**Headers:** +| Header | Value | +|--------|-------| +| `Authorization` | `Bearer ` | +| `Content-Type` | `application/json` | + +**Request Body:** +```json +{ + "name": "My SDK Token", + "description": "Token for accessing marketplace API", + "scopes": ["read:products", "write:products"], + "lifetimeDays": 7 +} +``` + +**Response (200):** +```json +{ + "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMzQ1Njc4OTAifQ...", + "key": "rk_live_xxx", + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "scopes": ["read:products", "write:products"], + "lifetime": { + "createdAt": "2024-01-15T10:30:00Z", + "expiresAt": "2024-01-22T10:30:00Z" + } +} +``` + +--- + +### List Developer Tokens + +Lists all developer tokens belonging to the authenticated user. + +**Endpoint:** `GET /sdk/developer-tokens` + +**Headers:** +| Header | Value | +|--------|-------| +| `Authorization` | `Bearer ` | + +**Response (200):** +```json +[ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "name": "Production SDK Token", + "scopes": ["read:products"], + "createdAt": "2024-01-10T08:00:00Z", + "expiresAt": "2024-02-10T08:00:00Z", + "isExpired": false + } +] +``` + +--- + +### Get Developer Token by ID + +Retrieves a specific developer token by its ID. + +**Endpoint:** `GET /sdk/developer-tokens/{tokenId}` + +**Headers:** +| Header | Value | +|--------|-------| +| `Authorization` | `Bearer ` | + +**Response (200):** +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "name": "My SDK Token", + "scopes": ["read:products", "write:products"], + "createdAt": "2024-01-15T10:30:00Z", + "expiresAt": "2024-01-22T10:30:00Z", + "isExpired": false +} +``` + +**Error (404):** Token not found + +--- + +### Delete Developer Token + +Deletes a developer token by its ID. + +**Endpoint:** `DELETE /sdk/developer-tokens/{tokenId}` + +**Headers:** +| Header | Value | +|--------|-------| +| `Authorization` | `Bearer ` | + +**Response (200):** +``` +Token deleted successfully +``` + +--- + +## Token Verification API + +### Verify Token + +Verifies a developer token against its persisted token data. This endpoint is anonymous (no `Authorization` header required). + +**Endpoint:** `POST /sdk/tokens/verify` + +**Request Body:** +```json +{ + "key": "rk_live_xxx" +} +``` + +**Response (200):** +```json +true +``` + +--- + +### Revoke and Rotate Token + +Revokes an existing token and generates a replacement. Requires the `User` role (`Authorization: Bearer ` with `User` role claim). + +**Endpoint:** `POST /sdk/tokens/{tokenId}/revoke-rotate` + +**Headers:** +| Header | Value | +|--------|-------| +| `Authorization` | `Bearer ` | + +**Response (200):** +```json +{ + "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjY4ODkwMTIzNDU2fQ...", + "key": "rk_live_yyy", + "tokenId": "660e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "scopes": ["read:products", "write:products"], + "lifetime": { + "createdAt": "2024-01-16T10:30:00Z", + "expiresAt": "2024-01-23T10:30:00Z" + } +} +``` + +## Error Responses + +### 401 Unauthorized +```json +{ + "type": "https://tools.ietf.org/html/rfc7235#section-3.1", + "title": "Unauthorized", + "status": 401, + "detail": "Authentication credentials are missing or invalid." +} +``` + +### 404 Not Found +```json +{ + "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4", + "title": "Not Found", + "status": 404, + "detail": "The requested resource was not found." +} +``` + +### 403 Forbidden +```json +{ + "type": "https://tools.ietf.org/html/rfc7231#section-6.5.3", + "title": "Forbidden", + "status": 403, + "detail": "You do not have permission to access this resource." +} +``` + +## Using Tokens in SDK Requests + +Developer tokens are passed via the `X-Developer-Token` header: + +```http +GET /api/products HTTP/1.1 +Host: api.example.com +Authorization: Bearer +X-Developer-Token: +``` + +The API will validate both tokens and ensure the developer has access to the requested scopes. \ No newline at end of file diff --git a/Docs/content/pl/reference/grpc.md b/Docs/content/pl/reference/grpc.md new file mode 100644 index 0000000..006dde7 --- /dev/null +++ b/Docs/content/pl/reference/grpc.md @@ -0,0 +1,90 @@ +# Dokumentacja gRPC + +AuthKit udostępnia powierzchnię gRPC obok REST z tego samego potoku hosta (zobacz [ADR-013](/pl/adr/013-dual-rest-and-grpc-transport/)). Używaj jej do komunikacji backend-backend, gdzie opłacają się kontraktowe protobufy. + +Źródła proto leżą w `src/Host/Grpc/protos/` (`jwks.proto`, `monitoring.proto`); wtyczki mogą dokładać własne serwisy tak samo. + +## Serwisy + +| Serwis | Pakiet | Opis | +|--------|--------|------| +| [`Jwks`](#Serwis-Jwks) | `jwks` | Publiczne klucze podpisujące, lookup po kid, health i statystyki | +| [`Monitoring`](#Serwis-Monitoring) | `monitoring` | Zbiorczy health hosta i metryki procesu | + +## Serwis Jwks + +Publiczne klucze podpisujące w kształcie JWKS — te same dane, które serwuje warstwa REST, rzutowane przez protobuf. + +```proto +service Jwks { + rpc GetJwks (google.protobuf.Empty) returns (JwksResponse); + rpc GetKeyByKid (KeyLookupRequest) returns (SingleKeyResponse); + rpc GetJwksHealth (google.protobuf.Empty) returns (HealthResponse); + rpc GetJwksStats (google.protobuf.Empty) returns (KeyStoreStatsResponse); +} +``` + +### GetJwks + +Zwraca wszystkie aktywne (nieunieważnione) publiczne klucze podpisujące. + +**Żądanie:** `google.protobuf.Empty` + +**Odpowiedź:** `JwksResponse` z powtarzanym `Jwk` (`kty`, `use`, `kid`, `alg`, `n`, `e`, `x5c`). + +### GetKeyByKid + +Zwraca pojedynczy klucz po identyfikatorze wraz z metadanymi cyklu życia. + +**Żądanie:** + +```proto +message KeyLookupRequest { + string kid = 1; +} +``` + +**Odpowiedź:** `SingleKeyResponse` (`Jwk key`, `KeyMetadata metadata` z `kid`, `created_at`, `revoked`, `algorithm`, `purpose`). + +### GetJwksHealth + +Stan magazynu kluczy JWKS: `status`, `available_keys`, `active_key_id`, mapa `details`, `timestamp`. + +### GetJwksStats + +Statystyki magazynu do monitoringu: `total_keys`, wiek najstarszego/najnowszego klucza, `key_ids`, `timestamp`. + +## Serwis Monitoring + +```proto +service Monitoring { + rpc GetHealth (google.protobuf.Empty) returns (MonitoringHealthResponse); + rpc GetMetrics (google.protobuf.Empty) returns (MetricsResponse); +} +``` + +### GetHealth + +Zbiorczy health hosta i wtyczek: `status`, `time`, `jwt_key_store_healthy`, powtarzane `PluginHealth` (nazwa + wyniki checków ze statusem, powodem, tagami, danymi). + +### GetMetrics + +Metryki procesu: `uptime_seconds`, `process_start_unix_time`, `time`. + +## Wywołania przez grpcurl + +```bash +grpcurl --insecure localhost:5001 list +grpcurl --insecure localhost:5001 jwks.Jwks/GetJwks +grpcurl --insecure -d '{"kid": ""}' localhost:5001 jwks.Jwks/GetKeyByKid +``` + +Podmień `localhost:5001` na swój endpoint Kestrela z [Konfiguracji](/pl/guide/configuration/). Kestrel domyślnie serwuje HTTPS, gdy istnieje certyfikat deweloperski (`DEV_CERT_PATH`); użyj `--insecure` dla certyfikatu dev, a `-plaintext` tylko gdy brak certyfikatu (fallback HTTP). + +## Uwierzytelnianie + +Wywołania gRPC przechodzą przez te same globalne interceptory co reszta potoku. Przekazuj JWT Keycloak tak samo, jak oczekuje powierzchnia REST (bearer token) — zobacz [Uwierzytelnianie](/pl/reference/rest-api/#uwierzytelnianie). + +## Serwisy wtyczek + +Wtyczki mogą wystawiać własne serwisy gRPC obok hostowych (np. przykładowy `authkit.example.ExampleGreeter` z `SayHello`). Są odkrywane i mapowane razem z endpointami hosta — zobacz [ADR-009](/pl/adr/009-dynamic-plugin-discovery/). diff --git a/Docs/content/pl/reference/rest-api.md b/Docs/content/pl/reference/rest-api.md new file mode 100644 index 0000000..1653615 --- /dev/null +++ b/Docs/content/pl/reference/rest-api.md @@ -0,0 +1,219 @@ +# Dokumentacja REST API + +AuthKit udostępnia endpointy REST i gRPC do zarządzania tokenami i ich weryfikacji. + +## Uwierzytelnianie + +Wszystkie endpointy API wymagają uwierzytelnienia przez **token JWT Keycloak (bearer)** w nagłówku `Authorization`. + +```http +Authorization: Bearer +``` + +## API tokenów deweloperskich + +### Tworzenie tokenu deweloperskiego + +Tworzy nowy token deweloperski dla uwierzytelnionego użytkownika. + +**Endpoint:** `POST /sdk/developer-tokens` + +**Nagłówki:** +| Nagłówek | Wartość | +|----------|---------| +| `Authorization` | `Bearer ` | +| `Content-Type` | `application/json` | + +**Ciało żądania:** +```json +{ + "name": "Mój token SDK", + "description": "Token do dostępu do Marketplace API", + "scopes": ["read:products", "write:products"], + "lifetimeDays": 7 +} +``` + +**Odpowiedź (200):** +```json +{ + "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMzQ1Njc4OTAifQ...", + "key": "rk_live_xxx", + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "scopes": ["read:products", "write:products"], + "lifetime": { + "createdAt": "2024-01-15T10:30:00Z", + "expiresAt": "2024-01-22T10:30:00Z" + } +} +``` + +--- + +### Lista tokenów deweloperskich + +Zwraca wszystkie tokeny deweloperskie należące do uwierzytelnionego użytkownika. + +**Endpoint:** `GET /sdk/developer-tokens` + +**Nagłówki:** +| Nagłówek | Wartość | +|----------|---------| +| `Authorization` | `Bearer ` | + +**Odpowiedź (200):** +```json +[ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "name": "Produkcyjny token SDK", + "scopes": ["read:products"], + "createdAt": "2024-01-10T08:00:00Z", + "expiresAt": "2024-02-10T08:00:00Z", + "isExpired": false + } +] +``` + +--- + +### Pobieranie tokenu po ID + +Pobiera konkretny token deweloperski po jego ID. + +**Endpoint:** `GET /sdk/developer-tokens/{tokenId}` + +**Nagłówki:** +| Nagłówek | Wartość | +|----------|---------| +| `Authorization` | `Bearer ` | + +**Odpowiedź (200):** +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "name": "Mój token SDK", + "scopes": ["read:products", "write:products"], + "createdAt": "2024-01-15T10:30:00Z", + "expiresAt": "2024-01-22T10:30:00Z", + "isExpired": false +} +``` + +**Błąd (404):** Nie znaleziono tokenu + +--- + +### Usuwanie tokenu deweloperskiego + +Usuwa token deweloperski po jego ID. + +**Endpoint:** `DELETE /sdk/developer-tokens/{tokenId}` + +**Nagłówki:** +| Nagłówek | Wartość | +|----------|---------| +| `Authorization` | `Bearer ` | + +**Odpowiedź (200):** +``` +Token usunięty pomyślnie +``` + +--- + +## API weryfikacji tokenów + +### Weryfikacja tokenu + +Weryfikuje token deweloperski względem utrwalonych danych tokenu. Endpoint anonimowy (nagłówek `Authorization` nie jest wymagany). + +**Endpoint:** `POST /sdk/tokens/verify` + +**Ciało żądania:** +```json +{ + "key": "rk_live_xxx" +} +``` + +**Odpowiedź (200):** +```json +true +``` + +--- + +### Unieważnienie i rotacja tokenu + +Unieważnia istniejący token i generuje zamiennik. Wymaga roli `User` (`Authorization: Bearer ` z rolą `User`). + +**Endpoint:** `POST /sdk/tokens/{tokenId}/revoke-rotate` + +**Nagłówki:** +| Nagłówek | Wartość | +|----------|---------| +| `Authorization` | `Bearer ` | + +**Odpowiedź (200):** +```json +{ + "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjY4ODkwMTIzNDU2fQ...", + "key": "rk_live_yyy", + "tokenId": "660e8400-e29b-41d4-a716-446655440000", + "developerId": "550e8400-e29b-41d4-a716-446655440001", + "scopes": ["read:products", "write:products"], + "lifetime": { + "createdAt": "2024-01-16T10:30:00Z", + "expiresAt": "2024-01-23T10:30:00Z" + } +} +``` + +## Odpowiedzi błędów + +### 401 Unauthorized +```json +{ + "type": "https://tools.ietf.org/html/rfc7235#section-3.1", + "title": "Unauthorized", + "status": 401, + "detail": "Brak lub nieprawidłowe dane uwierzytelniające." +} +``` + +### 404 Not Found +```json +{ + "type": "https://tools.ietf.org/html/rfc7231#section-6.5.4", + "title": "Not Found", + "status": 404, + "detail": "Żądany zasób nie został znaleziony." +} +``` + +### 403 Forbidden +```json +{ + "type": "https://tools.ietf.org/html/rfc7231#section-6.5.3", + "title": "Forbidden", + "status": 403, + "detail": "Brak uprawnień do tego zasobu." +} +``` + +## Używanie tokenów w żądaniach SDK + +Tokeny deweloperskie przekazywane są w nagłówku `X-Developer-Token`: + +```http +GET /api/products HTTP/1.1 +Host: api.example.com +Authorization: Bearer +X-Developer-Token: +``` + +API zweryfikuje oba tokeny i upewni się, że deweloper ma dostęp do żądanych zakresów (scopes). From c159c093e6e7962951daa1831ef4148a9e29eb29 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 00:59:33 +0200 Subject: [PATCH 07/17] docs: add AuthKit overview and architecture diagrams --- Docs/content/en/README.md | 20 +++++++++ Docs/content/en/schemas.md | 92 ++++++++++++++++++++++++++++++++++++++ Docs/content/pl/README.md | 20 +++++++++ Docs/content/pl/schemas.md | 87 +++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 Docs/content/en/README.md create mode 100644 Docs/content/en/schemas.md create mode 100644 Docs/content/pl/README.md create mode 100644 Docs/content/pl/schemas.md diff --git a/Docs/content/en/README.md b/Docs/content/en/README.md new file mode 100644 index 0000000..99995d2 --- /dev/null +++ b/Docs/content/en/README.md @@ -0,0 +1,20 @@ +# AuthKit Documentation + +Welcome to AuthKit - Developer Authentication & SDK Access Service. + +## Overview + +AuthKit is a **plugin-based service** for handling **developer authentication, SDK token issuance, and access verification**. It ensures that only authorized developers can access SDK methods and provides a secure, auditable token-based authentication mechanism. + +## Quick Links + +- [Introduction](/en/guide/introduction/) +- [Quick Start](/en/guide/quick-start/) +- [REST API Reference](/en/reference/rest-api/) +- [Architecture](/en/architecture/adr/) + +## Languages + +You can read this documentation in: +- [English](/en/) +- [Polski](/pl/) \ No newline at end of file diff --git a/Docs/content/en/schemas.md b/Docs/content/en/schemas.md new file mode 100644 index 0000000..6b7d260 --- /dev/null +++ b/Docs/content/en/schemas.md @@ -0,0 +1,92 @@ +# AuthKit Schemas + +This document contains the Mermaid diagrams describing AuthKit's token flows and architecture. + +## Token Issuance & SDK Request Flow +```mermaid +sequenceDiagram + participant Dev as Developer + participant Keycloak as Keycloak + participant AuthKit as AuthKit API + participant SDK as AuthKitSdkClient + participant API as Target API (e.g. Marketplace) + + Dev->>Keycloak: Authenticate via Keycloak (JWT access token) + Keycloak-->>Dev: Returns access_token (Keycloak JWT) + + Dev->>AuthKit: Request Developer Token
Authorization: Bearer + AuthKit->>AuthKit: Validate Keycloak token
and create DeveloperToken (JWT) + AuthKit-->>Dev: Returns X-Developer-Token (AuthKit JWT) + + SDK->>API: Request with
Authorization: Bearer
X-Developer-Token: + API->>AuthKit: Validate developer token via REST + AuthKit->>Keycloak: Validate user session & roles + AuthKit-->>API: DeveloperToken valid ✅ + API-->>SDK: 200 OK — Operation authorized +``` + +## External REST vs Internal gRPC Call Flow +```mermaid +flowchart TD + Dev[Developer] -->|Authenticate| Keycloak[Keycloak JWT] + Keycloak --> Dev + + Dev -->|Request Dev Token| AuthKit[AuthKit API] + AuthKit -->|Validate Keycloak token| Keycloak + AuthKit -->|Return Dev Token| Dev + + Dev -->|Request Service Token| AuthKitService[AuthKit API] + AuthKitService -->|Validate Dev Token| AuthKit + AuthKitService -->|Return Service Token| Dev + + Dev -->|Configure SDK| SDK[AuthKitSdkClient] + + SDK -->|REST request| API_REST[Target API REST] + SDK -->|gRPC request| API_GRPC[Target API gRPC] + + subgraph REST_Flow + API_REST -->|Pass tokens to middleware| AuthKit_REST[AuthKit Middleware REST] + AuthKit_REST -->|Validate Dev & Service Tokens| TokenDB[Token Database] + AuthKit_REST -->|Validate Keycloak JWT| Keycloak + AuthKit_REST -->|Return auth result| API_REST + API_REST -->|200 OK / 403 Forbidden| SDK + end + + subgraph gRPC_Flow + API_GRPC -->|Pass tokens to middleware| AuthKit_GRPC[AuthKit Middleware gRPC] + AuthKit_GRPC -->|Validate Dev & Service Tokens| TokenDB + AuthKit_GRPC -->|Validate Keycloak JWT| Keycloak + AuthKit_GRPC -->|Return auth result| API_GRPC + API_GRPC -->|200 OK / 403 Forbidden| SDK + end +``` + +## SDK Function Call Flow (AuthKit → gRPC Microservices) +```mermaid +flowchart TD + classDef token fill:#fef3c7,stroke:#f59e0b,stroke-width:1px,color:#b45309; + classDef service fill:#fef3c7,stroke:#fef3c7,stroke-width:1px,color:#92400e; + classDef internal fill:#dbeafe,stroke:#3b82f6,stroke-width:1px,color:#1e40af; + +%% Actors + Dev[Developer] -->|Has Keycloak JWT,
DeveloperToken,
ServiceToken| SDK[AuthKitSdkClient] + class Dev,SDK token; + +%% REST request from external SDK + SDK -->|REST request with tokens| API_Controller[API Controller] + API_Controller -->|Validate tokens internally via AuthKit| AuthKit[AuthKit API] + +%% gRPC requests + API_Controller -->|gRPC call| GRPC_Service[gRPC Service] + GRPC_Service -->|gRPC call to other microservice| AnotherService_GRPC[Another gRPC Service] + +%% Responses + GRPC_Service -->|Return result| API_Controller + AnotherService_GRPC -->|Return result| GRPC_Service + API_Controller -->|Return response| SDK + +%% Styling + class Dev,SDK,AuthKit token; + class API_Controller,GRPC_Service service; + class AnotherService_GRPC internal; +``` \ No newline at end of file diff --git a/Docs/content/pl/README.md b/Docs/content/pl/README.md new file mode 100644 index 0000000..4d53173 --- /dev/null +++ b/Docs/content/pl/README.md @@ -0,0 +1,20 @@ +# Dokumentacja AuthKit + +Witaj w AuthKit — usłudze uwierzytelniania deweloperów i dostępu do SDK. + +## Przegląd + +AuthKit to **usługa oparta na wtyczkach** do **uwierzytelniania deweloperów, wydawania tokenów SDK i weryfikacji dostępu**. Gwarantuje, że tylko autoryzowani deweloperzy mają dostęp do metod SDK, zapewniając bezpieczny i audytowalny mechanizm uwierzytelniania oparty na tokenach. + +## Szybkie linki + +- [Wprowadzenie](/pl/guide/introduction/) +- [Szybki start](/pl/guide/quick-start/) +- [Dokumentacja REST API](/pl/reference/rest-api/) +- [Architektura](/architecture/) + +## Języki + +Dokumentację możesz czytać w językach: +- [English](/en/) +- [Polski](/pl/) diff --git a/Docs/content/pl/schemas.md b/Docs/content/pl/schemas.md new file mode 100644 index 0000000..db50ed7 --- /dev/null +++ b/Docs/content/pl/schemas.md @@ -0,0 +1,87 @@ +# Schematy AuthKit + +Ten dokument zawiera diagramy Mermaid opisujące przepływy tokenów i architekturę AuthKit. + +## Wydawanie tokenów i przepływ żądań SDK +```mermaid +sequenceDiagram + participant Dev as Deweloper + participant Keycloak as Keycloak + participant AuthKit as AuthKit API + participant SDK as AuthKitSdkClient + participant API as Docelowe API (np. Marketplace) + + Dev->>Keycloak: Uwierzytelnienie przez Keycloak (token dostępu JWT) + Keycloak-->>Dev: Zwraca access_token (JWT Keycloak) + + Dev->>AuthKit: Żądanie tokenu deweloperskiego
Authorization: Bearer + AuthKit->>AuthKit: Walidacja tokenu Keycloak
i utworzenie DeveloperToken (JWT) + AuthKit-->>Dev: Zwraca X-Developer-Token (JWT AuthKit) + + SDK->>API: Żądanie z
Authorization: Bearer
X-Developer-Token: + API->>AuthKit: Walidacja tokenu deweloperskiego przez REST + AuthKit->>Keycloak: Walidacja sesji i ról użytkownika + AuthKit-->>API: Token deweloperski poprawny ✅ + API-->>SDK: 200 OK — Operacja autoryzowana +``` + +## Zewnętrzny REST vs wewnętrzny przepływ gRPC +```mermaid +flowchart TD + Dev[Deweloper] -->|Uwierzytelnienie| Keycloak[Keycloak JWT] + Keycloak --> Dev + + Dev -->|Żądanie tokenu dev| AuthKit[AuthKit API] + AuthKit -->|Walidacja tokenu Keycloak| Keycloak + AuthKit -->|Zwrot tokenu dev| Dev + + Dev -->|Żądanie tokenu serwisowego| AuthKitService[AuthKit API] + AuthKitService -->|Walidacja tokenu dev| AuthKit + AuthKitService -->|Zwrot tokenu serwisowego| Dev + + Dev -->|Konfiguracja SDK| SDK[AuthKitSdkClient] + + SDK -->|Żądanie REST| API_REST[Docelowe API REST] + SDK -->|Żądanie gRPC| API_GRPC[Docelowe API gRPC] + + subgraph REST_Flow + API_REST -->|Przekazanie tokenów do middleware| AuthKit_REST[AuthKit Middleware REST] + AuthKit_REST -->|Walidacja tokenów dev i serwisowych| TokenDB[Baza tokenów] + AuthKit_REST -->|Walidacja JWT Keycloak| Keycloak + AuthKit_REST -->|Zwrot wyniku autoryzacji| API_REST + API_REST -->|200 OK / 403 Forbidden| SDK + end + + subgraph gRPC_Flow + API_GRPC -->|Przekazanie tokenów do middleware| AuthKit_GRPC[AuthKit Middleware gRPC] + AuthKit_GRPC -->|Walidacja tokenów dev i serwisowych| TokenDB + AuthKit_GRPC -->|Walidacja JWT Keycloak| Keycloak + AuthKit_GRPC -->|Zwrot wyniku autoryzacji| API_GRPC + API_GRPC -->|200 OK / 403 Forbidden| SDK + end +``` + +## Przepływ wywołań funkcji SDK (AuthKit → mikroserwisy gRPC) +```mermaid +flowchart TD + classDef token fill:#fef3c7,stroke:#f59e0b,stroke-width:1px,color:#b45309; + classDef service fill:#fef3c7,stroke:#fef3c7,stroke-width:1px,color:#92400e; + classDef internal fill:#dbeafe,stroke:#3b82f6,stroke-width:1px,color:#1e40af; + + Dev[Deweloper] -->|Posiada Keycloak JWT,
DeveloperToken,
ServiceToken| SDK[AuthKitSdkClient] + class Dev,SDK token; + + SDK -->|Żądanie REST z tokenami| API_Controller[Kontroler API] + API_Controller -->|Wewnętrzna walidacja przez AuthKit| AuthKit[AuthKit API] + + API_Controller -->|Wywołanie gRPC| GRPC_Service[Serwis gRPC] + GRPC_Service -->|Wywołanie gRPC do innego mikroserwisu| AnotherService_GRPC[Inny serwis gRPC] + + GRPC_Service -->|Zwrot wyniku| API_Controller + AnotherService_GRPC -->|Zwrot wyniku| GRPC_Service + API_Controller -->|Zwrot odpowiedzi| SDK + + class Dev,SDK,AuthKit token; + class API_Controller,GRPC_Service service; + class AnotherService_GRPC internal; +``` From 8538486639ad9b6dd77cda78f39e327d9e5a32e0 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 01:03:18 +0200 Subject: [PATCH 08/17] docs: remove relocated documentation files --- Docs/ADR/README.md | 108 --------------------------------------------- Docs/README.md | 9 ---- Docs/Schemas.md | 92 -------------------------------------- 3 files changed, 209 deletions(-) delete mode 100644 Docs/ADR/README.md delete mode 100644 Docs/README.md delete mode 100644 Docs/Schemas.md diff --git a/Docs/ADR/README.md b/Docs/ADR/README.md deleted file mode 100644 index 0b6170e..0000000 --- a/Docs/ADR/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# Architecture Decision Records - -This directory stores AuthKit.Server architectural decisions as ADRs. It is not changelog and not rewritten commit history. It is curated set of technical decisions that explains why the system has its current shape and which constraints that imposes on future work. - -ADRs are grouped by architecture area. Numbering is global, so decision ID does not depend on the file it lives in. Moving a file to another area does not change its number, and the number should be treated as stable decision identifier. - -## How To Read This Collection - -Start with the area that matches what you are changing: - -- if the change affects key management, token key bindings, or core domain contracts, read the `AuthKit.Core` decisions below -- if it affects the REST or gRPC surface, CLI, configuration, or how the server is composed and hosted, see the Host decisions -- if it affects the plugin system, solutions, or plugin abstractions, see the Plugins decisions - -Each ADR contains: - -- `Context`: - the layer and architectural location of the decision -- `Problem`: - the specific technical tension the decision resolves -- `Decision`: - the chosen direction and responsibility boundary -- `Rejected`: - realistic alternatives that were intentionally not selected -- `Consequences`: - maintenance impact, constraints, side effects, and practical implications for future code - -## How To Use ADRs During Changes - -ADRs do not replace reading the code, but they reduce the cost of understanding decisions that have already been made. When you change a given area: - -1. find the matching area -2. read the 2-4 closest ADRs, not just one -3. check whether the new change extends the current model or actually breaks it -4. if decision is no longer true, add a new ADR instead of silently drifting away from the current direction - -This collection is meant to preserve consistency across Core, Host, and Plugins. In AuthKit.Server, much of the cost of change comes from contracts between layers rather than from any single class. - -## Category Map - -The table below shows the architecture areas and their current scope. - -| Area | Scope | -| --- | --- | -| Core | Shared domain model: signing key management, token key bindings, error contracts, and Core interfaces. | -| Host | Application composition and external surface: REST, gRPC, CLI, configuration, and key-material hosting. | -| Plugins | Plugin system: solutions, plugin abstractions, and extension boundaries. | - -## Current ADRs - -| ID | Title | Area | Status | Date | -|----|-------|------|--------|------| -| [ADR-001](./001-centralize-signing-key-management.md) | Centralize Signing Key Management Through A Core Key Store Abstraction | Core | accepted | 2026-08-26 | -| [ADR-002](./002-encrypt-keystore-at-rest.md) | Encrypt Persisted Keystore Material At Rest Through A Pluggable Encryptor | Core | accepted | 2026-08-26 | -| [ADR-003](./003-signing-key-lifecycle-immutable-transitions.md) | Model Signing Key Lifecycle As Immutable State Transitions | Core | accepted | 2026-08-26 | -| [ADR-004](./004-token-key-bindings-domain.md) | Treat Developer Token To Signing Key Bindings As A Core Domain | Core | accepted | 2026-08-26 | -| [ADR-005](./005-public-keys-via-jwks.md) | Publish Public Keys Through JWKS Exposing Only Non-Revoked Keys | Core | accepted | 2026-08-26 | -| [ADR-006](./006-kid-as-generated-guid.md) | Derive The JWT Key Identifier As A Generated GUID | Core | accepted | 2026-08-26 | -| [ADR-007](./007-default-signing-algorithm-rsa-4096.md) | Default Signing Algorithm Is RSA-4096 With RS256 | Core | accepted | 2026-08-26 | -| [ADR-008](./008-standardized-error-response.md) | Standardize API Errors Through A Core Error Response Contract | Core | accepted | 2026-08-26 | -| [ADR-009](./009-dynamic-plugin-discovery.md) | Discover And Load Plugins Dynamically Through The IAuthKitPlugin Contract | Plugins | accepted | 2026-08-26 | -| [ADR-010](./010-plugin-loading-from-directory.md) | Load Plugins From A Configurable Directory At Startup | Host | accepted | 2026-08-26 | -| [ADR-011](./011-keystore-persisted-as-singleton-marten-document.md) | Persist The Encrypted Keystore As A Singleton Marten Document | Host | accepted | 2026-08-26 | -| [ADR-012](./012-token-key-bindings-persisted-in-marten.md) | Persist Token Key Bindings In Marten | Host | accepted | 2026-08-26 | -| [ADR-013](./013-dual-rest-and-grpc-transport.md) | Expose Both REST And gRPC Transport Surfaces | Host | accepted | 2026-08-26 | -| [ADR-014](./014-error-responses-via-middleware.md) | Render HTTP Errors As RFC 7807 Problem Details Via Middleware | Host | accepted | 2026-08-26 | -| [ADR-015](./015-keycloak-external-jwt-authority.md) | Use Keycloak As The External JWT Authority | Host | accepted | 2026-08-26 | -| [ADR-016](./016-marten-and-wolverine-infrastructure.md) | Use Marten And Wolverine As Host Infrastructure | Host | accepted | 2026-08-26 | -| [ADR-017](./017-Plugin-Contract-and-Dynamic-Loading-Architecture.md) | Define The Plugin Contract And Dynamic Loading Architecture | Plugins | accepted | 2026-09-11 | -| [ADR-017](./017-api-key-credential-extraction-strategies.md) | Define API Key Credential Extraction Strategies | Host | accepted | 2026-09-11 | -| [ADR-018](./018-security-scheme-contract-explicit-handling.md) | Handle Security Scheme Contract Values Explicitly | Plugins | accepted | 2026-09-11 | -| [ADR-019](./019-plugin-metadata-attribute.md) | Declare Plugin Identity Through The PluginMetadata Attribute | Plugins | accepted | 2026-09-11 | -| [ADR-020](./020-devtools-plugin.md) | Host Developer Tools Through A Dedicated DevTools Plugin | Plugins | accepted | 2026-09-11 | -| [ADR-021](./021-swagger-serving-via-reflection.md) | Serve Swagger Through Reflection-Based SwaggerHost In DevTools | Plugins | accepted | 2026-09-11 | -| [ADR-022](./022-plugin-configuration-context-and-builder.md) | Extend Plugin Configuration With The Host Builder And Scoped Context | Plugins | accepted | 2026-09-12 | -| [ADR-023](./023-plugin-application-pipeline-hooks.md) | Integrate Plugin Endpoints And Middleware Through Explicit Host Pipeline Hooks | Plugins | accepted | 2026-09-12 | -| [ADR-024](./024-plugin-lifecycle-and-hosted-services.md) | Bridge Plugin Lifecycle Hooks To The Standard .NET Host Lifecycle | Plugins | accepted | 2026-09-12 | -| [ADR-025](./025-plugin-options-openapi-and-marten-integrations.md) | Keep Plugin Options, OpenAPI, And Marten Integrations Explicit | Plugins | accepted | 2026-09-12 | -| [ADR-026](./026-plugin-authentication-and-authorization-hooks.md) | Configure Plugin Authentication And Authorization Through Host Security Infrastructure | Plugins | accepted | 2026-09-12 | -| [ADR-027](./027-devtools-ui-typescript.md) | Compile The DevTools UI From Modular TypeScript Into A Single Embedded Resource | Plugins | accepted | 2026-09-16 | - -## Relationships Between Areas - -The most common architectural flow in AuthKit.Server looks like this: - -`Core -> Host -> Plugins` - -This is not strict dependency diagram of the project, but it is useful map for reading decisions. In practice: - -- `Core` defines what the system considers to be domain data and the cryptographic contracts (keys, bindings, errors) -- `Host` defines how that domain is exposed and composed into a running server (API surfaces, CLI, configuration) -- `Plugins` extend behavior on top of the stable Core and Host contracts - -## When To Add A New ADR - -A new ADR is worth adding when change: - -- shifts responsibility boundaries between layers -- introduces a new data contract or new durable artifact -- changes the execution model of key management, hosting, or plugin loading -- adds a new provider or plugin specific behavior that no longer fits the current model -- replaces an earlier decision with a different conscious trade off - -It is usually not worth adding an ADR for: - -- an ordinary refactor without an architectural change in direction -- a cosmetic local API change limited to one file or class -- a documentation or test only adjustment that does not change system contracts diff --git a/Docs/README.md b/Docs/README.md deleted file mode 100644 index 165fd20..0000000 --- a/Docs/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# AuthKit Documentation - -This is the documentation index for AuthKit. - -| Topic | Link | -| --- | --- | -| Schemas & Diagrams | [Schemas](Schemas.md) | -| Contributing | [Contributing](../CONTRIBUTING.md) | -| Security | [Security](../SECURITY.md) | diff --git a/Docs/Schemas.md b/Docs/Schemas.md deleted file mode 100644 index e3d160b..0000000 --- a/Docs/Schemas.md +++ /dev/null @@ -1,92 +0,0 @@ -# AuthKit Schemas - -This document contains the Mermaid diagrams describing AuthKit's token flows and architecture. - -## Token Issuance & SDK Request Flow -```mermaid -sequenceDiagram - participant Dev as Developer - participant Keycloak as Keycloak - participant AuthKit as AuthKit API - participant SDK as AuthKitSdkClient - participant API as Target API (e.g. Marketplace) - - Dev->>Keycloak: Authenticate via Keycloak (JWT access token) - Keycloak-->>Dev: Returns access_token (Keycloak JWT) - - Dev->>AuthKit: Request Developer Token
Authorization: Bearer - AuthKit->>AuthKit: Validate Keycloak token
and create DeveloperToken (JWT) - AuthKit-->>Dev: Returns X-Developer-Token (AuthKit JWT) - - SDK->>API: Request with
Authorization: Bearer
X-Developer-Token: - API->>AuthKit: Validate developer token via REST - AuthKit->>Keycloak: Validate user session & roles - AuthKit-->>API: DeveloperToken valid ✅ - API-->>SDK: 200 OK — Operation authorized -``` - -## External REST vs Internal gRPC Call Flow -```mermaid -flowchart TD - Dev[Developer] -->|Authenticate| Keycloak[Keycloak JWT] - Keycloak --> Dev - - Dev -->|Request Dev Token| AuthKit[AuthKit API] - AuthKit -->|Validate Keycloak token| Keycloak - AuthKit -->|Return Dev Token| Dev - - Dev -->|Request Service Token| AuthKitService[AuthKit API] - AuthKitService -->|Validate Dev Token| AuthKit - AuthKitService -->|Return Service Token| Dev - - Dev -->|Configure SDK| SDK[AuthKitSdkClient] - - SDK -->|REST request| API_REST[Target API REST] - SDK -->|gRPC request| API_GRPC[Target API gRPC] - - subgraph REST_Flow - API_REST -->|Pass tokens to middleware| AuthKit_REST[AuthKit Middleware REST] - AuthKit_REST -->|Validate Dev & Service Tokens| TokenDB[Token Database] - AuthKit_REST -->|Validate Keycloak JWT| Keycloak - AuthKit_REST -->|Return auth result| API_REST - API_REST -->|200 OK / 403 Forbidden| SDK - end - - subgraph gRPC_Flow - API_GRPC -->|Pass tokens to middleware| AuthKit_GRPC[AuthKit Middleware gRPC] - AuthKit_GRPC -->|Validate Dev & Service Tokens| TokenDB - AuthKit_GRPC -->|Validate Keycloak JWT| Keycloak - AuthKit_GRPC -->|Return auth result| API_GRPC - API_GRPC -->|200 OK / 403 Forbidden| SDK - end -``` - -## SDK Function Call Flow (AuthKit → gRPC Microservices) -```mermaid -flowchart TD - classDef token fill:#fef3c7,stroke:#f59e0b,stroke-width:1px,color:#b45309; - classDef service fill:#fef3c7,stroke:#fef3c7,stroke-width:1px,color:#92400e; - classDef internal fill:#dbeafe,stroke:#3b82f6,stroke-width:1px,color:#1e40af; - -%% Actors - Dev[Developer] -->|Has Keycloak JWT,
DeveloperToken,
ServiceToken| SDK[AuthKitSdkClient] - class Dev,SDK token; - -%% REST request from external SDK - SDK -->|REST request with tokens| API_Controller[API Controller] - API_Controller -->|Validate tokens internally via AuthKit| AuthKit[AuthKit API] - -%% gRPC requests - API_Controller -->|gRPC call| GRPC_Service[gRPC Service] - GRPC_Service -->|gRPC call to other microservice| AnotherService_GRPC[Another gRPC Service] - -%% Responses - GRPC_Service -->|Return result| API_Controller - AnotherService_GRPC -->|Return result| GRPC_Service - API_Controller -->|Return response| SDK - -%% Styling - class Dev,SDK,AuthKit token; - class API_Controller,GRPC_Service service; - class AnotherService_GRPC internal; -``` From 1f608513f3b6379a6abfd29a6f9802b4d006bd60 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 01:23:01 +0200 Subject: [PATCH 09/17] feat: introduce reusable Docs content utilities --- Docs/src/lib/adr/registry-filter.ts | 106 +++++++++++++++++++++++++ Docs/src/lib/chrome/content-hero.ts | 69 ++++++++++++++++ Docs/src/lib/chrome/dom.ts | 54 +++++++++++++ Docs/src/lib/chrome/icons.ts | 24 ++++++ Docs/src/lib/chrome/landing-data.ts | 92 +++++++++++++++++++++ Docs/src/lib/chrome/section-accents.ts | 21 +++++ 6 files changed, 366 insertions(+) create mode 100644 Docs/src/lib/adr/registry-filter.ts create mode 100644 Docs/src/lib/chrome/content-hero.ts create mode 100644 Docs/src/lib/chrome/dom.ts create mode 100644 Docs/src/lib/chrome/icons.ts create mode 100644 Docs/src/lib/chrome/landing-data.ts create mode 100644 Docs/src/lib/chrome/section-accents.ts diff --git a/Docs/src/lib/adr/registry-filter.ts b/Docs/src/lib/adr/registry-filter.ts new file mode 100644 index 0000000..a8aa5ae --- /dev/null +++ b/Docs/src/lib/adr/registry-filter.ts @@ -0,0 +1,106 @@ +// ADR registry filter bar (search input + area pills + live count). +// Extracted from AdrChrome: single responsibility is filtering registry +// table. Display strings are injected (Dependency Inversion), table shape +// (ID | title | area) is the only contract language agnostic. +import { el } from '../chrome/dom' + +export interface FilterLabels { + search: string + all: string + shown: string + empty: string +} + +/** + * @param table the registry to filter (bar is inserted before it) + * @param labels pre translated UI strings + */ +export function buildRegistryFilter(table: HTMLTableElement, labels: FilterLabels): void +{ + table.parentElement?.querySelector(':scope > .adr-filter')?.remove() + const rows = [...table.querySelectorAll('tbody tr')] + const areas = [ + ...new Set( + rows.map(r => (r.children[2]?.textContent ?? '').trim()).filter(Boolean), + ), + ] + + const bar = el('div', 'adr-filter') + const input = el('input', 'adr-filter__search') + input.type = 'search' + input.placeholder = labels.search + input.setAttribute('aria-label', labels.search) + + const pills = el('div', 'adr-filter__pills') + pills.setAttribute('role', 'group') + let area = '' + const buttons: HTMLButtonElement[] = [] + for (const name of ['', ...areas]) + { + const b = el('button', 'adr-filter__pill', name || labels.all) + b.type = 'button' + b.setAttribute('aria-pressed', name === '' ? 'true' : 'false') + if (name === '') b.classList.add('is-active') + b.addEventListener('click', () => { + area = name + for (const x of buttons) { + const on = x === b + x.classList.toggle('is-active', on) + x.setAttribute('aria-pressed', String(on)) + } + apply() + }) + buttons.push(b) + pills.appendChild(b) + } + + const count = el('span', 'adr-filter__count') + count.setAttribute('aria-live', 'polite') + const empty = el('p', 'adr-filter__empty', labels.empty) + empty.hidden = true + + function apply(): void + { + const q = input.value.trim().toLowerCase() + let visible = 0 + for (const r of rows) + { + const cells = r.children + const hay = `${cells[0]?.textContent ?? ''} ${cells[1]?.textContent ?? ''}`.toLowerCase() + const ok = (!area || cells[2]?.textContent?.trim() === area) && (!q || hay.includes(q)) + ;(r as HTMLTableRowElement).hidden = !ok + if (ok) visible++ + } + count.textContent = `${visible} ${labels.shown} ${rows.length}` + empty.hidden = visible > 0 + } + + input.addEventListener('input', apply) + bar.append(input, pills, count) + table.before(bar) + table.after(empty) + apply() +} + +const LABELS: Record = { + en: { + search: 'Search by ID or title…', + all: 'All', + shown: 'of', + empty: 'No results for the given filters.', + }, + pl: { + search: 'Szukaj po ID lub tytule…', + all: 'Wszystkie', + shown: 'z', + empty: 'Brak wyników dla podanych filtrów.', + }, +} + +/** + * Labels for locale code (eg. 'en', 'pl'). Unknown locales fall back + * to English adding language means adding one dictionary entry. + */ +export function filterLabels(locale: string): FilterLabels { + return LABELS[locale] ?? LABELS.en +} diff --git a/Docs/src/lib/chrome/content-hero.ts b/Docs/src/lib/chrome/content-hero.ts new file mode 100644 index 0000000..f89a335 --- /dev/null +++ b/Docs/src/lib/chrome/content-hero.ts @@ -0,0 +1,69 @@ +// Shared hero builder for content-chrome components. +// +// Both AdrChrome (adr hero*) and SectionChrome (sec-hero*) wrap the page h1 +// + lead paragraphs into a hero panel with stat cards and a section nav. +// This module owns that algorithm once (DRY); components only supply their +// class namespace + page specific stats. Styling stays in the components. +import { el, sectionLinks, statCard } from './dom' + +export interface HeroNamespace { + hero: string + stats: string + card: string + num: string + label: string + nav: string +} + +export interface HeroStat { + value: string + label: string +} + +/** + * Move h1 + following lead paragraphs into a hero panel. + * @returns the hero element, or null when the page has no h1. + */ +export function wrapHero(root: ParentNode, heroClass: string): HTMLDivElement | null { + const h1 = root.querySelector(':scope > h1') + if (!h1) return null + const hero = el('div', heroClass) + h1.before(hero) + hero.appendChild(h1) + let next: ChildNode | null = hero.nextSibling + while (next && next instanceof HTMLParagraphElement) { + const cur = next + next = next.nextSibling + hero.appendChild(cur) + } + return hero +} + +/** Append stat cards to a hero. */ +export function appendStats(hero: HTMLElement, items: HeroStat[], ns: HeroNamespace): void { + const stats = el('div', ns.stats) + for (const item of items) { + stats.append(statCard(item.value, item.label, { card: ns.card, num: ns.num, labelCls: ns.label })) + } + hero.appendChild(stats) +} + +/** Append a nav of h2 section links to a hero. No-op without sections. */ +export function appendSectionNav( + hero: HTMLElement, + root: ParentNode, + ns: HeroNamespace, + ariaLabel = '', +): void +{ + const links = sectionLinks(root) + if (links.length === 0) return + const nav = el('nav', ns.nav) + if (ariaLabel) nav.setAttribute('aria-label', ariaLabel) + for (const { href, text } of links) { + const a = el('a', '', text) + a.href = href + nav.appendChild(a) + } + hero.appendChild(nav) +} diff --git a/Docs/src/lib/chrome/dom.ts b/Docs/src/lib/chrome/dom.ts new file mode 100644 index 0000000..4811737 --- /dev/null +++ b/Docs/src/lib/chrome/dom.ts @@ -0,0 +1,54 @@ +// Shared DOM primitives for the content-chrome components (AdrChrome, +// SectionChrome). Single responsibility: element creation only — no +// knowledge of ADR vs section pages. + +/** Create an element with an optional class name and text content. */ +export function el( + tag: K, + className = '', + text = '', +): HTMLElementTagNameMap[K] +{ + const node = document.createElement(tag) + if (className) node.className = className + if (text) node.textContent = text + return node +} + +export interface StatClasses +{ + card?: string + num?: string + labelCls?: string +} + +/** + * A single hero stat card: big numeric value + uppercase label. + * Class names are injected so ADR and section pages keep their own skin. + */ +export function statCard(value: string, label: string, classes: StatClasses = {}): HTMLDivElement { + const d = el('div', classes.card ?? '') + d.append(el('span', classes.num ?? '', value), el('span', classes.labelCls ?? '', label)) + return d +} + +export interface SectionLink { + href: string + text: string +} + +/** + * Collect top-level h2 headings of a content root into nav links. + * Returns an empty array when the page has no linkable sections. + */ +export function sectionLinks(root: ParentNode): SectionLink[] +{ + const links: SectionLink[] = [] + for (const h2 of root.querySelectorAll(':scope > h2')) { + const href = h2.querySelector(':scope > a')?.getAttribute('href') + const text = (h2.textContent ?? '').trim() + if (!href || !text) continue + links.push({ href, text }) + } + return links +} diff --git a/Docs/src/lib/chrome/icons.ts b/Docs/src/lib/chrome/icons.ts new file mode 100644 index 0000000..8873a89 --- /dev/null +++ b/Docs/src/lib/chrome/icons.ts @@ -0,0 +1,24 @@ +// Shared SVG icon registry for content components (IntroCards, …). +// built-in set is fixed, but consumers extend it via +// registerIcon() without touching this module or its callers. +const ICONS = new Map([ + ['shield', ''], + ['key', ''], + ['sync', ''], + ['code', ''], + ['db', ''], + ['layers', ''], + ['box', ''], + ['terminal', ''], + ['plug', ''], +]) + +/** Register (or override) an icon. Unknown names render as empty. */ +export function registerIcon(name: string, svgInner: string): void { + ICONS.set(name, svgInner) +} + +/** Inner SVG markup for an icon name, or '' when unknown. */ +export function getIcon(name: string): string { + return ICONS.get(name) ?? '' +} diff --git a/Docs/src/lib/chrome/landing-data.ts b/Docs/src/lib/chrome/landing-data.ts new file mode 100644 index 0000000..4fdb29c --- /dev/null +++ b/Docs/src/lib/chrome/landing-data.ts @@ -0,0 +1,92 @@ +// Landing page content model. Single responsibility: translate i18n copy +// + route base into render data. The translator `t` and `base` are injected +// this module never imports paraglide or routing, +// so it stays pure and locale agnostic. + +export type Translator = (key: string) => string + +export interface HexCard { + icon: string + num: string + title: string + sub: string + body: string + code: string + link: string + linkLabel: string +} + +export interface FeatureCard { + t: string + d: string + icon: string +} + +export interface ThirdNav { + label: string + href: string +} + +/** Flow hexes for the landing "hive" section. */ +export function buildHexes(t: Translator, base: string): HexCard[] { + return [ + { + icon: 'M12 2l7 4v6c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6l7-4z', + num: t('landing.hex1Num'), + title: t('landing.hex1Title'), + sub: t('landing.hex1Sub'), + body: t('landing.hex1Body'), + code: 'Authorization: Bearer ', + link: `${base}/guide/introduction/`, + linkLabel: t('landing.hex1LinkLabel'), + }, + { + icon: 'M8 12a4 4 0 1 0 0.01 0 M12 12h9 M18 12v4 M21 12v3', + num: t('landing.hex2Num'), + title: t('landing.hex2Title'), + sub: t('landing.hex2Sub'), + body: t('landing.hex2Body'), + code: 'POST /sdk/developer-tokens\n→ { "jwt": "eyJhbG…", "key": "rk_live_…",\n "scopes": ["write:packages"] }', + link: `${base}/reference/rest-api/`, + linkLabel: t('landing.hex2LinkLabel'), + }, + { + icon: 'M4 12l5 5L20 6', + num: t('landing.hex3Num'), + title: t('landing.hex3Title'), + sub: t('landing.hex3Sub'), + body: t('landing.hex3Body'), + code: 'X-Developer-Token: \nPOST /sdk/tokens/verify → { "valid": true }', + link: `${base}/reference/rest-api/`, + linkLabel: t('landing.hex3LinkLabel'), + }, + ] +} + +/** Feature cards below the hive. */ +export function buildFeatures(t: Translator): FeatureCard[] { + return [ + { + t: t('landing.feat1T'), + d: t('landing.feat1D'), + icon: 'M12 2l7 4v6c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6l7-4z', + }, + { + t: t('landing.feat2T'), + d: t('landing.feat2D'), + icon: 'M7 7h10v10H7z M10 2v3 M14 2v3 M10 19v3 M14 19v3 M2 10h3 M2 14h3 M19 10h3 M19 14h3', + }, + { + t: t('landing.feat3T'), + d: t('landing.feat3D'), + icon: 'M4 6h16 M4 12h16 M4 18h10', + }, + ] +} + +/** Third nav item per locale registry (ADR index or configuration). */ +export function buildThirdNav(t: Translator, base: string, navThird: string): ThirdNav { + return navThird === 'config' + ? { label: t('landing.navConfig'), href: `${base}/guide/configuration/` } + : { label: t('landing.navAdrs'), href: `${base}/adr/` } +} diff --git a/Docs/src/lib/chrome/section-accents.ts b/Docs/src/lib/chrome/section-accents.ts new file mode 100644 index 0000000..7d65397 --- /dev/null +++ b/Docs/src/lib/chrome/section-accents.ts @@ -0,0 +1,21 @@ +// Per page accent hues for section pages. Single source of truth — +// SectionChrome resolves, CSS consumes via --sec-accent. Open for extension: +// add page key, no component changes needed. +export const SECTION_ACCENTS: Record = { + devtokens: '#34d399', + devtools: '#38bdf8', + custom: '#fbbf24', + plugins: '#a78bfa', + marten: '#fb923c', + keycloak: '#60a5fa', + wolverine: '#f43f5e', + docker: '#22d3ee', + infrastructure: '#2dd4bf', +} + +const FALLBACKS: Record = { INFRA: '#2dd4bf', PLUGIN: '#34d399' } + +/** Resolve the accent color for section page. Pure — trivially testable. */ +export function resolveAccent(name: string, section: string): string { + return SECTION_ACCENTS[name.toLowerCase()] ?? FALLBACKS[section] ?? FALLBACKS.PLUGIN +} From 63aeadae52268ed12357f2a9c805a0d20246622b Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 01:39:57 +0200 Subject: [PATCH 10/17] feat: initialize SveltePress documentation site --- Docs/src/app.d.ts | 1 + Docs/src/app.html | 14 +++++++++++++ Docs/src/hooks.server.ts | 17 +++++++++++++++ Docs/svelte.config.ts | 16 ++++++++++++++ Docs/tsconfig.json | 22 ++++++++++++++++++++ Docs/vite.config.ts | 45 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 Docs/src/app.d.ts create mode 100644 Docs/src/app.html create mode 100644 Docs/src/hooks.server.ts create mode 100644 Docs/svelte.config.ts create mode 100644 Docs/tsconfig.json create mode 100644 Docs/vite.config.ts diff --git a/Docs/src/app.d.ts b/Docs/src/app.d.ts new file mode 100644 index 0000000..71b7bd5 --- /dev/null +++ b/Docs/src/app.d.ts @@ -0,0 +1 @@ +/// diff --git a/Docs/src/app.html b/Docs/src/app.html new file mode 100644 index 0000000..5c8b024 --- /dev/null +++ b/Docs/src/app.html @@ -0,0 +1,14 @@ + + + + + + + %sveltekit.head% + + +
+ %sveltekit.body% +
+ + \ No newline at end of file diff --git a/Docs/src/hooks.server.ts b/Docs/src/hooks.server.ts new file mode 100644 index 0000000..07e85a1 --- /dev/null +++ b/Docs/src/hooks.server.ts @@ -0,0 +1,17 @@ +import { sequence } from '@sveltejs/kit/hooks' +import { createLocaleHandle } from '@sveltepress/vite/hooks' +import { paraglideMiddleware } from './lib/paraglide/server' +// side effect: registers the "custom-sveltepress" strategy (URL prefix → locale) +import './lib/locale-strategy' +import { locales } from './locales' + +const paraglideHandle = ({ event, resolve }) => + paraglideMiddleware(event.request, ({ request, locale }) => { + event.request = request + return resolve(event, { + transformPageChunk: ({ html }) => + html.replace('%paraglide.lang%', locale), + }) + }) + +export const handle = sequence(paraglideHandle, createLocaleHandle(locales)) diff --git a/Docs/svelte.config.ts b/Docs/svelte.config.ts new file mode 100644 index 0000000..d7a4272 --- /dev/null +++ b/Docs/svelte.config.ts @@ -0,0 +1,16 @@ +import adapter from '@sveltejs/adapter-static'; +import type { Config } from '@sveltejs/kit'; + +const config: Config = { + extensions: ['.svelte', '.md'], + kit: { + adapter: adapter({ + fallback: 'index.html' + }), + prerender: { + entries: ['/', '/en/', '/pl/'] + } + } +}; + +export default config; diff --git a/Docs/tsconfig.json b/Docs/tsconfig.json new file mode 100644 index 0000000..3ac2613 --- /dev/null +++ b/Docs/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "allowImportingTsExtensions": true, + "types": ["node", "vite/client"], + "extends": "./.svelte-kit/tsconfig.json" + }, + "include": [ + "src/**/*.{js,ts}", + "scripts/**/*.ts", + "vite.config.ts", + "svelte.config.js" + ], + "exclude": [ + "node_modules", + ".svelte-kit" + ] +} \ No newline at end of file diff --git a/Docs/vite.config.ts b/Docs/vite.config.ts new file mode 100644 index 0000000..9fc3314 --- /dev/null +++ b/Docs/vite.config.ts @@ -0,0 +1,45 @@ +import { defaultTheme } from '@sveltepress/theme-default' +import { sveltepress } from '@sveltepress/vite' +import tailwindcss from '@tailwindcss/vite' +import { paraglideVitePlugin } from '@inlang/paraglide-js' +import { defineConfig } from 'vite' +import { locales, codeLanguages, enSidebar } from './src/locales' + +export default defineConfig({ + plugins: [ + tailwindcss(), + paraglideVitePlugin({ + project: './project.inlang', + outdir: './src/lib/paraglide' + }), + sveltepress({ + theme: defaultTheme({ + highlighter: { languages: [...codeLanguages] }, + themeColor: { + primary: '#e4e4e7', + primaryDeep: '#18181b', + hover: '#f4f4f5', + }, + navbar: [ + { + label: 'AuthKit', + items: [ + { label: 'Home', link: '/en/' }, + { label: 'Introduction', link: '/en/guide/introduction/' }, + ], + }, + ], + sidebar: enSidebar, + github: 'https://github.com/AuthKits/AuthKit.Server' + }), + locales, + siteConfig: { + title: 'AuthKit Documentation', + description: 'Documentation for AuthKit.Server' + }, + llms: { + enabled: true + } + }) + ] +}) \ No newline at end of file From ffc0dd02ea131a36fd52a2d9e1ec4d6b34f8d82e Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 01:42:21 +0200 Subject: [PATCH 11/17] feat: localize docs navigation and landing pages --- Docs/i18n/messages/en.json | 83 ++++++++++++++++++++++++++++++++++++++ Docs/i18n/messages/pl.json | 83 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 Docs/i18n/messages/en.json create mode 100644 Docs/i18n/messages/pl.json diff --git a/Docs/i18n/messages/en.json b/Docs/i18n/messages/en.json new file mode 100644 index 0000000..a6dd1e9 --- /dev/null +++ b/Docs/i18n/messages/en.json @@ -0,0 +1,83 @@ +{ + "meta": { + "label": "English", + "short": "EN", + "navThird": "adr" + }, + "theme": { + "light": "Light", + "dark": "Dark" + }, + "themeToggle": { + "switchToLight": "Switch to light mode", + "switchToDark": "Switch to dark mode" + }, + "locale": { + "language": "Language", + "unavailable": "This page is not available in this language yet." + }, + "navbar": { + "home": "Home", + "schemas": "Schemas & Diagrams", + "github": "GitHub" + }, + "docs": { + "introduction": "Introduction", + "quickStart": "Quick Start", + "configuration": "Configuration", + "restApi": "REST API", + "schemas": "Schemas", + "adrOverview": "ADR Overview", + "grpc": "gRPC", + "plugins": "Plugins", + "devTokens": "DevTokens", + "devTools": "DevTools", + "customPlugins": "Custom plugins", + "guide": "Guide", + "reference": "Reference", + "infrastructure": "Infrastructure", + "keycloak": "Keycloak", + "marten": "Marten + PostgreSQL", + "wolverine": "Wolverine", + "docker": "Docker + Kestrel" + }, + "landing": { + "metaTitle": "AuthKit Developer Authentication & SDK Access", + "metaDescription": "Plugin based service for developer authentication, SDK token issuance and access verification.", + "navDocs": "Docs", + "navApi": "API", + "navAdrs": "ADRs", + "navConfig": "Config", + "navGithub": "GitHub", + "heroTitleA": "Authentication for", + "heroTitleB": "the age of SDKs.", + "heroSub": "AuthKit verifies developers through Keycloak, issues scoped tokens, and lets any API verify them. Plugin-based, auditable, boring in all the right places.", + "heroPrimary": "Get started", + "heroSecondary": "Quick start →", + "flowLabel": "Token flow", + "detailsMore": "details +", + "dialogClose": "Close", + "hex1Num": "01 / WHO YOU ARE", + "hex1Title": "Authenticate", + "hex1Sub": "Authorization: Bearer ", + "hex1Body": "Everything starts with Keycloak. The developer signs in there AuthKit never sees or stores a password. Each API call carries the Keycloak access token in the Authorization header, and AuthKit validates its signature, expiry and roles before doing anything else. The verified identity is what all later tokens get bound to.", + "hex1LinkLabel": "How AuthKit works →", + "hex2Num": "02 / GET A TOKEN", + "hex2Title": "POST /sdk/developer-tokens", + "hex2Sub": "→ jwt + rk_live_… + scopes", + "hex2Body": "With a valid Keycloak token you request a developer token: name it, pick scopes like write:packages and a lifetime in days. AuthKit signs a JWT, generates rk_live_… key for it and returns both. Scopes and expiry live inside the token no lookup needed later. Cap is MaxDeveloperTokens per developer.", + "hex2LinkLabel": "Token endpoints →", + "hex3Num": "03 / PROVE IT", + "hex3Title": "POST /sdk/tokens/verify", + "hex3Sub": "X-Developer-Token → valid · scopes", + "hex3Body": "The SDK attaches the developer JWT as X-Developer-Token next to the Keycloak bearer token. The target API asks AuthKit to verify it signature, expiry, revocation and scopes or checks the signature itself offline using the JWKS endpoint. One call answers: is this token valid, and may it touch this scope?", + "hex3LinkLabel": "Verification API →", + "feat1T": "Keycloak-native identity", + "feat1D": "No passwords stored, ever. Developers sign in via Keycloak; every token issued is bound to a verified identity with explicit scopes.", + "feat2T": "Scoped developer tokens", + "feat2D": "Short lived signed JWTs with embedded scopes and lifetime. Verify online, or offline at the edge with JWKS no database round trip.", + "feat3T": "One host, two transports", + "feat3D": "The same surface over REST and gRPC. Wolverine dispatches, Marten on PostgreSQL stores the audit trail, plugins extend everything.", + "mit": "AuthKit MIT" + } +} diff --git a/Docs/i18n/messages/pl.json b/Docs/i18n/messages/pl.json new file mode 100644 index 0000000..67fd536 --- /dev/null +++ b/Docs/i18n/messages/pl.json @@ -0,0 +1,83 @@ +{ + "meta": { + "label": "Polski", + "short": "PL", + "navThird": "adr" + }, + "theme": { + "light": "Jasny", + "dark": "Ciemny" + }, + "themeToggle": { + "switchToLight": "Przełącz na tryb jasny", + "switchToDark": "Przełącz na tryb ciemny" + }, + "locale": { + "language": "Język", + "unavailable": "Ta strona nie jest jeszcze dostępna w tym języku." + }, + "navbar": { + "home": "Strona główna", + "schemas": "Schematy i diagramy", + "github": "GitHub" + }, + "docs": { + "introduction": "Wprowadzenie", + "quickStart": "Szybki start", + "configuration": "Konfiguracja", + "restApi": "REST API", + "schemas": "Schematy", + "adrOverview": "Przegląd ADR", + "grpc": "gRPC", + "plugins": "Wtyczki", + "devTokens": "DevTokens", + "devTools": "DevTools", + "customPlugins": "Własne wtyczki", + "guide": "Przewodnik", + "reference": "Dokumentacja", + "infrastructure": "Infrastruktura", + "keycloak": "Keycloak", + "marten": "Marten + PostgreSQL", + "wolverine": "Wolverine", + "docker": "Docker + Kestrel" + }, + "landing": { + "metaTitle": "AuthKit Uwierzytelnianie deweloperów i dostęp do SDK", + "metaDescription": "Usługa oparta na wtyczkach do uwierzytelniania deweloperów, wydawania tokenów SDK i weryfikacji dostępu.", + "navDocs": "Docs", + "navApi": "API", + "navAdrs": "ADRs", + "navConfig": "Konfig", + "navGithub": "GitHub", + "heroTitleA": "Uwierzytelnianie", + "heroTitleB": "w epoce SDK.", + "heroSub": "AuthKit weryfikuje deweloperów przez Keycloak, wydaje tokeny o wąskich zakresach i pozwala każdemu API je weryfikować. Oparty na wtyczkach, audytowalny, nudny tam, gdzie trzeba.", + "heroPrimary": "Zacznij", + "heroSecondary": "Szybki start →", + "flowLabel": "Przepływ tokenu", + "detailsMore": "szczegóły +", + "dialogClose": "Zamknij", + "hex1Num": "01 / KIM JESTEŚ", + "hex1Title": "Uwierzytelnij", + "hex1Sub": "Authorization: Bearer ", + "hex1Body": "Wszystko zaczyna się w Keycloak. Deweloper loguje się tam AuthKit nigdy nie widzi ani nie trzyma hasła. Każde wywołanie API niesie token dostępowy Keycloak w nagłówku Authorization, a AuthKit weryfikuje jego podpis, ważność i role. Do zweryfikowanej tożsamości wiązane są wszystkie późniejsze tokeny.", + "hex1LinkLabel": "Jak działa AuthKit →", + "hex2Num": "02 / WEŹ TOKEN", + "hex2Title": "POST /sdk/developer-tokens", + "hex2Sub": "→ jwt + rk_live_… + scopes", + "hex2Body": "Z ważnym tokenem Keycloak prosisz o token deweloperski: nadajesz nazwę, wybierasz zakresy jak write:packages i czas życia w dniach. AuthKit podpisuje JWT, generuje do niego klucz rk_live_… i zwraca oba. Zakresy i ważność siedzą w tokenie później nic nie trzeba dopytywać. Limit to MaxDeveloperTokens na dewelopera.", + "hex2LinkLabel": "Endpointy tokenów →", + "hex3Num": "03 / UDOWODNIJ", + "hex3Title": "POST /sdk/tokens/verify", + "hex3Sub": "X-Developer-Token → valid · scopes", + "hex3Body": "SDK dokleja deweloperski JWT jako X-Developer-Token obok tokenu Keycloak. Docelowe API prosi AuthKit o weryfikację podpis, ważność, unieważnienia i zakresy albo sprawdza podpis samodzielnie offline przez endpoint JWKS. Jedno wywołanie odpowiada: czy token jest ważny i czy wolno mu tknąć ten zakres?", + "hex3LinkLabel": "API weryfikacji →", + "feat1T": "Tożsamość z Keycloak", + "feat1D": "Zero przechowywanych haseł. Deweloperzy logują się przez Keycloak; każdy wydany token jest powiązany ze zweryfikowaną tożsamością i jawnymi zakresami.", + "feat2T": "Tokeny o wąskich zakresach", + "feat2D": "Krótko żyjące, podpisane JWT z wbudowanymi zakresami i czasem życia. Weryfikacja online albo offline na brzegu przez JWKS bez zaglądania do bazy.", + "feat3T": "Jeden host, dwa transporty", + "feat3D": "Ta sama powierzchnia przez REST i gRPC. Wolverine dystrybuuje, Marten na PostgreSQL trzyma ślad audytowy, wtyczki rozszerzają wszystko.", + "mit": "AuthKit MIT" + } +} From 3e86e07b0575f7f21fd0267cbcd6146a14d9b716 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:03:33 +0200 Subject: [PATCH 12/17] feat: configure SveltePress versioning and localization --- Docs/package-lock.json | 14344 ++++++++++++++++++++++++++++ Docs/package.json | 32 + Docs/project.inlang/settings.json | 19 + Docs/sveltepress.versions.en.json | 22 + Docs/sveltepress.versions.json | 95 + Docs/sveltepress.versions.pl.json | 22 + 6 files changed, 14534 insertions(+) create mode 100644 Docs/package-lock.json create mode 100644 Docs/package.json create mode 100644 Docs/project.inlang/settings.json create mode 100644 Docs/sveltepress.versions.en.json create mode 100644 Docs/sveltepress.versions.json create mode 100644 Docs/sveltepress.versions.pl.json diff --git a/Docs/package-lock.json b/Docs/package-lock.json new file mode 100644 index 0000000..1db9cba --- /dev/null +++ b/Docs/package-lock.json @@ -0,0 +1,14344 @@ +{ + "name": "@authkit/docs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@authkit/docs", + "dependencies": { + "@humanspeak/svelte-motion": "^1.2.1" + }, + "devDependencies": { + "@inlang/paraglide-js": "^2.25.4", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.48.3", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "@sveltepress/cli": "^0.4.3", + "@sveltepress/theme-default": "^8.9.0", + "@sveltepress/vite": "^1.8.3", + "@tailwindcss/vite": "^4.1.12", + "@types/node": "^22.15.0", + "mermaid": "^11.12.0", + "svelte": "^5.57.0", + "tailwindcss": "^4.1.12", + "tsx": "^4.20.5", + "typescript": "^5.9.2", + "vite": "^8.3.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-2.1.0.tgz", + "integrity": "sha512-sdg9NxU3zR4Mnawfbc/x6GB5Wf17WYud5qOuEuxXjaKpYpMkISSJEjItGebXJ2bQ4DIcly4NYH23mtkGJjvKUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.8.0", + "tinyexec": "^1.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@apideck/better-ajv-errors": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.7.tgz", + "integrity": "sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonpointer": "^5.0.1", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz", + "integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz", + "integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz", + "integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@bytecodealliance/jco-node-fs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs/-/jco-node-fs-0.3.2.tgz", + "integrity": "sha512-yxvqQreNcOQdMsEKZomkSqThtkxrAz3f1Cmy8BsV0UHi9saa2/D1KDB14IAXPYwDq/maS6lCzS+MuMQx6QkUgA==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@bytecodealliance/jco-node-fs-darwin-arm64": "0.3.2", + "@bytecodealliance/jco-node-fs-darwin-x64": "0.3.2", + "@bytecodealliance/jco-node-fs-linux-arm64-gnu": "0.3.2", + "@bytecodealliance/jco-node-fs-linux-arm64-musl": "0.3.2", + "@bytecodealliance/jco-node-fs-linux-x64-gnu": "0.3.2", + "@bytecodealliance/jco-node-fs-linux-x64-musl": "0.3.2", + "@bytecodealliance/jco-node-fs-win32-arm64-msvc": "0.3.2", + "@bytecodealliance/jco-node-fs-win32-x64-msvc": "0.3.2" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-darwin-arm64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-darwin-arm64/-/jco-node-fs-darwin-arm64-0.3.2.tgz", + "integrity": "sha512-WXQq1tRVUWhbK+ImH0G8Kni2AR0sdokLf/KyXRw5P6n4A9ZbgMHOuPfN/PEsYgw4eosuTAonutK0xILk/hA81A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-darwin-x64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-darwin-x64/-/jco-node-fs-darwin-x64-0.3.2.tgz", + "integrity": "sha512-Fy/OjHnto7hNE5ksewVkmAMXG/uXyj+RAKFZWQFTzFkp73UyT5vuPjKq3nvx9KolUGWBG37BudEMb4ZAoD9TbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-linux-arm64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-linux-arm64-gnu/-/jco-node-fs-linux-arm64-gnu-0.3.2.tgz", + "integrity": "sha512-OafRtRu3tfOFQARfkia/LDEqSo2R3yAL1xPwzf4RcRW6JqkOY7qKWsUS5+LPVo/aFaSkMX7F7bdFGpFPmcoZJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-linux-arm64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-linux-arm64-musl/-/jco-node-fs-linux-arm64-musl-0.3.2.tgz", + "integrity": "sha512-JblDiwD7+Y+w0d/tjaNDX4QdGvh5lyuDc+S/jDeT7sYA1caA9yiwIjLa8PC/lm2xudqSxD+Cuy4AosXvl+qI0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-linux-x64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-linux-x64-gnu/-/jco-node-fs-linux-x64-gnu-0.3.2.tgz", + "integrity": "sha512-6FzmHoLOsa6b4X9AuFLsvlpNF66Dt4sRRftZHaT1I1pYzCWrJkkpgNJhRXxf67ZPmOwBZJT4dan/g752Rx4xRw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-linux-x64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-linux-x64-musl/-/jco-node-fs-linux-x64-musl-0.3.2.tgz", + "integrity": "sha512-SbAJG2PDV8YAHBESHU9sVSckOitJyvlezdF4CGP5/mOp01JnijVkLVXzGK62yVSfa5TpAybbSd1rk+v36NAW/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-win32-arm64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-win32-arm64-msvc/-/jco-node-fs-win32-arm64-msvc-0.3.2.tgz", + "integrity": "sha512-nUWYdFysRQJGsIOCk0KAYN2smkNYiHG7rZ7m+0ZXqP+5wqWxKEjkDsORwXiBjdaWFLVww0anZ3SBxrju6P7hXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-node-fs-win32-x64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-node-fs-win32-x64-msvc/-/jco-node-fs-win32-x64-msvc-0.3.2.tgz", + "integrity": "sha512-RsPj2t8TvltsMWK7/Z7JcVC/IWPMi07/AJkNLiNTCuGTdT/sseqTThJJwhuz3sjFw7dJdxA+bSGT+23y/KT0fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@bytecodealliance/jco-transpile": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/jco-transpile/-/jco-transpile-0.13.0.tgz", + "integrity": "sha512-9hZ2GMqOlYP1Bf7qQ8v3sCsmkFoXGbgi0HtjHipzrgyk+9GGDzvvbehTGe0oM54rcbKJacvyjpPDn7wtpgzwYA==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "dependencies": { + "@bytecodealliance/preview2-shim": "^0.24.1", + "@bytecodealliance/preview3-shim": "^0.6.0", + "binaryen": "^130.0.0", + "oxc-minify": "^0.136.0" + } + }, + "node_modules/@bytecodealliance/preview2-shim": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.24.1.tgz", + "integrity": "sha512-QGZsKD5M76xBhwu3BzLWqYDEpaMX90QWrrfhkQPn2pN9t378koumtdAVH4lr25mqGCZt10YNXkWvyWkw/vJbLQ==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "dependencies": { + "@bytecodealliance/jco-node-fs": "0.3.2" + } + }, + "node_modules/@bytecodealliance/preview3-shim": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview3-shim/-/preview3-shim-0.6.1.tgz", + "integrity": "sha512-61mEfjfgGmZhEMA0H3waawPKvYd3za9y0vJ7pmQz/9yvm4FR6Ef+cmqhnxDE7ezsM07MY1btP92ymmgsgFwxmg==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "dependencies": { + "@bytecodealliance/jco-node-fs": "0.3.2", + "@bytecodealliance/preview2-shim": "^0.25.0" + } + }, + "node_modules/@bytecodealliance/preview3-shim/node_modules/@bytecodealliance/preview2-shim": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@bytecodealliance/preview2-shim/-/preview2-shim-0.25.0.tgz", + "integrity": "sha512-6ZSDRJ8hJc/febZepzd68z3KzLcOXyCOKtRm8LB2rgAU88xV7ykq6dMb5I4a+sBh1cuV2Yb1159gDzI1q8UsoQ==", + "dev": true, + "license": "(Apache-2.0 WITH LLVM-exception)", + "dependencies": { + "@bytecodealliance/jco-node-fs": "0.3.2" + } + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@docsearch/css": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.7.0.tgz", + "integrity": "sha512-Sk5xkdRFeE7PeWjG9l4AfTwdvMfr9wHiwNNCpHXT4v4SNyNMKdHGvEILc31BgaVFGDDNbv5u/a73tofRiwbEZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@docsearch/js": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-4.7.0.tgz", + "integrity": "sha512-x5lCqu1tetgsJFkjQ6VSocbHldsRkGEgwg5N98Vx21sq/V5wcmj4u226PY9k+TEpIgQ772zlYbPLTPicWyGnpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanspeak/svelte-motion": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanspeak/svelte-motion/-/svelte-motion-1.2.1.tgz", + "integrity": "sha512-dnYL9ih+bJ0myIcBZSYHSKGMnibuoPJrKcMrGGPa3XOgjOACUUrw/MYyIv2q4ufNErQE259Yg+PZjd7ux7shvg==", + "license": "MIT", + "dependencies": { + "acorn": "^8.18.0", + "motion": "^13.2.0", + "motion-dom": "^13.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/humanspeak" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.7.tgz", + "integrity": "sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^2.0.1", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@inlang/paraglide-js": { + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/@inlang/paraglide-js/-/paraglide-js-2.25.4.tgz", + "integrity": "sha512-z8OoKAcPT0DwlfTQ/SvaPBQILrtmkl4lUPCSQPjKxqERRp1n7W7a2eKi7EvfylatWivSZFGHGjlB6Ad20w0nzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inlang/recommend-sherlock": "^0.2.1", + "@inlang/sdk": "^3.0.6", + "commander": "11.1.0", + "consola": "3.4.0", + "jiti": "^2.7.0", + "json5": "2.2.3", + "unplugin": "^2.1.2", + "urlpattern-polyfill": "^10.0.0", + "valibot": "^1.4.2" + }, + "bin": { + "paraglide-js": "bin/run.js" + }, + "peerDependencies": { + "typescript": ">=5.6", + "vite": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@inlang/paraglide-js/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/@inlang/paraglide-js/node_modules/consola": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", + "integrity": "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/@inlang/recommend-sherlock": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@inlang/recommend-sherlock/-/recommend-sherlock-0.2.1.tgz", + "integrity": "sha512-ckv8HvHy/iTqaVAEKrr+gnl+p3XFNwe5D2+6w6wJk2ORV2XkcRkKOJ/XsTUJbPSiyi4PI+p+T3bqbmNx/rDUlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "comment-json": "^4.2.3" + } + }, + "node_modules/@inlang/sdk": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@inlang/sdk/-/sdk-3.0.6.tgz", + "integrity": "sha512-JyUxQNjKNWglT8qhInmenKK/AnKkbX9AhAM8vFnTT8SyQ0gFA2YGKPntGp+3+UZP9F06Nmawf4sFTn7nGIyTXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lix-js/sdk": "0.17.0", + "@sinclair/typebox": "^0.31.17", + "kysely": "^0.28.12", + "uuid": "^14.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lix-js/sdk": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@lix-js/sdk/-/sdk-0.17.0.tgz", + "integrity": "sha512-xplbKYEokKbm0/soUy9eXlROF55Si1J9HK97iwJrNl/av1VixZ2mvpDTa0QsX96UyxFnzkXru6hngjtIJTl73g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bytecodealliance/jco-transpile": "0.13.0", + "binaryen": "130.0.0", + "fflate": "^0.8.3" + }, + "optionalDependencies": { + "@lix-js/sdk-darwin-arm64": "0.17.0", + "@lix-js/sdk-linux-arm64": "0.17.0", + "@lix-js/sdk-linux-x64": "0.17.0", + "@lix-js/sdk-win32-x64": "0.17.0" + } + }, + "node_modules/@lix-js/sdk-darwin-arm64": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@lix-js/sdk-darwin-arm64/-/sdk-darwin-arm64-0.17.0.tgz", + "integrity": "sha512-+r74U7uBNfzgHEkxJAo4VkwQugqfk3MYZ5GHUIZnWZyyU1+oecXTmeepiaMnmHuflMPVv6ZfE4Yl8eM0Wyn+lw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lix-js/sdk-linux-arm64": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@lix-js/sdk-linux-arm64/-/sdk-linux-arm64-0.17.0.tgz", + "integrity": "sha512-4HqHHsWq1gfPgkReR43Sy18T10JmRSo+VVR3Kqr/xu5zD/2ssoGdtl9QEpC80KVn4pCT5vDCysT1UOwEJkv7iA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lix-js/sdk-linux-x64": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@lix-js/sdk-linux-x64/-/sdk-linux-x64-0.17.0.tgz", + "integrity": "sha512-968kHRX0waV5UoR4i0HZkqNr5KDOWPd4he3miLImCMGsQDWLViYde613Bf4hxas/SouCSfmnvlAnl87oSAZc8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lix-js/sdk-win32-x64": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@lix-js/sdk-win32-x64/-/sdk-win32-x64-0.17.0.tgz", + "integrity": "sha512-/uYvg0c5R9+BtQ1aJqBE9VCwNSYSaZORUjo5u6ukAFkH7XuN1ZnpTzoI9K6HE82/dxlCymMsP3Ga/rQVpQn4hA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.1.tgz", + "integrity": "sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.2" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.4.tgz", + "integrity": "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=23.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", + "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" + } + }, + "node_modules/@oxc-minify/binding-android-arm-eabi": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.136.0.tgz", + "integrity": "sha512-gk1jzky1vLeOcK7w9Ib2RT/UooZ7O21s8YSeXCsy4tzsmguKb3Cbsv/Ra2fKhMp4mKeKCzvC1Xa41OfSBWfWdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-android-arm64": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.136.0.tgz", + "integrity": "sha512-5GIYanqud/ohXEcg2dsdn0+eSKXqclw5qlRUkvSM1sKEa4ZQ7hqOk8XPJBNPh3LXXw+Qw85B6jkmOFLKsCHp5w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-darwin-arm64": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.136.0.tgz", + "integrity": "sha512-QAMpHKXWOoMCTenSZjQjVT5YmMooujlCKAf1T3PHFl2LuaA6ukQFXba0bgSLgAxRrAeX/itkwi4lzVQXtYmnRg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-darwin-x64": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.136.0.tgz", + "integrity": "sha512-rDnoPj8hztiU8C1VNKuzujh7SgTJlgiUvUCiWQjTnVSLsABsLW9ZWd1l1Ji0VN3UW39wGpptgvahIWTrHnGH/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-freebsd-x64": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.136.0.tgz", + "integrity": "sha512-9fGSgP7uyPLCTjMx9z3AUV4UjnfOVoGTH5JzamLegPwGLJ97Gr1jht1437CRk8ZNabGmxQR6qNn3e+Tox2lswg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.136.0.tgz", + "integrity": "sha512-k0QvZS+x6ROI4O5Ikqn9dDU2dmkEJ46Yh6baZJI/eUk/a1k1GOs9/vyXItLZrKlwYrSgdEx2BFXbKgyd1NyRPw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm-musleabihf": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.136.0.tgz", + "integrity": "sha512-iRFxUc8ubotVfuyq3e4LPGbHrjvWd1/B3499a55GueMLc1EDJ0fHzNXJiCx2eMQGfzHtHodjmvrJ2BSvSXBNhQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm64-gnu": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.136.0.tgz", + "integrity": "sha512-hbKxNCXJsULrb6EyG5SumzJKuPfP8Y0UQ/TElRgXVUhyyPf6cBPlF8HMq+MAylF98ACBzV8jBp2Mm62lJyTo+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm64-musl": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.136.0.tgz", + "integrity": "sha512-T+u/CGKW0UXemJeVux4ix6rK+ug3bQCUEbu5hFlX9K61KQNd44rOcrM15mDK99L7USaXwmiwHeIkEDvmmyDMSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-ppc64-gnu": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.136.0.tgz", + "integrity": "sha512-WNPTN2F448tb49BoqjV9IMRzZWa0WB8GHzrB+bnxKQPOyzz07T6rmDKrr4Hjl81ADGjDYSsr1fgXcjyLQFdMdw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-riscv64-gnu": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.136.0.tgz", + "integrity": "sha512-MvcCfu8OeabrmNN9wqhh8Gqizg68RQ3iOvXBJmlLMy5p1PC6az9bAwqOk98lsCmKI4I5LpULekOlfxRYh3o5Kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-riscv64-musl": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.136.0.tgz", + "integrity": "sha512-rwJXFUFFA0egAULtOOgfW8YhhLhtWrr2qFxftvZ7/U6Xtxiev8i+eCwSNW1RpHiX74QMsJVpRE3ykoefqb1MtQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-s390x-gnu": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.136.0.tgz", + "integrity": "sha512-qizAxHmj7VHm5/D5qiIlvzxAS2tlmadDOJ5XFI7zx/wfnk/+fdk5iVaHOv+C4tDE/4wLQyMoBYVIs6R1LeN91w==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-x64-gnu": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.136.0.tgz", + "integrity": "sha512-gcyLAad0UblkEhGjVfx5Mwq63OSx8r04IbcfwzpZYpHisO/vioMsrs4GkDsQZ2Ejc8cdUk6YMIrf9FwNBzh+Dw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-linux-x64-musl": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.136.0.tgz", + "integrity": "sha512-QAK6kwBjljX6luYzeppVdRP3gTaFNFfp9iS/V0cCvU43wUZay5xFXBgmzBHYrzZV2MhzURNnXfEZRo9poAxyvA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-openharmony-arm64": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.136.0.tgz", + "integrity": "sha512-nIGxkTOnN9GwslmooxbZ3Ti2RgbX9QLHy0X9uO0pslOT+4dsNVUawBU/6r4M5cWM+ZdRD2tOF4V+n0l8tS59nQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-wasm32-wasi": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.136.0.tgz", + "integrity": "sha512-YB3G8AHT6PpDS8/DfjlJrQjywj+/6gCkNBcAJdYzcYbQRIZE6SaTNowiGuZPR1m1jOl1WjcjefniKSmVxzhvRA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.5" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@oxc-minify/binding-win32-arm64-msvc": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.136.0.tgz", + "integrity": "sha512-UVRH3BlNc2rmla+sbSd5xTF/u+esCqZS6VSWPolZybcBh3TlVe1Sf5MOuHQWUaFoyv5uFOvee4hOfS/14nPvZw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-win32-ia32-msvc": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.136.0.tgz", + "integrity": "sha512-zFGkUd82jci0E+isc2O36lVmmXVUDXyEMN2RYIyez+MBNqhdjPLIGx62FCsrJtLKeuiPf/8XkFv977aUtndUng==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-minify/binding-win32-x64-msvc": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.136.0.tgz", + "integrity": "sha512-VHgPwd5xibC9UYxBeq7nURTjY+wxhdumllij6JaCIUVfD9IRcrA66SVlJ5fPNoUXcRp8ZXhJfoIZwVz9wAEGJw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm-eabi": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.150.0.tgz", + "integrity": "sha512-oQef2Zu4Prz1KLKznz3HqZzU9uVoA5PMoDZuuLmqms7hKmKSAPzlaMnLllJq3t+rgKmfJJ2siPrpZfFrW06btw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.150.0.tgz", + "integrity": "sha512-B6ofpoFiAUwIZ0MJ2IgHPvZK8FAtL4qzSZRwOkAKIfxEobE1mQC8nDdiFZj7pUaJiVUVCsfkMsBJKedzO8rZvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.150.0.tgz", + "integrity": "sha512-J+9IHKzx/bSz1JetOfD4zKXSK9sOm4/a7+0qomJODcTL6JsRXGeV/ZdkAPSIDydfFmWzYCraMlQEosSZEyBYkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.150.0.tgz", + "integrity": "sha512-v6IPfcAcSYrBWXV5Tce1DmxDMXLhEYpIIWiRFPJopgCVscZdLaV4MRQOUxvL3usQlw+yrwYOjBFB9IwBx+jUiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.150.0.tgz", + "integrity": "sha512-AoR/4jD02HET0KO0yNT4nbTE+XJUxiO9jB1X/ycEjUE3WrIJ3IjV/Vf+gskhWLcqqeXfvNnkDtBR7epllAm88A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.150.0.tgz", + "integrity": "sha512-A/hycCFjLUrCmLoL5O/vBp40ohlaXO1Ta3v5hqYZxicYFs129wZmgZJggcW4mYGYbZebQLhup+N8JjeQl8qwyw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.150.0.tgz", + "integrity": "sha512-pbqahg1Pkz7J4RKmXm30s/iQu99hv64ayXCu8P4p75HcEH5azOdR4eGqiB6lFGkFR3mMpzaYsSKLkS8oJbjmeQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.150.0.tgz", + "integrity": "sha512-HV11aRbBQGwqv8bEo+K/6qr88uB4fEe1mhXncMhlVCrj+WpBSraxrUzHaPVmeQRU6x6x8v/3DuCbbo93rpp+fw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.150.0.tgz", + "integrity": "sha512-k6pVkJqALwtEuP4zukVhGRhdIy4+ofChUIUUsAHHyqDZlNsknmel3JjbggrJiWGaes6h/dIcWmEXsKW4SmK9oQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.150.0.tgz", + "integrity": "sha512-tEFg39mw/rHO5n8GK2DR4ZMFfsPQZtnQIPbsIpjoQRomJc/2tRfsCSmCT6gNit+NZGoeJG5aH9ATDH5bf0WnoQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.150.0.tgz", + "integrity": "sha512-0JO7IFkoek6HqV589Menx3hJySNXi6quRhO4tq2P7kpEHKEXoDATnoPVUpn5B7gDH2KLkdo751N0uIrGJFCTCw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-musl": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.150.0.tgz", + "integrity": "sha512-7XPzREnyAS5wHU9aB+49Uaqgoo1gVCklHc3DRlc3fJy2tXD/eAJFN1QFz/crj+Ulup5P1+axNREF+/RGaB/IRA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.150.0.tgz", + "integrity": "sha512-7n7ZxcbRWDFaTdyj8M8p0O9OfzoMKm8O6syBAIgcSutbOALq0Bb9G52Me+XH0anMLZV+NgXc726gqgG2q39vcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.150.0.tgz", + "integrity": "sha512-Vx0GSA9ZCRTUiczoEQnIIyXkMvtEY8uc6IiwLQtMe5ci2sXPqjrry0Ek5fsPP1k2kCzkML3ow9UOOEgnEDi7Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.150.0.tgz", + "integrity": "sha512-ii4/9m3viDLssMnfXU7/Pni/3nYplApuGayceX4qsVGaqqQJCx3tHIH9M/HWIeSty5i8LjS21zPYT6lVIkwLxw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-openharmony-arm64": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.150.0.tgz", + "integrity": "sha512-ZtoxX5rez36ZWkwtiEhjkCPnlTPoQ2I7lIL0IYZ1yjxMYohbvoOjBmUIZzrf9W/HouONq0omIfTeCWEY+R380w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.150.0.tgz", + "integrity": "sha512-VqeRb5JX/bKYBrff7TUDvJyKY0914UzuCkuXIGxJS4FUmvMNfqkCbc7Sq90iMz9DlmAtlggwaBYQ9eg3h3ltiw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-ia32-msvc": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.150.0.tgz", + "integrity": "sha512-EPqJfeZ4Pgg2BJSsCV8GozxV0FDltRzpVtGVa1r2noJu1iu+opOw3gtBWXwIo9odCT/MdFfyHxdy0/CRqs3OqA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.150.0.tgz", + "integrity": "sha512-n5YMzbqwPQqozbkrexi0lNZrUz5cnPHalYpFWe6Dau7AmKIWNo+y24IwzDuZEQtEdUHuKhXmMMih/MPjOI+CMw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", + "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@pagefind/darwin-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-arm64/-/darwin-arm64-1.5.2.tgz", + "integrity": "sha512-MXpI+7HsAdPkvJ0gk9xj9g541BCqBZOBbdwj9g6lB5LCj6kSV6nqDSjzcAJwvOsfu0fjwvC8hQU+ecfhp+MpiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/darwin-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/darwin-x64/-/darwin-x64-1.5.2.tgz", + "integrity": "sha512-IojxFWMEJe0RQ7PQ3KXQsPIImNsbpPYpoZ+QUDrL8fAl/O27IX+LVLs74/UzEZy5uA2LD8Nz1AiwKr72vrkZQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@pagefind/freebsd-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/freebsd-x64/-/freebsd-x64-1.5.2.tgz", + "integrity": "sha512-7EVzo9+0w+2cbe671BtMj10UlNo83I+HrLVLfRxO731svHRJKUfJ/mo05gU14pe9PCfpKNQT8FS3Xc/oDN6pOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@pagefind/linux-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-arm64/-/linux-arm64-1.5.2.tgz", + "integrity": "sha512-Ovt9+K35sqzn8H3ZMXGwls4TD/wMJuvRtShHIsmUQREmaxjrDEX7gHckRCrwYJ4XE1H1p6HkLz3wukrAnsfXQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/linux-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/linux-x64/-/linux-x64-1.5.2.tgz", + "integrity": "sha512-V+tFqHKXhQKq/WqPBD67AFy7scn1/aZID00ws4fSDd+1daSi5UHR9VVlRrOUYKxn3VuFQYRD7lYXdZK1WED1YA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@pagefind/windows-arm64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-arm64/-/windows-arm64-1.5.2.tgz", + "integrity": "sha512-hN9Nh90fNW61nNRCW9ZyQrAj/mD0eRvmJ8NlTUzkbuW8kIzGJUi3cxjFkEcMZ5h/8FsKWD/VcouZl4yo1F7B6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@pagefind/windows-x64": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@pagefind/windows-x64/-/windows-x64-1.5.2.tgz", + "integrity": "sha512-Fa2Iyw7kaDRzGMfNYNUXNW2zbL5FQVDgSOcbDHdzBrDEdpqOqg8TcZ68F22ol6NJ9IGzvUdmeyZypLW5dyhqsg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@quansync/fs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-1.1.0.tgz", + "integrity": "sha512-qAPG/t3HqML1TlN7sY/pTbEjzFVAKsMjNNMGheyDosro+kT4iw2KCUoHcVdmliwWjorm4elZbgNQyU2eD97eDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.9.tgz", + "integrity": "sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.9.tgz", + "integrity": "sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.9.tgz", + "integrity": "sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.9.tgz", + "integrity": "sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.9.tgz", + "integrity": "sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.9.tgz", + "integrity": "sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.9.tgz", + "integrity": "sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.9.tgz", + "integrity": "sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.9.tgz", + "integrity": "sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.9.tgz", + "integrity": "sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.9.tgz", + "integrity": "sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.9.tgz", + "integrity": "sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.9.tgz", + "integrity": "sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.9.tgz", + "integrity": "sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.9.tgz", + "integrity": "sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-babel": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-6.1.0.tgz", + "integrity": "sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@rollup/pluginutils": "^5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-1.0.0.tgz", + "integrity": "sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "serialize-javascript": "^7.0.3", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.4.tgz", + "integrity": "sha512-I+BSHzTAhKN2n7ZwGZsegGcZjDpLqFOMAtJz/u6uFGe0pUFbq56dEHjqJV/ZUdRJtNXNxA+hREUatZBvMR3Oiw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.4.tgz", + "integrity": "sha512-pu3BdjS2LtEzRu2elmGzS3fIeWSZy4BMDIaLNwjorO76+k2d0LMluijhsDx3KQyQBQ/lLUZCQA9/s6csvUfuhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.4.tgz", + "integrity": "sha512-xfSrj9MHnWK9GaSqT9U0ImHtH/N8WZlHLx4cZHiuLcqs640hvZ3hLPd5UR2AZS57FaE8HrRUSpltbZdWRxHiDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.4.tgz", + "integrity": "sha512-bqU99PLJb/dqb3S0GIMdeuyAEETSUgZBoqXYd3Sd+WCsV+MmPhnN6JrotWyir31+QgH7EvvE5/mwGJlEoci8Fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.4.tgz", + "integrity": "sha512-JinsFZ5G40oXQb+sUuiA5x689vhr6dDYK0H0NL+rwKdL6CqnmYN8PE4ZwfRSoIjrCxqTQG/SLfTtSvHeGxoVlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.4.tgz", + "integrity": "sha512-GAdA4UxpiNm27cLHr2GqXBpAD0x9FqwYBY7/YSP0Ss0/PNi4k8gbviqpIpYbVSRBaS2ZcegXEzgTQMbRNCwxCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.4.tgz", + "integrity": "sha512-qDd6NoA1znaLjp4jR5U/KWCdLAKDJNB8W9ChbbDaKbo0xA+Atln5HK6LFCZ4oJQpemtRZA288DCirFRjrspptw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.4.tgz", + "integrity": "sha512-WtB5Tz5KTNINb8ZA+8sQ7bmjuS1JrRT7YverYIhUGdWWDlpzVWmIwuZE+jidkEXUn1l0zrEkaIMa8dHF3NGcsA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.4.tgz", + "integrity": "sha512-VcQ3L1tjnkKzWjryAVaFhHEWcqOfICX9uxVVoDzm2t0DpgKRHd2zOpVrJc0xsWeBZcBFyYROCIBdyR/fS174pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.4.tgz", + "integrity": "sha512-6+ZQX6P5s0cMDN2Ypb8Lbm2+/sZYmZjdaYny992ujUU9UKi/4CWoJWsl1pNvjWJHNHGK51m+jKGLlh1ylb2ifQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.4.tgz", + "integrity": "sha512-D72ZnvkFkBXOfzMMQLcwfPLyGkKb7HZ9/mf97B7v6/P5Lbv4oFOtSY/uHbS8lH6uKUOxoKiuokdb50XZSzzbJw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.4.tgz", + "integrity": "sha512-piU6BxeqA3O9KSu3kRCIQQtNqFFaTu21SEV4FwaRZowpnj3bLaWPZHw+xFqCs0XlJ+aOH3PTRWGoglH+mKA/OA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.4.tgz", + "integrity": "sha512-/5PGpHwqt2EEEOUs1XwzubE/ucr0dWDQ+to3zqi4Ds7EWpwtQ79wXc4JBoxqj/OwpawTsKWzJxHfSuBOq3DrWA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.4.tgz", + "integrity": "sha512-cX3beZDLWt7G2oJF+nhChiT+qtaihs+S2xi7ziGmVB+2pwPng6D0Ed0HmElQOgv2UsUmSJJLGwpBao/3TDx3VA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.4.tgz", + "integrity": "sha512-1uz2mGWHyptR7DgHHrlbdRAjXK7v7elGZ9lMja910/RP+ZYbX6xAmCiU9UZSX4hqmgtHMv6lr5l3kq1HIOpcag==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.4.tgz", + "integrity": "sha512-nLS8topojxyz7SRpKR2IODRpQ0XPZ+xaOXvT3+hqK/Uy8Lo5HFgkkIBiIrCu5tL5YqzTvgovGw55PwpahTAGig==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.4.tgz", + "integrity": "sha512-gs7DRKotr3l3q+jGPQBjH0ng1FjlEDm5ueQrkw5JtQvtLyEIcLASqAEaor56BhkKRzk+IcQzrcanBdb/bBQn8g==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.4.tgz", + "integrity": "sha512-791ET7W17NnScOZM7h4dX5hYspxE28htPFsb1awY/NRR8+PRNkS53e475rDdxXXDrP+kwnCcNWg9CX5ztn/Aqw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.4.tgz", + "integrity": "sha512-iwZQRcmj7g88g3tzefIrQY7qvmuA/cfYwhrDtTBhsmukO4U2huVO5W+86XacUMRvdSFVAc6kZUZy21JaRwiB9w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.4.tgz", + "integrity": "sha512-dVHFp9gRWrdTpnqQuGfCwd7hOQDatK1VCP2iWhLY/cGrOQs/ucFzJ6A5SRqbXX12ZDI8EUuejSM5kwg+ja7Png==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.4.tgz", + "integrity": "sha512-t3NlauOW6gxZVVFcBEnO62Cb4wbyDFL416gTg1uFI/2tgqYQlf69FbSE115Ajre9I+c26Lk4mcmdFUsS/DGifQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.4.tgz", + "integrity": "sha512-xWuIaSye5FWZF8+UYtVEcHtRJDN5kN9Kfgxx3Kq8XIov9KSKbc1fiqQCm90SKrgQbUXZelbnUhnlUJmfSE7P9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.4.tgz", + "integrity": "sha512-9ALJJUOg/ZflMJepVo2PlgsGxSaxN7SQ4Z8GoZfVlarWr6r3rkHUNsd/zAio7p4YMtChSMXPionxej4Hkf6CXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.4.tgz", + "integrity": "sha512-blj9z5qx/Pv4WU0W1NMFDB97e0JH5ed+aZGywW8WCvp/NhWX/4PFAq5uu6Q0AebNn+Vo6KzUYDT++JzTT5ojlQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.4.tgz", + "integrity": "sha512-Erx822VRBwLa124shbj+wNXe//BOgMEctDV0m1aqTQdNO1S69DgNUCFKC1RCeZfixs1J31l6igk1ziyXErbigQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-3.23.0.tgz", + "integrity": "sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/types": "3.23.0", + "twoslash": "^0.3.6" + }, + "peerDependencies": { + "typescript": ">=5.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.31.30", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.31.30.tgz", + "integrity": "sha512-MGsM7bVmHg3sUKCphlu3SGQ+T+5JTbygZWYArfKQCW5anJeACHeqLhcnf+R7XlCWZ+QR3C8JTBx3kCKJTN69ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.13.tgz", + "integrity": "sha512-wgKggnhZVL9Bfx1OaKKTrYY9BFRk6C8UAkQNUcIv1+llzYrIqy+RZm5HPKzn0NpEBvTVhTqB4kQyllZywsRBRQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-static": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.10.tgz", + "integrity": "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/enhanced-img": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@sveltejs/enhanced-img/-/enhanced-img-0.10.4.tgz", + "integrity": "sha512-Am5nmAKUo7Nboqq7Dhtfn7dcXA087d7gIz6Vecn1opB41aJ680+0q9U9KvEcMgduOyeiwckTIOQOx4Mmq9GcvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.5", + "sharp": "^0.34.1", + "svelte-parse-markup": "^0.1.5", + "vite-imagetools": "^9.0.3", + "zimmerframe": "^1.1.2" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^6.0.0 || ^7.0.0", + "svelte": "^5.0.0", + "vite": "^6.3.0 || >=7.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.70.3", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.70.3.tgz", + "integrity": "sha512-UDvEYuZqAMbfB/oXIoqKvbKcb7YczK5zYrzmsGV1zRJk03jntwp8dXiYoIJotxAndsKvcPFtx9H1GRSKFdSHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.9", + "@types/cookie": "^0.6.0", + "acorn": "^8.16.0", + "cookie": "^0.6.0", + "devalue": "^5.8.1", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3 || ^6.0.0", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-7.3.0.tgz", + "integrity": "sha512-QbRoJyD92e9R0ufeQIWRHrCC0ObcqSv/aBDdrQMoU+sypav3cDx5wytdQ6GLdXjEMO6xjrXGzfkUygng8JMv0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "deepmerge": "^4.3.1", + "magic-string": "^1.0.0", + "obug": "^2.1.0", + "vitefu": "^1.1.2" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24" + }, + "peerDependencies": { + "svelte": "^5.46.4", + "vite": "^8.0.0-beta.7 || ^8.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@sveltepress/cli": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@sveltepress/cli/-/cli-0.4.3.tgz", + "integrity": "sha512-/NIMCaZSL5QOa40T53Un6ksvenJMSHcoDCYi6I11Q2CO8CMLH0u0cbWzJ1tyzFdj+PSpSK567GYVUYEyoR5apg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltepress/vite": "1.8.3", + "vite": "^8.2.2" + }, + "bin": { + "sveltepress": "bin.js" + } + }, + "node_modules/@sveltepress/docsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@sveltepress/docsearch/-/docsearch-0.1.2.tgz", + "integrity": "sha512-a8+8/BK6Ym06te3Gl+EVCJNPtPaupJi+pHKVFgagmQCrl0Kk4//mKZFTga3NFouDwtbCkzbpzNDRNJKKMupmtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "^4.7.0", + "@docsearch/js": "^4.7.0" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@sveltepress/theme-default": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@sveltepress/theme-default/-/theme-default-8.9.0.tgz", + "integrity": "sha512-CpRr+l6lK8dgPOJ9ISWvZNRdalLrCa7SYLYCjFXP62hRlacPW+dBA9FQqC1U6D5Xy0Sigbu01r3P2fzh9JrNYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/twoslash": "^3.23.0", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "@sveltepress/docsearch": "0.1.2", + "@sveltepress/twoslash": "1.3.23", + "@unocss/extractor-svelte": "^66.10.0", + "@vite-pwa/sveltekit": "^1.1.0", + "lru-cache": "^11.5.2", + "mdast-util-from-markdown": "^2.0.3", + "mdast-util-gfm": "^3.1.0", + "shiki": "^3.23.0", + "uid": "^2.0.2", + "unist-util-visit": "^5.1.0", + "unocss": "^66.10.0", + "workbox-build": "^7.4.1", + "workbox-expiration": "^7.4.1", + "workbox-precaching": "^7.4.1", + "workbox-routing": "^7.4.1", + "workbox-strategies": "^7.4.1" + }, + "peerDependencies": { + "@sveltejs/kit": ">=2.65.1 <3", + "@sveltejs/vite-plugin-svelte": "^7.0.0", + "@sveltepress/vite": "^1.8.3", + "svelte": "^5.46.4", + "vite": "^8.0.0" + } + }, + "node_modules/@sveltepress/twoslash": { + "version": "1.3.23", + "resolved": "https://registry.npmjs.org/@sveltepress/twoslash/-/twoslash-1.3.23.tgz", + "integrity": "sha512-z33VLY0sPuQsehD1ph+vhIHqqq/xpsgr67vkYGH5lAmc3LAOkzO7vusli1fcvBRsPQKqPUwMlySXJjjzyAfjYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0", + "@shikijs/twoslash": "^3.23.0", + "mdast-util-from-markdown": "^2.0.3", + "mdast-util-gfm": "^3.1.0", + "mdast-util-to-hast": "^13.2.1", + "shiki": "^3.23.0", + "source-map-js": "^1.2.1", + "svelte2tsx": "^0.7.61", + "twoslash": "^0.3.9", + "twoslash-protocol": "^0.3.9" + }, + "peerDependencies": { + "svelte": "^5.0.0" + } + }, + "node_modules/@sveltepress/vite": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sveltepress/vite/-/vite-1.8.3.tgz", + "integrity": "sha512-rsi/niwWMWyf0lzPIz75wx1gMKOWWz7KltDqghAz1CeembaAden9oSS80cX11EGjYieupOSDhr5rJzeH/taOQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/enhanced-img": "^0.10.4", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "cross-spawn": "^7.0.6", + "fs-extra": "^11.4.0", + "lru-cache": "^11.5.2", + "pagefind": "^1.5.2", + "picocolors": "^1.1.1", + "rehype-stringify": "^10.0.1", + "remark-directive": "^4.0.0", + "remark-emoji": "^5.0.2", + "remark-extract-frontmatter": "^3.2.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.1", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.1.2", + "remark-stringify": "^11.0.0", + "shiki": "^3.23.0", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0", + "vfile": "^6.0.3", + "vite-plugin-inspect": "^11.4.1", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@sveltejs/kit": ">=2.65.1 <3", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "svelte": "^5.46.4", + "vite": "^8.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@trickfilm400/rollup-plugin-off-main-thread": { + "version": "3.0.0-pre1", + "resolved": "https://registry.npmjs.org/@trickfilm400/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-3.0.0-pre1.tgz", + "integrity": "sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "ejs": "^3.1.10", + "json5": "^2.2.3", + "magic-string": "^0.30.21", + "string.prototype.matchall": "^4.0.12" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", + "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.12.tgz", + "integrity": "sha512-Qe/KWYhEiIIxGs7HrAAjMfShxKldx19SJtr5zu53f3afPsdZNz7HHtdTLXo/kqeiWNXVycI24kSnfzBYkTzpgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", + "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.4.tgz", + "integrity": "sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript/vfs": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.4.tgz", + "integrity": "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unocss/cli": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/cli/-/cli-66.10.5.tgz", + "integrity": "sha512-NjHkCNRsgnrU7m/hI1y2ryv8RMku+uejx9ChCnKcdKVKuBpgKFdhjmSjaTJQjpAHORyv5hLdT/7TkLbJzqk4tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@unocss/config": "66.10.5", + "@unocss/core": "66.10.5", + "@unocss/preset-wind3": "66.10.5", + "@unocss/preset-wind4": "66.10.5", + "@unocss/transformer-directives": "66.10.5", + "cac": "^7.0.0", + "chokidar": "^5.0.0", + "colorette": "^2.0.20", + "consola": "^3.4.2", + "magic-string": "^1.4.1", + "pathe": "^2.0.3", + "perfect-debounce": "^2.1.0", + "tinyglobby": "^0.2.17", + "unplugin-utils": "^0.3.2" + }, + "bin": { + "unocss": "bin/unocss.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/cli/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@unocss/config": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/config/-/config-66.10.5.tgz", + "integrity": "sha512-ddmmmsJ+Vjg9oS4c5ElP8vR1oftID9dqG0yASDWLsLNY4uKo295EuCQXIBVbkyRnBZcdjpnOUfo71iwElaCeyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "colorette": "^2.0.20", + "consola": "^3.4.2", + "unconfig": "^7.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/core": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/core/-/core-66.10.5.tgz", + "integrity": "sha512-fukv4bL32z/kWIiKgDy5ih452Jzf7S76p8RnP4N+3utqMFeqWayEApiqRidGv5b6NwPguTsKXaLsy+mbK9aMfA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/extractor-arbitrary-variants": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/extractor-arbitrary-variants/-/extractor-arbitrary-variants-66.10.5.tgz", + "integrity": "sha512-8qCJjByALdNiGQB1xHWK3tAl3n+hacBLlklqHhgNj0qWYtr3Hp+pfyA2nuyzJcPXkolqtGn1APJ1TNPbL5w+qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/extractor-svelte": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/extractor-svelte/-/extractor-svelte-66.10.5.tgz", + "integrity": "sha512-gFaGBK6wCR/5X3DFKOfATGSv4waTwrPrhZdTsKq8Jw6OtOGvY30ILVgk+OHcjmCdaxDfHwH7Go87AOSL9WetQg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/inspector": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/inspector/-/inspector-66.10.5.tgz", + "integrity": "sha512-YTYkwzBrEnfleoIv9Q7PQDlbC7st/hUKI8V7veWwkqpzcAxGcLfbLn50jGgnbvAZrxtGgvF021uW6aor9FyX6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/config": "66.10.5", + "@unocss/core": "66.10.5", + "@unocss/rule-utils": "66.10.5", + "devframe": "^1.0.0", + "tinyglobby": "^0.2.17", + "unplugin-utils": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-attributify": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-attributify/-/preset-attributify-66.10.5.tgz", + "integrity": "sha512-2wgfTLGe7ryG9FwAMhNNpfzuL7jbBRWP4VgeGLnKusGIPrzmJ+bF3/+EZTgVZwAi+5jhj6wofcEJLvmHRUOYMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-icons": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-icons/-/preset-icons-66.10.5.tgz", + "integrity": "sha512-YZuDehWpwpvLzkMPxO329fhd66GKpblhbUHrL/5uVMAXJpxK7ZVSQECgpIbU8sXlc4/gvTOjkIFD0fZ1MRPK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@iconify/utils": "^3.1.7", + "@unocss/core": "66.10.5", + "ofetch": "^1.5.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-mini": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-mini/-/preset-mini-66.10.5.tgz", + "integrity": "sha512-oFKjmK32jyKp8rMI8Zu5+1AaFOvbwlQ7wztNGjtiAhhglKREZoncThLBE6Yd3B2+p/xf8YXfSOr5TFzhzXnDIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/extractor-arbitrary-variants": "66.10.5", + "@unocss/rule-utils": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-tagify": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-tagify/-/preset-tagify-66.10.5.tgz", + "integrity": "sha512-8lefFZt4H4N+hu48vp+aqqQcTG2P28ox4tTRXgpTrhk4toYFrY2YreMqa3BFvOmZsBRunr/pdd7ZwDi5vt5nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-typography": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-typography/-/preset-typography-66.10.5.tgz", + "integrity": "sha512-b7hP1v4LyopVRrzJiI+ymnJEZMoLW1DdBo0SFWyPnFZXJv7umtDFlZ9plb+8AJvviyRgZ3qI03adRLXA4QCt2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/rule-utils": "66.10.5" + } + }, + "node_modules/@unocss/preset-uno": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-uno/-/preset-uno-66.10.5.tgz", + "integrity": "sha512-Okd40CCXMWzv4fJQplNWCiARdPnAo5ghALvo2YQrYGaqwL4qwDurw4KK1R62PmvDCKXPPQY9duzcje/uOkvmeQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/preset-wind3": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-web-fonts": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-web-fonts/-/preset-web-fonts-66.10.5.tgz", + "integrity": "sha512-7yz51nOMorsHqKVpWLjp9aHX2bW6fgRkKPY/mZnpw/1S8rpYNOeZPv4w6ogaSIyCvQppDnxPnwp2hQwwnNKi2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "ofetch": "^1.5.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-wind": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-wind/-/preset-wind-66.10.5.tgz", + "integrity": "sha512-K2vnt3ri39kbToG5x4j56kB9pTLLsJuPZfQbWcEAnwOq8ojW5g80dCxetW3Rqukou/u2NnAJmAKm93aG0RZFIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/preset-wind3": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-wind3": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-wind3/-/preset-wind3-66.10.5.tgz", + "integrity": "sha512-1zjLAJ4JCVREQlRaLiajP5T/BQUQzc2ilpScD1kvgTkJLV8en+ae1G/ctjZwAThmosD0oicuuMT9ODjt2NfGOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/preset-mini": "66.10.5", + "@unocss/rule-utils": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/preset-wind4": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/preset-wind4/-/preset-wind4-66.10.5.tgz", + "integrity": "sha512-rYLe20SyOEf5V9SsHkHVhdmFGE4qZJL0/yheZGAUXXv/kN0yR+qlMPB4Q6UR4JiDxrR5R+8U7BIa/juOks7EvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/extractor-arbitrary-variants": "66.10.5", + "@unocss/rule-utils": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/rollup": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/rollup/-/rollup-66.10.5.tgz", + "integrity": "sha512-Ii1srTmJ1kF3yHdt1vdIiYID4cAeaxooSQJ1LIWLxy0Xr2/QVXKlcxp9KdXti8nfrmPcx3oWYDa92sEHVxIpgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@unocss/config": "66.10.5", + "@unocss/core": "66.10.5", + "chokidar": "^5.0.0", + "magic-string": "^1.4.1", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.17", + "unplugin-utils": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "rolldown": "^1.0.0", + "rollup": "^4.0.0" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/@unocss/rollup/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@unocss/rule-utils": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/rule-utils/-/rule-utils-66.10.5.tgz", + "integrity": "sha512-ePcz9fJfEVN4VXJgx2bPdGSZ/ujdyUhiJOnMTwIWRxlUdZ2Wgc5aT6zTb9W9AjOB0eWxO2Iyb0HGhA9GGuIY8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "magic-string": "^1.4.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/rule-utils/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@unocss/transformer-attributify-jsx": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/transformer-attributify-jsx/-/transformer-attributify-jsx-66.10.5.tgz", + "integrity": "sha512-G3QPttsY2ZLgLPTliNwQTPrESNXTr0B9NiTy/qHcRcUBfjunB4Et2wcBG4JAiaZCdLikYCuR+g9O+GveCbboAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "oxc-parser": "^0.150.0", + "oxc-walker": "^0.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/transformer-compile-class": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/transformer-compile-class/-/transformer-compile-class-66.10.5.tgz", + "integrity": "sha512-JHTSocPg3boTxkFvCVvVwoGlgyyoJ9YhZBy+c2hxW44mCIOGFimsRvslRg7RscYRR2ts8cdQhC3Oi4Wce+BHQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/transformer-directives": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/transformer-directives/-/transformer-directives-66.10.5.tgz", + "integrity": "sha512-X7WkyesHojKlDBPzgytRzqgftI7lRqpSbSdz7kx+d09D/Xf/1V7i0IOc+mBxeFngvqh2ueuLElwZbaT3CuKHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5", + "@unocss/rule-utils": "66.10.5", + "css-tree": "^3.2.1" + } + }, + "node_modules/@unocss/transformer-variant-group": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/transformer-variant-group/-/transformer-variant-group-66.10.5.tgz", + "integrity": "sha512-e1l3bCxl4qMizPJPe6E6tfS2swdL9r/ohiKxSxku6+/kyKYnAxRcpVPK6IbmkurQfo73cjSJUV+zXmqdxbdWNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/core": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@unocss/vite": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/@unocss/vite/-/vite-66.10.5.tgz", + "integrity": "sha512-aFJ+lTcqIbtqxsKD1OI1gtvfEieJPVa9KOZr1Wj/ChrSCStcS7QP/DTbYvM6hC+qa07W6hEbSEgYqOUtCvFKVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@unocss/config": "66.10.5", + "@unocss/core": "66.10.5", + "@unocss/inspector": "66.10.5", + "chokidar": "^5.0.0", + "magic-string": "^1.4.1", + "pathe": "^2.0.3", + "tinyglobby": "^0.2.17", + "unplugin-utils": "^0.3.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0-0" + } + }, + "node_modules/@unocss/vite/node_modules/magic-string": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", + "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.6.0" + } + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/@vite-pwa/sveltekit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vite-pwa/sveltekit/-/sveltekit-1.1.0.tgz", + "integrity": "sha512-mMIf2tY+7Hg8jecpu/WY+Ki2ikoXy3hVmt3tOxi0K+lYYnKQrDYthuHireI0S+26Mg9BXzL7qQF1xeB5VYlYlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kolorist": "^1.8.0", + "tinyglobby": "^0.2.9", + "vite-plugin-pwa": "^1.2.0" + }, + "engines": { + "node": ">=18.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@sveltejs/kit": "^1.3.1 || ^2.0.1", + "@vite-pwa/assets-generator": "^1.0.0" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.4.0.tgz", + "integrity": "sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", + "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binaryen": { + "version": "130.0.0", + "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-130.0.0.tgz", + "integrity": "sha512-XDrb+zql0RbFPKgj7MuH9zOc78R3Fa/P/VSGnnpdwYsvNZPWjcMYMdAkKCOQEL2A7yqgjSMTDRFp6gfSDW+/QQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "wasm-as": "bin/wasm-as", + "wasm-ctor-eval": "bin/wasm-ctor-eval", + "wasm-dis": "bin/wasm-dis", + "wasm-merge": "bin/wasm-merge", + "wasm-metadce": "bin/wasm-metadce", + "wasm-opt": "bin/wasm-opt", + "wasm-reduce": "bin/wasm-reduce", + "wasm-shell": "bin/wasm-shell", + "wasm2js": "bin/wasm2js" + } + }, + "node_modules/birpc": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-4.2.0.tgz", + "integrity": "sha512-KxgKcZPfrtzJDDALHPguGpGJUrzdgpymyiQQgzFjWreHMOpWrnFNVREr5J48x2DBh8ZVioscrV1SBkDipGiX+Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cac": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", + "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/comment-json": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz", + "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.4.12.tgz", + "integrity": "sha512-aypfsr6t0uNvkqaZc6zvBfXzC6pLI0/sIulpkV6RwCVtZqG5ebBzv4weImKK0VNCj91Wl9F5j7p5WU4MNrybng==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "srvx": ">=0.11.5" + }, + "peerDependenciesMeta": { + "srvx": { + "optional": true + } + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cytoscape": { + "version": "3.34.3", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.3.tgz", + "integrity": "sha512-yfYGhRcGAntq6YBD583j4n0Eg3jIxvWmZtz/5uz9UYkeIStSlMxuUja+ec5j3iBD8nv1rwaOAYMW09tBdkSeaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true, + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.23", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent-js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz", + "integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.9.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.9.4.tgz", + "integrity": "sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==", + "license": "MIT" + }, + "node_modules/devframe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/devframe/-/devframe-1.0.0.tgz", + "integrity": "sha512-u4eeDBJ8Cxd3n19o/cT6SQcoEgASzL9dL51IkYpIDriTNDmR7WBv+o+dufQmabir10KcozoRZqgwvDi/riASAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "crossws": "^0.4.12", + "h3": "^2.0.1-rc.31", + "nostics": "^1.2.0", + "pathe": "^2.0.3" + }, + "bin": { + "devframe": "bin/devframe.mjs" + }, + "peerDependencies": { + "@devframes/agentic": "1.0.0", + "cac": "^7.0.0" + }, + "peerDependenciesMeta": { + "@devframes/agentic": { + "optional": true + }, + "cac": { + "optional": true + } + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dompurify": { + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.15.tgz", + "integrity": "sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.433", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.433.tgz", + "integrity": "sha512-5lCAbyZBjtmUt/RAGHRqrL2q0oEFRThDAsZHHDn9XHa89Qw7gMYOeSicBTy+AHfvo0r6vwsZvqNJTQIQy1BLzA==", + "dev": true, + "license": "ISC" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.25.1.tgz", + "integrity": "sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-toolkit": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types", + "tests/browser-compat" + ] + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrap": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.3.7.tgz", + "integrity": "sha512-n2nf7fZR3c9yXf0BPEuHuXqT+KW0SJVj4cN5FMEkpCZ3scLjOQWpiccyCxVzCC2q1wubTghuEGzngJY/7Ah0Ow==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "peerDependencies": { + "@typescript-eslint/types": "^8.2.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/types": { + "optional": true + } + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.6.0.tgz", + "integrity": "sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastdom": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.12.tgz", + "integrity": "sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "strictdom": "^1.0.1" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz", + "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/framer-motion": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-13.4.0.tgz", + "integrity": "sha512-HCpqKM9BTu6UYKtj0u6J1QNxojnnirNcghcSDZ+SkpiL3myxvtsgXPS3ZGEELC2eSma7YiA937rAEXtRyydSXQ==", + "license": "MIT", + "dependencies": { + "motion-dom": "^13.3.0", + "motion-utils": "^13.3.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/h3": { + "version": "2.0.1-rc.32", + "resolved": "https://registry.npmjs.org/h3/-/h3-2.0.1-rc.32.tgz", + "integrity": "sha512-Epg1E85L8yIKd9UeAQAVdm6QVrnHbppMsQ641EjpNi4c0IlAg+PJlwp4Xw03Z1loRXPQaH9k64gJT5qDELqm+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "rou3": "^0.9.2", + "srvx": "^1.0.5" + }, + "bin": { + "h3": "bin/h3.mjs" + }, + "engines": { + "node": ">=20.11.1" + }, + "peerDependencies": { + "crossws": "^0.4.12", + "ocache": ">=0.3.0" + }, + "peerDependenciesMeta": { + "crossws": { + "optional": true + }, + "ocache": { + "optional": true + } + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/imagetools-core": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-9.1.0.tgz", + "integrity": "sha512-xQjs+2vrxLnAjCq+omuNkd5UQTld9/bP8+YT0LyYTlKfuSQtgUBvqhUwGugzSAh6sCdN+LnROMuLswn5hZ9Fhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", + "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/kysely": { + "version": "0.28.17", + "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.28.17.tgz", + "integrity": "sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-regexp": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz", + "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12", + "mlly": "^1.7.2", + "regexp-tree": "^0.1.27", + "type-level-regexp": "~0.1.17", + "ufo": "^1.5.4", + "unplugin": "^2.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", + "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/mermaid": { + "version": "11.17.2", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.17.2.tgz", + "integrity": "sha512-V6K3C8EBdEsPFZXSKMJe6ppQOENxuHARr9GvHX4hh47lAbhMRD9qf4oEK7LoaRQxULMa80/qt5gHO73aCleBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.2", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.2.1", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.34.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.21", + "dompurify": "^3.3.3", + "es-toolkit": "^1.45.1", + "fastdom": "1.0.12", + "katex": "^0.16.47", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.2.tgz", + "integrity": "sha512-pRzm4kDTu0MjlmBkxmS9yYhw60nncfcEwu9NNdPFSQEFXS95ZKyIIyTSHu/o3ReBUrLKYEq+7YaXCRn/bPB4MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/motion": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-13.4.0.tgz", + "integrity": "sha512-aiNSA29N+vgV5p5cJSB5cFzx8KTuuxB99z8zGtxsaqlwKtBK6sq8YgPRpkVQLkbJMOcLDU0q/ShdT95qpBy/0g==", + "license": "MIT", + "dependencies": { + "framer-motion": "^13.4.0", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/motion-dom": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-13.3.0.tgz", + "integrity": "sha512-AmAnB6pHdZ1vHGzWzuzteG6Q3j1lHKeX/lbST6jGlgm0cjvLUgaCk1xhOuPMOy5SgovN6wnnUdwFrkcsus7Ftg==", + "license": "MIT", + "dependencies": { + "motion-utils": "^13.3.0" + } + }, + "node_modules/motion-utils": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-13.3.0.tgz", + "integrity": "sha512-sgSschQp7EseHInIlR7hBbMuvet3RA0bs28KPZAXJcGKGdxHGvh1ogpYDilY3bOMtl73EqPNmp75sAKHYPU5sg==", + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.56.tgz", + "integrity": "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nostics": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/nostics/-/nostics-1.2.0.tgz", + "integrity": "sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", + "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/ohash": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/oniguruma-parser": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/open": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oxc-minify": { + "version": "0.136.0", + "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.136.0.tgz", + "integrity": "sha512-u9UvPFTYVwQ/i1kpp/c20S/SbvLaLV0Ngzyhgi0YV4B1SlxM7RgnnePl4vY9N3Z9sTRcozL1MRStI3PlUN9RFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-minify/binding-android-arm-eabi": "0.136.0", + "@oxc-minify/binding-android-arm64": "0.136.0", + "@oxc-minify/binding-darwin-arm64": "0.136.0", + "@oxc-minify/binding-darwin-x64": "0.136.0", + "@oxc-minify/binding-freebsd-x64": "0.136.0", + "@oxc-minify/binding-linux-arm-gnueabihf": "0.136.0", + "@oxc-minify/binding-linux-arm-musleabihf": "0.136.0", + "@oxc-minify/binding-linux-arm64-gnu": "0.136.0", + "@oxc-minify/binding-linux-arm64-musl": "0.136.0", + "@oxc-minify/binding-linux-ppc64-gnu": "0.136.0", + "@oxc-minify/binding-linux-riscv64-gnu": "0.136.0", + "@oxc-minify/binding-linux-riscv64-musl": "0.136.0", + "@oxc-minify/binding-linux-s390x-gnu": "0.136.0", + "@oxc-minify/binding-linux-x64-gnu": "0.136.0", + "@oxc-minify/binding-linux-x64-musl": "0.136.0", + "@oxc-minify/binding-openharmony-arm64": "0.136.0", + "@oxc-minify/binding-wasm32-wasi": "0.136.0", + "@oxc-minify/binding-win32-arm64-msvc": "0.136.0", + "@oxc-minify/binding-win32-ia32-msvc": "0.136.0", + "@oxc-minify/binding-win32-x64-msvc": "0.136.0" + } + }, + "node_modules/oxc-parser": { + "version": "0.150.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.150.0.tgz", + "integrity": "sha512-zwajKw1GUa57IOdafIS7/yOObGF2NihwIfZfs5yJTRprMSkiwhWOc/k+n8bwnUPbHr2/XsjfBO8KyTPaW3VpWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.150.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/oxc-project" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm-eabi": "0.150.0", + "@oxc-parser/binding-android-arm64": "0.150.0", + "@oxc-parser/binding-darwin-arm64": "0.150.0", + "@oxc-parser/binding-darwin-x64": "0.150.0", + "@oxc-parser/binding-freebsd-x64": "0.150.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.150.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.150.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.150.0", + "@oxc-parser/binding-linux-arm64-musl": "0.150.0", + "@oxc-parser/binding-linux-ppc64-gnu": "0.150.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.150.0", + "@oxc-parser/binding-linux-riscv64-musl": "0.150.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.150.0", + "@oxc-parser/binding-linux-x64-gnu": "0.150.0", + "@oxc-parser/binding-linux-x64-musl": "0.150.0", + "@oxc-parser/binding-openharmony-arm64": "0.150.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.150.0", + "@oxc-parser/binding-win32-ia32-msvc": "0.150.0", + "@oxc-parser/binding-win32-x64-msvc": "0.150.0" + } + }, + "node_modules/oxc-walker": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.7.0.tgz", + "integrity": "sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "magic-regexp": "^0.10.0" + }, + "peerDependencies": { + "oxc-parser": ">=0.98.0" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz", + "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/pagefind": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/pagefind/-/pagefind-1.5.2.tgz", + "integrity": "sha512-XTUaK0hXMCu2jszWE584JGQT7y284TmMV9l/HX3rnG5uo3rHI/uHU56XTyyyPFjeWEBxECbAi0CaFDJOONtG0Q==", + "dev": true, + "license": "MIT", + "bin": { + "pagefind": "lib/runner/bin.cjs" + }, + "optionalDependencies": { + "@pagefind/darwin-arm64": "1.5.2", + "@pagefind/darwin-x64": "1.5.2", + "@pagefind/freebsd-x64": "1.5.2", + "@pagefind/linux-arm64": "1.5.2", + "@pagefind/linux-x64": "1.5.2", + "@pagefind/windows-arm64": "1.5.2", + "@pagefind/windows-x64": "1.5.2" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-bytes": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/property-information": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/quansync": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", + "integrity": "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true, + "license": "MIT" + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.3.tgz", + "integrity": "sha512-ycwFAS14Jw4mppvmK4GR/J6u3WpWpjkEApehuHtLc/8VpPNpDMbQ4WjqwplXifGeyKOzHSFLmSPqzksDQE2Sfg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-stringify": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-to-html": "^9.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-4.0.0.tgz", + "integrity": "sha512-7sxn4RfF1o3izevPV1DheyGDD6X4c9hrGpfdUpm7uC++dqrnJxIZVkk7CoKqcLm0VUMAuOol7Mno3m6g8cfMuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^4.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-5.0.2.tgz", + "integrity": "sha512-IyIqGELcyK5AVdLFafoiNww+Eaw/F+rGrNSXoKucjo95uL267zrddgxGM83GN1wFIb68pyDuAsY3m5t2Cav1pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.4", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.3", + "unified": "^11.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/remark-extract-frontmatter": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/remark-extract-frontmatter/-/remark-extract-frontmatter-3.2.0.tgz", + "integrity": "sha512-PmYwNCo0cMAUV3oAGg5Hn6YSZgiSDwVdxLJmPIZ804aYuvE5mAzozo5AkO0C8ELroWrtN/f9zzb0jqFPBkMnwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/rolldown": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.9.tgz", + "integrity": "sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.150.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.9", + "@rolldown/binding-android-arm64": "1.2.9", + "@rolldown/binding-darwin-arm64": "1.2.9", + "@rolldown/binding-darwin-x64": "1.2.9", + "@rolldown/binding-freebsd-x64": "1.2.9", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.9", + "@rolldown/binding-linux-arm64-gnu": "1.2.9", + "@rolldown/binding-linux-arm64-musl": "1.2.9", + "@rolldown/binding-linux-ppc64-gnu": "1.2.9", + "@rolldown/binding-linux-s390x-gnu": "1.2.9", + "@rolldown/binding-linux-x64-gnu": "1.2.9", + "@rolldown/binding-linux-x64-musl": "1.2.9", + "@rolldown/binding-openharmony-arm64": "1.2.9", + "@rolldown/binding-win32-arm64-msvc": "1.2.9", + "@rolldown/binding-win32-x64-msvc": "1.2.9" + } + }, + "node_modules/rollup": { + "version": "4.63.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.4.tgz", + "integrity": "sha512-4U0liVayNIoLp3GFl1FcI8561WepLnZ1rqfraGh7S9B3Ur5F9S283y8Futii7RUU2C/97tOBmBy7nYvhoiOpbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.4", + "@rollup/rollup-android-arm64": "4.63.4", + "@rollup/rollup-darwin-arm64": "4.63.4", + "@rollup/rollup-darwin-x64": "4.63.4", + "@rollup/rollup-freebsd-arm64": "4.63.4", + "@rollup/rollup-freebsd-x64": "4.63.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.4", + "@rollup/rollup-linux-arm-musleabihf": "4.63.4", + "@rollup/rollup-linux-arm64-gnu": "4.63.4", + "@rollup/rollup-linux-arm64-musl": "4.63.4", + "@rollup/rollup-linux-loong64-gnu": "4.63.4", + "@rollup/rollup-linux-loong64-musl": "4.63.4", + "@rollup/rollup-linux-ppc64-gnu": "4.63.4", + "@rollup/rollup-linux-ppc64-musl": "4.63.4", + "@rollup/rollup-linux-riscv64-gnu": "4.63.4", + "@rollup/rollup-linux-riscv64-musl": "4.63.4", + "@rollup/rollup-linux-s390x-gnu": "4.63.4", + "@rollup/rollup-linux-x64-gnu": "4.63.4", + "@rollup/rollup-linux-x64-musl": "4.63.4", + "@rollup/rollup-openbsd-x64": "4.63.4", + "@rollup/rollup-openharmony-arm64": "4.63.4", + "@rollup/rollup-win32-arm64-msvc": "4.63.4", + "@rollup/rollup-win32-ia32-msvc": "4.63.4", + "@rollup/rollup-win32-x64-gnu": "4.63.4", + "@rollup/rollup-win32-x64-msvc": "4.63.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/rou3": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/rou3/-/rou3-0.9.2.tgz", + "integrity": "sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.1.tgz", + "integrity": "sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", + "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smob": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.6.2.tgz", + "integrity": "sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz", + "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/srvx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/srvx/-/srvx-1.0.5.tgz", + "integrity": "sha512-KvSKRpgPG/oaq3cyT614OQ2bAa7DynuGamivCZeoZzIUULOdbQz6wUtnnVuC4+DCx2Zglzo8v5gBYmWIWYhDxA==", + "dev": true, + "license": "MIT", + "bin": { + "srvx": "bin/srvx.mjs" + }, + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strictdom": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strictdom/-/strictdom-1.0.1.tgz", + "integrity": "sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string.prototype.matchall": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", + "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "get-intrinsic": "^1.3.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.4", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.57.1.tgz", + "integrity": "sha512-Uqj49lWKB+iSSnneuwiYYJ7MZgkB+eXr0LXBhv4uDuAkXqnWmq65Sxflfvp0Lc6MdKjMUxGaeOKWJqz5SNiVIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.6.0", + "@sveltejs/acorn-typescript": "^1.0.13", + "@types/estree": "^1.0.9", + "acorn": "^8.18.0", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.9.2", + "esm-env": "^1.2.1", + "esrap": "^2.3.6", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-parse-markup": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/svelte-parse-markup/-/svelte-parse-markup-0.1.5.tgz", + "integrity": "sha512-T6mqZrySltPCDwfKXWQ6zehipVLk4GWfH1zCMGgRtLlOIFPuw58ZxVYxVvotMJgJaurKi1i14viB2GIRKXeJTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://bjornlu.com/sponsor" + }, + "peerDependencies": { + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0-next.1" + } + }, + "node_modules/svelte2tsx": { + "version": "0.7.61", + "resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.7.61.tgz", + "integrity": "sha512-EpQ/+UHITBULeUojx/LLD3uTYasZXcX1BrqlrzfLUnT9vdUhaOWK59a3ryWcFU8L0sY1SP+gRhJ2Beiis98+qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dedent-js": "^1.0.1", + "scule": "^1.3.0" + }, + "peerDependencies": { + "svelte": "^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0", + "typescript": "^4.9.4 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/twoslash": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.9.tgz", + "integrity": "sha512-rDclk+OtzuTX+tnea7DYLCkqGQ3eP0IyfD+kzUJ7t46X/NzlaxwrhecmEBNuSCuEn3V+n1PhcjUUQQ7gUJzX5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript/vfs": "^1.6.4", + "twoslash-protocol": "0.3.9" + }, + "peerDependencies": { + "typescript": "^5.5.0 || ^6.0.0" + } + }, + "node_modules/twoslash-protocol": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.9.tgz", + "integrity": "sha512-9/iwp+CXOnjFMPQuPL5PkuRbZnDoNpBvtJCLs9t8kDYkL3YHujbvnHfZA1i5fApDftVEdBw+T/4F+dH5kIzpYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-level-regexp": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz", + "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==", + "dev": true, + "license": "MIT" + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.5.tgz", + "integrity": "sha512-0FHJvLPqZ7KJzp17O13jfsAjsqazgrxBu2zEK95PmUz8lv2+GjRuxUInCr2Rk9Dms3ihN21zJ929ZO43yJ95QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unconfig": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.5.0.tgz", + "integrity": "sha512-oi8Qy2JV4D3UQ0PsopR28CzdQ3S/5A1zwsUwp/rosSbfhJ5z7b90bIyTwi/F7hCLD4SGcZVjDzd4XoUQcEanvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "defu": "^6.1.4", + "jiti": "^2.6.1", + "quansync": "^1.0.0", + "unconfig-core": "7.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unconfig-core": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/unconfig-core/-/unconfig-core-7.5.0.tgz", + "integrity": "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unocss": { + "version": "66.10.5", + "resolved": "https://registry.npmjs.org/unocss/-/unocss-66.10.5.tgz", + "integrity": "sha512-hts6uxRjtEdOLmdmo0Mbh5k3jrHsjsQlU3rFJdtob+wu57iM5b+d70fnxqMWe7yF/OBeiZKW6H+ti0qHNJBKPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@unocss/cli": "66.10.5", + "@unocss/core": "66.10.5", + "@unocss/preset-attributify": "66.10.5", + "@unocss/preset-icons": "66.10.5", + "@unocss/preset-mini": "66.10.5", + "@unocss/preset-tagify": "66.10.5", + "@unocss/preset-typography": "66.10.5", + "@unocss/preset-uno": "66.10.5", + "@unocss/preset-web-fonts": "66.10.5", + "@unocss/preset-wind": "66.10.5", + "@unocss/preset-wind3": "66.10.5", + "@unocss/preset-wind4": "66.10.5", + "@unocss/rollup": "66.10.5", + "@unocss/transformer-attributify-jsx": "66.10.5", + "@unocss/transformer-compile-class": "66.10.5", + "@unocss/transformer-directives": "66.10.5", + "@unocss/transformer-variant-group": "66.10.5", + "@unocss/vite": "66.10.5" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@unocss/astro": "66.10.5", + "@unocss/postcss": "66.10.5", + "@unocss/webpack": "66.10.5" + }, + "peerDependenciesMeta": { + "@unocss/astro": { + "optional": true + }, + "@unocss/postcss": { + "optional": true + }, + "@unocss/webpack": { + "optional": true + } + } + }, + "node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.2.tgz", + "integrity": "sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz", + "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", + "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/valibot": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.5.0.tgz", + "integrity": "sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", + "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.7", + "postcss": "^8.5.28", + "rolldown": "~1.2.6", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.7.1", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-dev-rpc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz", + "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==", + "dev": true, + "license": "MIT", + "dependencies": { + "birpc": "^4.0.0", + "vite-hot-client": "^2.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-hot-client": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.2.0.tgz", + "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-imagetools": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/vite-imagetools/-/vite-imagetools-9.0.3.tgz", + "integrity": "sha512-FwjApRNZyN+RucPW9Z9kf0dyzyi3r3zlDfrTnzHXNaYpmT3pZ5w//d6QkApy1iypbDm+3fq+Gwfv+PYA4j4uYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.5", + "imagetools-core": "^9.1.0", + "sharp": "^0.34.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz", + "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.3.0", + "error-stack-parser-es": "^1.0.5", + "obug": "^2.1.1", + "ohash": "^2.0.11", + "open": "^11.0.0", + "perfect-debounce": "^2.1.0", + "sirv": "^3.0.2", + "unplugin-utils": "^0.3.1", + "vite-dev-rpc": "^2.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-pwa": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-1.3.0.tgz", + "integrity": "sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.6", + "pretty-bytes": "^6.1.1", + "tinyglobby": "^0.2.10", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vite-pwa/assets-generator": "^1.0.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "workbox-build": "^7.4.1", + "workbox-window": "^7.4.1" + }, + "peerDependenciesMeta": { + "@vite-pwa/assets-generator": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/vite/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.24", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.24.tgz", + "integrity": "sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/workbox-background-sync": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-7.4.1.tgz", + "integrity": "sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-7.4.1.tgz", + "integrity": "sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-build": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-7.4.1.tgz", + "integrity": "sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.24.4", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", + "@rollup/plugin-terser": "^1.0.0", + "@trickfilm400/rollup-plugin-off-main-thread": "^3.0.0-pre1", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "eta": "^4.5.1", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^11.0.1", + "pretty-bytes": "^5.3.0", + "rollup": "^4.53.3", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "7.4.1", + "workbox-broadcast-update": "7.4.1", + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-google-analytics": "7.4.1", + "workbox-navigation-preload": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-range-requests": "7.4.1", + "workbox-recipes": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1", + "workbox-streams": "7.4.1", + "workbox-sw": "7.4.1", + "workbox-window": "7.4.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/workbox-build/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.1.tgz", + "integrity": "sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-core": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-7.4.1.tgz", + "integrity": "sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-expiration": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-7.4.1.tgz", + "integrity": "sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-google-analytics": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-7.4.1.tgz", + "integrity": "sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-background-sync": "7.4.1", + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-7.4.1.tgz", + "integrity": "sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-precaching": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-7.4.1.tgz", + "integrity": "sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-range-requests": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-7.4.1.tgz", + "integrity": "sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-recipes": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-7.4.1.tgz", + "integrity": "sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-cacheable-response": "7.4.1", + "workbox-core": "7.4.1", + "workbox-expiration": "7.4.1", + "workbox-precaching": "7.4.1", + "workbox-routing": "7.4.1", + "workbox-strategies": "7.4.1" + } + }, + "node_modules/workbox-routing": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-7.4.1.tgz", + "integrity": "sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-strategies": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-7.4.1.tgz", + "integrity": "sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1" + } + }, + "node_modules/workbox-streams": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-7.4.1.tgz", + "integrity": "sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "workbox-core": "7.4.1", + "workbox-routing": "7.4.1" + } + }, + "node_modules/workbox-sw": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-7.4.1.tgz", + "integrity": "sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/workbox-window": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-7.4.1.tgz", + "integrity": "sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "7.4.1" + } + }, + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zimmerframe": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.5.tgz", + "integrity": "sha512-msJxIvYDYcoNL+PJsu+7qmpDWsYmAxTY+2TNYXXF0hzBzBk0BMecOqDOG/EckUoKCuKwObfbugIl8QpqHDXeFA==", + "license": "MIT" + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/Docs/package.json b/Docs/package.json new file mode 100644 index 0000000..0a5e34b --- /dev/null +++ b/Docs/package.json @@ -0,0 +1,32 @@ +{ + "name": "@authkit/docs", + "private": true, + "type": "module", + "scripts": { + "dev": "npm run sync && vite dev", + "build": "npm run sync && sveltepress versions build", + "typecheck": "svelte-kit sync && tsc --noEmit", + "preview": "vite preview", + "sync": "tsx scripts/sync-content.ts" + }, + "devDependencies": { + "@inlang/paraglide-js": "^2.25.4", + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.48.3", + "@sveltejs/vite-plugin-svelte": "^7.3.0", + "@sveltepress/cli": "^0.4.3", + "@sveltepress/theme-default": "^8.9.0", + "@sveltepress/vite": "^1.8.3", + "@tailwindcss/vite": "^4.1.12", + "@types/node": "^22.15.0", + "mermaid": "^11.12.0", + "svelte": "^5.57.0", + "tailwindcss": "^4.1.12", + "tsx": "^4.20.5", + "typescript": "^5.9.2", + "vite": "^8.3.0" + }, + "dependencies": { + "@humanspeak/svelte-motion": "^1.2.1" + } +} diff --git a/Docs/project.inlang/settings.json b/Docs/project.inlang/settings.json new file mode 100644 index 0000000..5df427e --- /dev/null +++ b/Docs/project.inlang/settings.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://inlang.com/schema/project-settings", + "baseLocale": "en", + "locales": [ + "en", + "pl" + ], + "strategy": [ + "custom-sveltepress", + "cookie", + "baseLocale" + ], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js" + ], + "plugin.inlang.messageFormat": { + "pathPattern": "./i18n/messages/{locale}.json" + } +} diff --git a/Docs/sveltepress.versions.en.json b/Docs/sveltepress.versions.en.json new file mode 100644 index 0000000..8f3d2f5 --- /dev/null +++ b/Docs/sveltepress.versions.en.json @@ -0,0 +1,22 @@ +{ + "$schema": "./node_modules/@sveltepress/cli/schema/versions.schema.json", + "basePath": "/en/v", + "current": { + "id": "0.1", + "label": "0.1" + }, + "versions": [], + "content": { + "include": [ + "**" + ], + "exclude": [], + "shared": ["$lib/**", "static/**"] + }, + "artifacts": { + "mode": "incremental", + "siteId": "authkit-docs", + "store": ".sveltepress/version-artifacts", + "sources": "version-deltas-en" + } +} diff --git a/Docs/sveltepress.versions.json b/Docs/sveltepress.versions.json new file mode 100644 index 0000000..8f278e4 --- /dev/null +++ b/Docs/sveltepress.versions.json @@ -0,0 +1,95 @@ +{ + "$schema": "./node_modules/@sveltepress/cli/schema/versions.schema.json", + "basePath": "/v", + "current": { + "id": "0.1", + "label": "0.1", + "routes": [ + "/", + "/en/", + "/en/adr/", + "/en/adr/001-centralize-signing-key-management/", + "/en/adr/002-encrypt-keystore-at-rest/", + "/en/adr/003-signing-key-lifecycle-immutable-transitions/", + "/en/adr/004-token-key-bindings-domain/", + "/en/adr/005-public-keys-via-jwks/", + "/en/adr/006-kid-as-generated-guid/", + "/en/adr/007-default-signing-algorithm-rsa-4096/", + "/en/adr/008-standardized-error-response/", + "/en/adr/009-dynamic-plugin-discovery/", + "/en/adr/010-plugin-loading-from-directory/", + "/en/adr/011-keystore-persisted-as-singleton-marten-document/", + "/en/adr/012-token-key-bindings-persisted-in-marten/", + "/en/adr/013-dual-rest-and-grpc-transport/", + "/en/adr/014-error-responses-via-middleware/", + "/en/adr/015-keycloak-external-jwt-authority/", + "/en/adr/016-marten-and-wolverine-infrastructure/", + "/en/adr/017-Plugin-Contract-and-Dynamic-Loading-Architecture/", + "/en/adr/017-api-key-credential-extraction-strategies/", + "/en/adr/018-security-scheme-contract-explicit-handling/", + "/en/adr/019-plugin-metadata-attribute/", + "/en/adr/020-devtools-plugin/", + "/en/adr/021-swagger-serving-via-reflection/", + "/en/adr/022-plugin-configuration-context-and-builder/", + "/en/adr/023-plugin-application-pipeline-hooks/", + "/en/adr/024-plugin-lifecycle-and-hosted-services/", + "/en/adr/025-plugin-options-openapi-and-marten-integrations/", + "/en/adr/025-structured-plugin-health-contract/", + "/en/adr/026-plugin-authentication-and-authorization-hooks/", + "/en/architecture/adr/", + "/en/architecture/adr/001-centralize-signing-key-management/", + "/en/architecture/adr/002-encrypt-keystore-at-rest/", + "/en/architecture/adr/003-signing-key-lifecycle-immutable-transitions/", + "/en/architecture/adr/004-token-key-bindings-domain/", + "/en/architecture/adr/005-public-keys-via-jwks/", + "/en/architecture/adr/006-kid-as-generated-guid/", + "/en/architecture/adr/007-default-signing-algorithm-rsa-4096/", + "/en/architecture/adr/008-standardized-error-response/", + "/en/architecture/adr/009-dynamic-plugin-discovery/", + "/en/architecture/adr/010-plugin-loading-from-directory/", + "/en/architecture/adr/011-keystore-persisted-as-singleton-marten-document/", + "/en/architecture/adr/012-token-key-bindings-persisted-in-marten/", + "/en/architecture/adr/013-dual-rest-and-grpc-transport/", + "/en/architecture/adr/014-error-responses-via-middleware/", + "/en/architecture/adr/015-keycloak-external-jwt-authority/", + "/en/architecture/adr/016-marten-and-wolverine-infrastructure/", + "/en/architecture/adr/017-Plugin-Contract-and-Dynamic-Loading-Architecture/", + "/en/architecture/adr/017-api-key-credential-extraction-strategies/", + "/en/architecture/adr/018-security-scheme-contract-explicit-handling/", + "/en/architecture/adr/019-plugin-metadata-attribute/", + "/en/architecture/adr/020-devtools-plugin/", + "/en/architecture/adr/021-swagger-serving-via-reflection/", + "/en/architecture/adr/022-plugin-configuration-context-and-builder/", + "/en/architecture/adr/023-plugin-application-pipeline-hooks/", + "/en/architecture/adr/024-plugin-lifecycle-and-hosted-services/", + "/en/architecture/adr/025-plugin-options-openapi-and-marten-integrations/", + "/en/architecture/adr/025-structured-plugin-health-contract/", + "/en/architecture/adr/026-plugin-authentication-and-authorization-hooks/", + "/en/guide/configuration/", + "/en/guide/introduction/", + "/en/guide/quick-start/", + "/en/reference/rest-api/", + "/en/schemas/" + ], + "changes": { + "versionId": "0.1", + "baselineVersionId": null, + "newPages": [], + "updatedPages": [] + } + }, + "versions": [], + "content": { + "include": [ + "**" + ], + "exclude": [], + "shared": ["$lib/**", "static/**"] + }, + "artifacts": { + "mode": "incremental", + "siteId": "authkit-docs", + "store": ".sveltepress/version-artifacts", + "sources": "version-deltas" + } +} diff --git a/Docs/sveltepress.versions.pl.json b/Docs/sveltepress.versions.pl.json new file mode 100644 index 0000000..9a17c44 --- /dev/null +++ b/Docs/sveltepress.versions.pl.json @@ -0,0 +1,22 @@ +{ + "$schema": "./node_modules/@sveltepress/cli/schema/versions.schema.json", + "basePath": "/pl/v", + "current": { + "id": "0.1", + "label": "0.1" + }, + "versions": [], + "content": { + "include": [ + "**" + ], + "exclude": [], + "shared": ["$lib/**", "static/**"] + }, + "artifacts": { + "mode": "incremental", + "siteId": "authkit-docs", + "store": ".sveltepress/version-artifacts", + "sources": "version-deltas-pl" + } +} From 3889ca6168dcf817a4a45d21e74b048a8a8f0778 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:08:49 +0200 Subject: [PATCH 13/17] feat: automate locale routes and docs registry generation --- .gitignore | 13 ++++ Docs/scripts/sync-content.ts | 97 ++++++++++++++++++++++++++ Docs/scripts/sync/adr.ts | 90 ++++++++++++++++++++++++ Docs/scripts/sync/layouts.ts | 124 +++++++++++++++++++++++++++++++++ Docs/scripts/sync/locales.ts | 53 ++++++++++++++ Docs/scripts/sync/paraglide.ts | 43 ++++++++++++ Docs/scripts/sync/paths.ts | 48 +++++++++++++ Docs/scripts/sync/routes.ts | 117 +++++++++++++++++++++++++++++++ Docs/scripts/sync/versions.ts | 98 ++++++++++++++++++++++++++ 9 files changed, 683 insertions(+) create mode 100644 Docs/scripts/sync-content.ts create mode 100644 Docs/scripts/sync/adr.ts create mode 100644 Docs/scripts/sync/layouts.ts create mode 100644 Docs/scripts/sync/locales.ts create mode 100644 Docs/scripts/sync/paraglide.ts create mode 100644 Docs/scripts/sync/paths.ts create mode 100644 Docs/scripts/sync/routes.ts create mode 100644 Docs/scripts/sync/versions.ts diff --git a/.gitignore b/.gitignore index 36191f8..9a85c06 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,18 @@ .obsidian/ bin/ obj/ +/Docs/node_modules/ +/Docs/.svelte-kit/ +/Docs/build/ +/Docs/.sveltepress/ +# generated locale routes — sources: content/, ADR/, Schemas.md (sync rebuilds them) +/Docs/src/routes/??/ +/Docs/src/routes/??-??/ +# generated by Docs/scripts/sync-content.ts +/Docs/src/lib/site-locales.ts +# generated into static/ on every build +/Docs/static/sitemap.xml +/Docs/static/??/llms*.txt /plugins/ /out/ .idea/ @@ -12,3 +24,4 @@ src/Plugins/Solutions/DevTokens/manifest.json src/Plugins/Solutions/DevTools/manifest.json issues/ *.DotSettings.user +Docs/package-lock.json diff --git a/Docs/scripts/sync-content.ts b/Docs/scripts/sync-content.ts new file mode 100644 index 0000000..a761876 --- /dev/null +++ b/Docs/scripts/sync-content.ts @@ -0,0 +1,97 @@ +// Thin orchestrator — logic lives in ./sync/*. All locale route dirs are +// generated (sources: content/); adding a language = +// dropping i18n/messages/.json and running `npm run sync`. +import { readdir, rm, stat } from 'node:fs/promises' +import { join } from 'node:path' +import { validateAdrRegistry } from './sync/adr.ts' +import { writeAdrLayout, writeLandingWrapper, writeRegistry, writeSectionLayout } from './sync/layouts.ts' +import { discoverLocales } from './sync/locales.ts' +import { compileParaglide, ensureParaglideSettings, paraglideStale } from './sync/paraglide.ts' +import { adrSource, contentRoot, countPages, docsRoot, routesRoot, stats } from './sync/paths.ts' +import { adrPage, fallbackCopy, fixAdrRelativeLinks, prefixLocaleLinks, syncContentTree, writeRoute } from './sync/routes.ts' +import { ensureVersionManifests } from './sync/versions.ts' + +// 1. Locales, translations, registry, version manifests (never destructive). +const locales = await discoverLocales() +const codes = locales.map(l => l.code) + +const settingsChanged = await ensureParaglideSettings(locales) +if (settingsChanged || (await paraglideStale(locales))) compileParaglide() +await writeRegistry(locales) +await ensureVersionManifests(locales) + +// 2. Fail fast on missing English first sources before wiping anything. +for (const [label, path] of [ + ['Schemas.md', join(contentRoot, 'en', 'schemas.md')], + ['ADR index', join(adrSource, 'README.md')], +] as const) { + try { + await stat(path) + } catch { + throw new Error(`sync: missing ${label} at ${path}`) + } +} + +// 3. Locale dirs are fully generated wipe and rebuild. Also drop dirs of +// locales whose messages file was removed (two letter dirs only, so hand +// written sections like guide/ are never touched). +for (const { code } of locales) { + await rm(join(routesRoot, code), { recursive: true, force: true }) + stats.removed.push(code) +} +for (const entry of await readdir(routesRoot, { withFileTypes: true })) { + if (!entry.isDirectory() || !/^[a-z]{2}(-[A-Z]{2})?$/.test(entry.name)) continue + if (codes.includes(entry.name)) continue + await rm(join(routesRoot, entry.name), { recursive: true, force: true }) + stats.removed.push(`${entry.name} (stale)`) +} +await rm(join(routesRoot, '+page.md'), { force: true }) + +// 4. English-first sources (content/en/adr/, content/en/schemas.md) land under en/. +const en = locales.find(l => l.code === 'en') ?? locales[0] +const prefixEn = prefixLocaleLinks(en.code) + +await writeRoute(join(en.code, 'schemas'), join(contentRoot, 'en', 'schemas.md'), prefixEn) +await writeRoute(join(en.code, 'adr'), join(adrSource, 'README.md'), content => + prefixEn(adrPage('/adr/')(content)), +) + +for (const entry of await readdir(adrSource, { withFileTypes: true })) { + if (!entry.isFile() || !entry.name.endsWith('.md') || entry.name === 'README.md') continue + const slug = entry.name.slice(0, -'.md'.length) + await writeRoute(join(en.code, 'adr', slug), join(adrSource, entry.name), content => + prefixEn(adrPage('/adr/', en.prefix)(content)), + ) +} + +// 5. Per locale content trees (content// → routes//). +for (const locale of locales) { + try { + await syncContentTree(join(contentRoot, locale.code), locale.code, prefixLocaleLinks(locale.code), codes) + } catch { + // No content// yet locale gets English fallback below. + } +} + +// 6. Fallbacks + landing wrappers + ADR chrome for every locale. +for (const locale of locales) +{ + if (locale.code !== en.code) await fallbackCopy(join(routesRoot, en.code), join(routesRoot, locale.code)) + await fixAdrRelativeLinks(locale.code) + await writeLandingWrapper(locale) + await writeAdrLayout(locale) + await writeSectionLayout(locale, 'plugins', 'PLUGIN') + await writeSectionLayout(locale, 'infrastructure', 'INFRA') +} + +// 7. Verify: ADR registry integrity, then every locale must end up with +// pages never deploy an empty or broken one. +await validateAdrRegistry(locales) +for (const locale of locales) { + const count = await countPages(join(routesRoot, locale.code)) + if (count === 0) throw new Error(`sync: locale '${locale.code}' has no pages after sync — aborting`) +} + +console.log(`Locales: ${codes.join(', ')}`) +console.log(`Synchronized ${stats.written} Markdown routes.`) +console.log(`Cleared generated route groups: ${stats.removed.join(', ')}`) diff --git a/Docs/scripts/sync/adr.ts b/Docs/scripts/sync/adr.ts new file mode 100644 index 0000000..9eb8da3 --- /dev/null +++ b/Docs/scripts/sync/adr.ts @@ -0,0 +1,90 @@ +import { readdir, readFile } from 'node:fs/promises' +import { join } from 'node:path' +import type { SiteLocale } from './locales.ts' +import { adrSource, contentRoot } from './paths.ts' + +// --------------------------------------------------------------------------- +// ADR integrity: the registry tables (content/en/adr/README.md, content//adr/) +// and Prev/Next chains are hand-maintained and rot silently as the count +// grows. Every sync verifies: table IDs unique, every row links an existing +// file, every Prev/Next link resolves. Failures throw — a broken registry +// must never deploy quietly. +// --------------------------------------------------------------------------- +const TABLE_ROW = /\|\s*\[ADR-(\d+)\]\(([^)]+)\)/g +const ADR_LINK = /\]\(((?:\/[a-z]{2})?\/adr\/([^/)\s]+)\/?)\)/g + +function slugFrom(href: string): string { + return href + .replace(/^\.\//, '') + .replace(/\.md$/, '') + .split('/') + .filter(Boolean) + .pop() ?? '' +} + +async function adrFiles(code: string): Promise> { + const files = new Set() + const dirs = [join(adrSource), join(contentRoot, code, 'adr')] + for (const dir of dirs) { + let entries + try { + entries = await readdir(dir) + } catch { + continue + } + for (const name of entries) { + if (name.endsWith('.md') && name !== 'README.md') files.add(name.slice(0, -'.md'.length)) + } + } + return files +} + +async function readIndex(code: string, en: SiteLocale): Promise { + const local = join(contentRoot, code, 'adr', 'README.md') + try { + return await readFile(local, 'utf8') + } catch { + // content//adr/ is an optional translation overlay — content/en/adr/ is canonical. + return await readFile(join(adrSource, 'README.md'), 'utf8') + } +} + +export async function validateAdrRegistry(locales: SiteLocale[]): Promise { + const en = locales.find(l => l.code === 'en') ?? locales[0] + for (const locale of locales) { + const files = await adrFiles(locale.code) + const index = await readIndex(locale.code, en) + const seen = new Set() + for (const m of index.matchAll(TABLE_ROW)) { + const [, id, href] = m + if (seen.has(id)) throw new Error(`sync: duplicate ADR-${id} in ${locale.code} registry table`) + seen.add(id) + const slug = slugFrom(href) + if (!slug || !files.has(slug)) { + throw new Error(`sync: ADR-${id} links missing file '${slug}' (${locale.code})`) + } + } + // Prev/Next chains: every /adr// link must resolve (own locale or en fallback). + const enFiles = await adrFiles(en.code) + const checkDirs = [join(contentRoot, locale.code, 'adr'), join(adrSource), join(contentRoot, en.code, 'adr')] + for (const slug of files) { + let content: string | null = null + for (const dir of checkDirs) { + try { + content = await readFile(join(dir, `${slug}.md`), 'utf8') + break + } catch { + continue + } + } + if (!content) continue + for (const m of content.matchAll(ADR_LINK)) { + const target = m[2] + if (target === 'README') continue + if (!files.has(target) && !enFiles.has(target)) { + throw new Error(`sync: ${locale.code}/${slug} links missing ADR page '${target}'`) + } + } + } + } +} diff --git a/Docs/scripts/sync/layouts.ts b/Docs/scripts/sync/layouts.ts new file mode 100644 index 0000000..5d7c921 --- /dev/null +++ b/Docs/scripts/sync/layouts.ts @@ -0,0 +1,124 @@ +import { mkdir, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import type { SiteLocale } from './locales.ts' +import { docsRoot, messagesRoot, readJsonFile, registryPath, routesRoot } from './paths.ts' + +export async function writeRegistry(locales: SiteLocale[]): Promise +{ + const body = `/* eslint-disable */ +// GENERATED by scripts/sync-content.ts - do not edit by hand. +// Add a locale by dropping i18n/messages/.json (with "meta" section) +// and optional content//, then run npm run sync. +export interface SiteLocale { + code: string + prefix: \`/\${string}/\` + label: string + short: string + navThird: 'adr' | 'config' +} + +export const siteLocales: SiteLocale[] = ${JSON.stringify(locales, null, 2)} + +export const defaultLocale: SiteLocale = siteLocales[0] +` + await writeFile(registryPath, body) + + // Static JSON imports (generated import.meta.glob doesn't exist in the + // vite.config.ts node context, and this keeps every consumer identical). + // Locale codes are sanitized to valid identifiers (e.g. pt-BR → ptBR). + const ident = (code: string): string => code.replaceAll(/[^A-Za-z0-9_$]/g, '') + const messagesPath = join(docsRoot, 'src', 'lib', 'locale-messages.ts') + const messagesBody = `/* eslint-disable */ +// GENERATED by scripts/sync-content.ts — do not edit by hand. +${locales.map(l => `import ${ident(l.code)} from '../../i18n/messages/${l.code}.json'`).join('\n')} + +export const localeMessages: Record>> = { +${locales.map(l => ` '${l.code}': ${ident(l.code)},`).join('\n')} +} +` + await writeFile(messagesPath, messagesBody) +} + +export async function writeLandingWrapper(locale: SiteLocale): Promise +{ + const dir = join(routesRoot, locale.code) + const messages = (await readJsonFile(join(messagesRoot, `${locale.code}.json`), `locale messages for '${locale.code}'`)) as + { + landing?: { metaTitle?: string } + label?: string + } + const title = messages.landing?.metaTitle ?? `AuthKit — ${locale.label}` + await mkdir(dir, { recursive: true }) + await writeFile( + join(dir, '+page.svelte'), + ` + + + + +`, + ) + await writeFile(join(dir, '+page.js'), 'export const prerender = true\n') +} + +// ADR section chrome: nested layout wrapping every //adr/* page in +// .adr-page (see $lib/AdrChrome.svelte for the restyling). Generated because +// locale dirs are wiped on every sync. +export async function writeAdrLayout(locale: SiteLocale): Promise +{ + const dir = join(routesRoot, locale.code, 'adr') + await mkdir(dir, { recursive: true }) + await writeFile( + join(dir, '+layout.svelte'), + ` + +
+ + {@render children()} +
+`, + ) +} + +// Section chrome: nested layout wrapping every //
/* page +// in .doc-section (see $lib/SectionChrome.svelte). Generated because locale +// dirs are wiped on every sync. +export async function writeSectionLayout(locale: SiteLocale, section: string, label: string): Promise +{ + const dir = join(routesRoot, locale.code, section) + await mkdir(dir, { recursive: true }) + await writeFile( + join(dir, '+layout.svelte'), + ` + +
+ + {@render children()} +
+`, + ) +} diff --git a/Docs/scripts/sync/locales.ts b/Docs/scripts/sync/locales.ts new file mode 100644 index 0000000..d428f32 --- /dev/null +++ b/Docs/scripts/sync/locales.ts @@ -0,0 +1,53 @@ +import { readdir } from 'node:fs/promises' +import { join } from 'node:path' +import { messagesRoot, readJsonFile } from './paths.ts' + +export interface SiteLocale { + code: string + prefix: `/${string}/` + label: string + short: string + navThird: 'adr' | 'config' +} + +interface LocaleMessages { + meta?: { label?: string; short?: string; navThird?: string } +} + +// --------------------------------------------------------------------------- +// Locale discovery: every i18n/messages/.json defines a locale. +// Adding a language = dropping in one JSON file (+ optional content//). +// Everything else derives from that — no code changes needed. +// --------------------------------------------------------------------------- +export async function discoverLocales(): Promise { + const entries = await readdir(messagesRoot, { withFileTypes: true }) + const locales: SiteLocale[] = [] + for (const entry of entries) { + if (!entry.isFile() || !entry.name.endsWith('.json')) continue + const code = entry.name.slice(0, -'.json'.length) + if (!/^[a-z]{2}(-[A-Z]{2})?$/.test(code)) continue + const messages = (await readJsonFile( + join(messagesRoot, entry.name), + `locale messages for '${code}'`, + )) as LocaleMessages + locales.push({ + code, + prefix: `/${code}/`, + label: messages.meta?.label ?? code, + short: messages.meta?.short ?? code.toUpperCase(), + navThird: messages.meta?.navThird === 'config' ? 'config' : 'adr', + }) + } + // Deterministic order (base first, rest by code) so generated files + // don't churn between machines with different readdir order. + locales.sort((a, b) => { + if (a.code === 'en') return b.code === 'en' ? 0 : -1 + if (b.code === 'en') return 1 + return a.code.localeCompare(b.code) + }) + if (locales.length === 0) throw new Error(`No locales found in ${messagesRoot}`) + return locales +} + +export const codesLike = (locales: SiteLocale[], slug: string): boolean => + locales.some(l => l.code === slug) diff --git a/Docs/scripts/sync/paraglide.ts b/Docs/scripts/sync/paraglide.ts new file mode 100644 index 0000000..f0aefa2 --- /dev/null +++ b/Docs/scripts/sync/paraglide.ts @@ -0,0 +1,43 @@ +import { execFileSync } from 'node:child_process' +import { readdir, readFile, stat, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import type { SiteLocale } from './locales.ts' +import { docsRoot, messagesRoot, settingsPath } from './paths.ts' + +export async function ensureParaglideSettings(locales: SiteLocale[]): Promise { + const raw = await readFile(settingsPath, 'utf8') + const settings = JSON.parse(raw) + const wanted = locales.map(l => l.code) + const current: string[] = settings.locales ?? [] + const same = current.length === wanted.length && wanted.every(code => current.includes(code)) + if (same) return false + // Exact match: add new codes, drop removed ones (order: base first). + const base = wanted.includes('en') ? ['en'] : [wanted[0]] + settings.locales = [...base, ...wanted.filter(code => !base.includes(code))] + await writeFile(settingsPath, `${JSON.stringify(settings, null, 2)}\n`) + return true +} + +export async function paraglideStale(locales: SiteLocale[]): Promise { + try { + const generated = await readdir(join(docsRoot, 'src', 'lib', 'paraglide', 'messages')) + for (const { code } of locales) { + if (!generated.some(f => f.startsWith(`${code}.`) || f === `${code}.js`)) return true + } + const indexTime = (await stat(join(docsRoot, 'src', 'lib', 'paraglide', 'messages', '_index.js'))).mtimeMs + for (const { code } of locales) { + if ((await stat(join(messagesRoot, `${code}.json`))).mtimeMs > indexTime) return true + } + return false + } catch { + return true + } +} + +export function compileParaglide(): void { + execFileSync( + 'npx', + ['@inlang/paraglide-js', 'compile', '--project', './project.inlang', '--outdir', './src/lib/paraglide'], + { cwd: docsRoot, stdio: 'inherit' }, + ) +} diff --git a/Docs/scripts/sync/paths.ts b/Docs/scripts/sync/paths.ts new file mode 100644 index 0000000..42fbfb6 --- /dev/null +++ b/Docs/scripts/sync/paths.ts @@ -0,0 +1,48 @@ +import { readdir, readFile } from 'node:fs/promises' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +export const docsRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..') +export const routesRoot = join(docsRoot, 'src', 'routes') +export const contentRoot = join(docsRoot, 'content') +export const adrSource = join(contentRoot, 'en', 'adr') +export const messagesRoot = join(docsRoot, 'i18n', 'messages') +export const settingsPath = join(docsRoot, 'project.inlang', 'settings.json') +export const registryPath = join(docsRoot, 'src', 'lib', 'site-locales.ts') + +export interface SyncStats { + written: number + removed: string[] +} + +export const stats: SyncStats = { written: 0, removed: [] } + +export async function readJsonFile(path: string, what: string): Promise { + let raw: string + try { + raw = await readFile(path, 'utf8') + } catch (e) { + throw new Error(`sync: cannot read ${what} at ${path}: ${(e as Error).message}`) + } + try { + return JSON.parse(raw) + } catch (e) { + throw new Error(`sync: invalid JSON in ${what} at ${path}: ${(e as Error).message}`) + } +} + +export async function countPages(dir: string): Promise { + let n = 0 + let entries + try { + entries = await readdir(dir, { withFileTypes: true }) + } catch { + return 0 + } + for (const entry of entries) { + const full = join(dir, entry.name) + if (entry.isDirectory()) n += await countPages(full) + else if (entry.name === '+page.md' || entry.name === '+page.svelte') n += 1 + } + return n +} diff --git a/Docs/scripts/sync/routes.ts b/Docs/scripts/sync/routes.ts new file mode 100644 index 0000000..1547ce0 --- /dev/null +++ b/Docs/scripts/sync/routes.ts @@ -0,0 +1,117 @@ +import { cp, mkdir, readdir, readFile, writeFile } from 'node:fs/promises' +import { dirname, join } from 'node:path' +import { routesRoot, stats } from './paths.ts' + +export type Transform = (content: string) => string +export type RouteWriter = (route: string, source: string, transform?: Transform) => Promise + +export const writeRoute: RouteWriter = async (route, source, transform = value => value) => { + const destination = join(routesRoot, route, '+page.md') + await mkdir(dirname(destination), { recursive: true }) + const content = await readFile(source, 'utf8') + await writeFile(destination, transform(content)) + stats.written += 1 +} + +// Root absolute markdown links (](/guide/…) belong to the locale being +// synced rewrite them to //…. Already-prefixed, asset and +// protocol-relative links pass through. +export const prefixLocaleLinks = (locale: string): Transform => content => + content.replaceAll(new RegExp(`(\\]\\()\\/(?!\\/|${locale}\\/|_app\\/)`, 'g'), `$1/${locale}/`) + +// ADR sources link relatively (`./slug.md`, `../../README.md`) — rewrite to +// absolute locale routes under the given target section. +const SIBLING_MD_LINK = /\(\.\/([^\s)]+)\.md\)/g + +export function adrPage(target: '/adr/', homePrefix?: string): Transform { + return content => { + if (homePrefix) content = content.replaceAll('(../../README.md)', `(${homePrefix})`) + return content + .replaceAll(SIBLING_MD_LINK, `(${target}$1/)`) + .replaceAll(`(${target}README/)`, `(${target})`) + } +} + +export async function syncContentTree( + sourceDirectory: string, + routePrefix = '', + transform: Transform = value => value, + skip: string[] = [], +): Promise { + for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) { + const source = join(sourceDirectory, entry.name) + if (entry.isDirectory()) { + await syncContentTree(source, join(routePrefix, entry.name), transform, skip) + continue + } + if (!entry.isFile() || !entry.name.endsWith('.md')) continue + + const route = entry.name === 'README.md' + ? routePrefix + : join(routePrefix, entry.name.slice(0, -'.md'.length)) + // '' is the hand written redirect page; '' landings are generated + // wrappers — never from READMEs (avoids route conflicts). + if (route === '') continue + if (skip.includes(route)) { + console.warn(`sync: skipped ${source} — route '${route}' collides with a locale landing`) + continue + } + await writeRoute(route, source, transform) + } +} + +// Post-pass: content trees (e.g. content//adr/) carry raw relative +// links (`./slug.md`, `../../README.md`) that don't resolve to routes. +// Rewrite them to absolute locale routes under //adr/. +export async function fixAdrRelativeLinks(locale: string): Promise { + const { readFile, writeFile } = await import('node:fs/promises') + const adrDir = join(routesRoot, locale, 'adr') + let entries + try { + entries = await readdir(adrDir, { withFileTypes: true }) + } catch { + return + } + const fix = adrPage(`/${locale}/adr/` as '/adr/', `/${locale}/adr/`) + const targets: string[] = [] + for (const entry of entries) { + if (entry.isFile() && entry.name === '+page.md') targets.push(join(adrDir, entry.name)) + else if (entry.isDirectory()) targets.push(join(adrDir, entry.name, '+page.md')) + } + for (const file of targets) { + try { + const raw = await readFile(file, 'utf8') + const fixed = fix(raw) + if (fixed !== raw) { + await writeFile(file, fixed) + stats.written += 1 + } + } catch { + // Missing +page.md in a fresh dir — nothing to fix. + } + } +} +// so no link ever 404s — translate progressively. +export async function fallbackCopy(fromDir: string, toDir: string): Promise { + let entries + try { + entries = await readdir(fromDir, { withFileTypes: true }) + } catch { + return + } + for (const entry of entries) { + const from = join(fromDir, entry.name) + const to = join(toDir, entry.name) + if (entry.isDirectory()) { + await fallbackCopy(from, to) + continue + } + if (!entry.isFile() || entry.name !== '+page.md') continue + try { + await readFile(to, 'utf8') + } catch { + await mkdir(dirname(to), { recursive: true }) + await cp(from, to) + } + } +} diff --git a/Docs/scripts/sync/versions.ts b/Docs/scripts/sync/versions.ts new file mode 100644 index 0000000..16ea034 --- /dev/null +++ b/Docs/scripts/sync/versions.ts @@ -0,0 +1,98 @@ +import { readdir, readFile, writeFile } from 'node:fs/promises' +import { join } from 'node:path' +import { codesLike } from './locales.ts' +import type { SiteLocale } from './locales.ts' +import { docsRoot } from './paths.ts' + +// --------------------------------------------------------------------------- +// Version manifests: every locale needs sveltepress.versions..json +// (the plugin resolves per-locale manifests by URL prefix; without it the +// theme hides the version selector). The default manifest orchestrates bare +// `versions build`/`validate` across all locales. Created once, never +// overwritten history and current IDs are preserved. Adding a language = +// dropping in messages JSON: the next sync scaffolds its manifest, then run +// `sveltepress versions migrate --site-id --locale `. +// --------------------------------------------------------------------------- +export const DEFAULT_VERSIONS_FILE = 'sveltepress.versions.json' + +export interface VersionManifestSkeleton { + $schema: string + basePath: string + current: { id: string; label: string } + versions: [] + content: { include: string[]; exclude: string[]; shared: string[] } + artifacts?: { mode: string; siteId: string; store: string; sources: string } +} + +export async function ensureVersionManifests(locales: SiteLocale[]): Promise { + const readJson = async (file: string): Promise => { + try { + return JSON.parse(await readFile(join(docsRoot, file), 'utf8')) + } catch { + return null + } + } + const created: string[] = [] + const existing = await Promise.all( + locales.map(l => readJson(`sveltepress.versions.${l.code}.json`)), + ) + const currentId = + (await readJson(DEFAULT_VERSIONS_FILE))?.current?.id ?? + existing.find(m => m?.current?.id)?.current?.id ?? + '0.1' + const siteId = + (await readJson(DEFAULT_VERSIONS_FILE))?.artifacts?.siteId ?? 'authkit-docs' + const skeleton = (basePath: string, sources?: string): VersionManifestSkeleton => ({ + $schema: './node_modules/@sveltepress/cli/schema/versions.schema.json', + basePath, + current: { id: currentId, label: currentId }, + versions: [], + content: { include: ['**'], exclude: [], shared: ['$lib/**', 'static/**'] }, + ...(sources + ? { + artifacts: { + mode: 'incremental', + siteId, + store: '.sveltepress/version-artifacts', + sources, + }, + } + : {}), + }) + if (!(await readJson(DEFAULT_VERSIONS_FILE))) { + await writeFile( + join(docsRoot, DEFAULT_VERSIONS_FILE), + JSON.stringify(skeleton('/v'), null, 2) + '\n', + ) + created.push(DEFAULT_VERSIONS_FILE) + } + for (const locale of locales) { + const file = `sveltepress.versions.${locale.code}.json` + if (await readJson(file)) continue + await writeFile( + join(docsRoot, file), + JSON.stringify( + skeleton(`${locale.prefix}v`, `version-deltas-${locale.code}`), + null, + 2, + ) + '\n', + ) + created.push(file) + } + // Manifests of removed locales are history — never auto-delete, just warn. + const dir = await readdir(docsRoot) + for (const name of dir) { + const m = /^sveltepress\.versions\.([a-z0-9-]+)\.json$/.exec(name) + if (m && !codesLike(locales, m[1])) { + console.warn( + `sync: stale ${name} — locale '${m[1]}' is gone, kept (history). Remove by hand if intended.`, + ) + } + } + if (created.length > 0) { + console.log(`sync: scaffolded version manifests: ${created.join(', ')}`) + console.log( + `sync: next run \`sveltepress versions migrate --site-id ${siteId} --locale \` for each new locale.`, + ) + } +} From 1c0c3d1c35a1cc93a588666f942a6a3a2507fe42 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:10:44 +0200 Subject: [PATCH 14/17] feat: bootstrap docs locale and theme --- Docs/src/locales.ts | 105 +++++++++++++++++++ Docs/src/routes/+layout.js | 3 + Docs/src/routes/+layout.svelte | 26 +++++ Docs/src/routes/+page.js | 1 + Docs/src/routes/+page.svelte | 50 +++++++++ Docs/src/theme.css | 186 +++++++++++++++++++++++++++++++++ 6 files changed, 371 insertions(+) create mode 100644 Docs/src/locales.ts create mode 100644 Docs/src/routes/+layout.js create mode 100644 Docs/src/routes/+layout.svelte create mode 100644 Docs/src/routes/+page.js create mode 100644 Docs/src/routes/+page.svelte create mode 100644 Docs/src/theme.css diff --git a/Docs/src/locales.ts b/Docs/src/locales.ts new file mode 100644 index 0000000..c1d1472 --- /dev/null +++ b/Docs/src/locales.ts @@ -0,0 +1,105 @@ +import type { LocalesConfig } from '@sveltepress/vite' +import { localeMessages } from './lib/locale-messages.ts' +import { siteLocales } from './lib/site-locales.ts' + +// Shiki languages used in code fences across content/, ADR/ and Schemas.md. +// The theme default only ships svelte/sh/js/html/ts/md/css/scss, +// so the list must be extended explicitly (it replaces the default). +export const codeLanguages = [ + 'svelte', + 'sh', + 'js', + 'html', + 'ts', + 'md', + 'css', + 'scss', + 'bash', + 'csharp', + 'http', + 'json', + 'mermaid', + 'proto', +] as const + +// All UI copy for sidebars/navbars comes from i18n/messages/.json +// (docs.* / navbar.*), so a new locale only needs its JSON file. +// Links stay in SveltePress "logical space" (no locale prefix) — the theme +// applies the active locale prefix at render time. Slugs follow the content +// convention: guide/{introduction,quick-start,configuration}, +// reference/rest-api, schemas. Missing pages fall back to English via sync. +function messagesFor(code: string): Record> { + return localeMessages[code] ?? localeMessages.en +} + +function sidebarFor(code: string) { + const docs = messagesFor(code).docs + const group = (key: string, fallback: string, items: { title: string; to: string }[]) => ({ + title: docs[key] ?? fallback, + items, + }) + const guideGroup = group('guide', 'Guide', [ + { title: docs.introduction, to: '/guide/introduction/' }, + { title: docs.quickStart, to: '/guide/quick-start/' }, + { title: docs.configuration, to: '/guide/configuration/' }, + ]) + const pluginsGroup = group('plugins', 'Plugins', [ + { title: docs.devTokens ?? 'DevTokens', to: '/plugins/devtokens/' }, + { title: docs.devTools ?? 'DevTools', to: '/plugins/devtools/' }, + { title: docs.customPlugins ?? 'Custom plugins', to: '/plugins/custom/' }, + ]) + const referenceGroup = group('reference', 'Reference', [ + { title: docs.restApi, to: '/reference/rest-api/' }, + { title: docs.grpc ?? 'gRPC', to: '/reference/grpc/' }, + { title: docs.schemas, to: '/schemas/' }, + ]) + const infraGroup = group('infrastructure', 'Infrastructure', [ + { title: docs.keycloak ?? 'Keycloak', to: '/infrastructure/keycloak/' }, + { title: docs.marten ?? 'Marten + PostgreSQL', to: '/infrastructure/marten/' }, + { title: docs.wolverine ?? 'Wolverine', to: '/infrastructure/wolverine/' }, + { title: docs.docker ?? 'Docker + Kestrel', to: '/infrastructure/docker/' }, + ]) + const adrGroup = group('adrOverview', 'ADR', [ + { title: docs.adrOverview ?? 'ADR', to: '/adr/' }, + ]) + // Fixed global group order on every sidebar — the active section is + // highlighted, never reordered, so navigation doesn't jump between pages. + return { + '/guide/': [guideGroup, pluginsGroup, infraGroup, adrGroup], + '/reference/': [referenceGroup, guideGroup, pluginsGroup, infraGroup, adrGroup], + '/schemas/': [ + group('schemas', 'Schemas', [{ title: docs.schemas, to: '/schemas/' }]), + guideGroup, + pluginsGroup, + infraGroup, + adrGroup, + ], + '/adr/': [guideGroup, pluginsGroup, infraGroup, adrGroup], + '/plugins/': [guideGroup, pluginsGroup, infraGroup, adrGroup], + '/infrastructure/': [guideGroup, pluginsGroup, infraGroup, adrGroup], + } +} + +// Kept for backwards compatibility (were imported elsewhere historically). +export const enSidebar = sidebarFor('en') +export const plSidebar = sidebarFor('pl') + +function navbarFor(code: string) { + const messages = messagesFor(code) + return [{ title: messages.navbar.home, to: `/${code}/` }] +} + +export const locales: LocalesConfig = Object.fromEntries( + siteLocales.map(locale => [ + locale.prefix, + { + lang: locale.code, + label: locale.label, + theme: { + highlighter: { languages: [...codeLanguages] }, + navbar: navbarFor(locale.code), + sidebar: sidebarFor(locale.code), + }, + }, + ]), +) diff --git a/Docs/src/routes/+layout.js b/Docs/src/routes/+layout.js new file mode 100644 index 0000000..5f9abe4 --- /dev/null +++ b/Docs/src/routes/+layout.js @@ -0,0 +1,3 @@ +// Docs (.md) rely on the SveltePress theme, whose components are not +// SSR-safe — keep them client-rendered (SPA fallback), as before. +export const prerender = false diff --git a/Docs/src/routes/+layout.svelte b/Docs/src/routes/+layout.svelte new file mode 100644 index 0000000..caba867 --- /dev/null +++ b/Docs/src/routes/+layout.svelte @@ -0,0 +1,26 @@ + + +{@render children()} diff --git a/Docs/src/routes/+page.js b/Docs/src/routes/+page.js new file mode 100644 index 0000000..176ae64 --- /dev/null +++ b/Docs/src/routes/+page.js @@ -0,0 +1 @@ +export const prerender = true diff --git a/Docs/src/routes/+page.svelte b/Docs/src/routes/+page.svelte new file mode 100644 index 0000000..00dcbda --- /dev/null +++ b/Docs/src/routes/+page.svelte @@ -0,0 +1,50 @@ + + + + + + AuthKit + + + + +
+

+ {#each siteLocales as l} + {l.label}{' '} + {/each} +

+
+ + diff --git a/Docs/src/theme.css b/Docs/src/theme.css new file mode 100644 index 0000000..6a9d562 --- /dev/null +++ b/Docs/src/theme.css @@ -0,0 +1,186 @@ +@layer theme, components, utilities; +@import "tailwindcss/theme.css" layer(theme); +@import "tailwindcss/utilities.css" layer(utilities); + +/* Class-based dark mode: the theme toggles html.dark / html[data-theme='dark'], + * not prefers-color-scheme, so the `dark:` variant is rebound to those. */ +@custom-variant dark (&:where(html.dark, html.dark *, html[data-theme='dark'], html[data-theme='dark'] *)); + +@theme { + --color-night: #060607; + --color-panel: #0b0b0d; + --color-card: #0c0c0e; + --color-raise: #131316; + --color-well: #1c1c1f; + --color-edge: #1d1d20; + --color-edge2: #2a2a2e; + --color-faint: #636366; + --color-fog: #8e8e93; + --color-mist: #a1a1aa; + --color-paper: #f4f4f5; + --font-mono: ui-monospace, 'SF Mono', Menlo, monospace; +} + +/* + * Brand overrides: monochrome (landing) instead of the default theme rose. + * The UnoCSS accent (`svp-primary`) is set via `themeColor` in vite.config; + * the remaining rose comes from DocSearch variables reused as generic + * accents (blockquote border, focus outline, search highlights). + */ +:root:root { + --docsearch-primary-color: #52525b; + --docsearch-logo-color: #a1a1aa; + --docsearch-highlight-color: #e4e4e7; + --docsearch-focus-color: #e4e4e7; + --docsearch-soft-primary-color: rgb(161 161 170 / 12%); + --docsearch-hit-highlight-color: rgb(161 161 170 / 14%); + --docsearch-searchbox-shadow: inset 0 0 0 1px #3f3f46; +} + +:root:root.dark, +:root:root[data-theme='dark'] { + --docsearch-primary-color: #d4d4d8; + --docsearch-logo-color: #a1a1aa; + --docsearch-highlight-color: #f4f4f5; + --docsearch-focus-color: #f4f4f5; + --docsearch-soft-primary-color: rgb(212 212 216 / 14%); + --docsearch-hit-highlight-color: rgb(212 212 216 / 18%); + --docsearch-searchbox-shadow: inset 0 0 0 1px #3f3f46; +} + +/* + * Shell surfaces: landing palette instead of theme zinc. + * Specificity (html prefix + class) outranks the UnoCSS utilities. + */ +html.dark body, +html[data-theme='dark'] body { + background-color: #060607; +} + +html.dark .theme-default-sidebar.theme-default-sidebar, +html[data-theme='dark'] .theme-default-sidebar.theme-default-sidebar { + background-color: #060607; +} + +html.dark header.header.header, +html[data-theme='dark'] header.header.header { + background-color: #060607; +} + +/* + * Inline code + admonitions: landing monochrome instead of theme + * orange/green/red/amber semantics. `body` in the selector outranks + * the theme rules. + */ +html.dark body :not(pre) > code, +html[data-theme='dark'] body :not(pre) > code { + color: #e4e4e7; +} + +/* + * Code blocks: landing panel instead of night-owl blue. Shiki sets the + * background inline, hence !important. Token colors stay (readability, + * same as sveltepress.site). + */ +html.dark body pre.shiki, +html[data-theme='dark'] body pre.shiki { + background-color: #0c0c0e !important; + border: 1px solid #1d1d20; +} + +/* + * Search modal (Pagefind): landing panel. Plain theme selectors, so + * `body` in ours outranks them. + */ +html.dark body .local-search-backdrop, +html[data-theme='dark'] body .local-search-backdrop { + background-color: rgb(0 0 0 / 0.65); + backdrop-filter: blur(8px); +} + +html.dark body .local-search-modal, +html[data-theme='dark'] body .local-search-modal { + background-color: #0c0c0e; + border: 1px solid #2a2a2e; + border-radius: 16px; + box-shadow: 0 32px 64px -16px rgb(0 0 0 / 0.7); +} + +html.dark body .search-header, +html[data-theme='dark'] body .search-header { + border-bottom-color: #1d1d20; + padding: 1rem 1.1rem; +} + +html.dark body .search-input, +html[data-theme='dark'] body .search-input { + font-size: 1.05rem; +} + +html.dark body .esc-button, +html[data-theme='dark'] body .esc-button { + border-radius: 999px; + padding: 0.25rem 0.6rem; + letter-spacing: 0.08em; +} + +html.dark body .result-item.selected, +html[data-theme='dark'] body .result-item.selected { + background-color: #1a1a1e; + outline: 1px solid #2a2a2e; + outline-offset: -1px; +} + +html.dark body .notice-icon, +html[data-theme='dark'] body .notice-icon { + color: #636366; +} + +html.dark body .search-footer, +html[data-theme='dark'] body .search-footer { + background-color: #0b0b0d; + border-top-color: #1d1d20; +} + +html.dark body .shortcut-tip kbd, +html[data-theme='dark'] body .shortcut-tip kbd { + background-color: #131316; + border-color: #2a2a2e; + border-radius: 6px; + padding: 0.15rem 0.4rem; + color: #d4d4d8; +} + +/* + * Introduction hero CTA. Card grids live in $lib/IntroCards.svelte + * (scoped styles); section

headings stay in markdown for the TOC. + */ +.content .intro-cta { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; + margin: 1.6rem 0 0; +} +.content .intro-cta a { + text-decoration: none; + font-size: 0.9rem; + font-weight: 550; + padding: 0.7rem 1.5rem; + border-radius: 999px; +} +.content .intro-cta__primary { + background: #f4f4f5; + color: #060607; +} +.content .intro-cta__primary:hover { + background: #fff; + color: #060607; +} +.content .intro-cta__secondary { + color: inherit; + border: 1px solid #d4d4d8; +} +html.dark body .content .intro-cta__secondary, +html[data-theme='dark'] body .content .intro-cta__secondary { + border-color: #2a2a2e; +} From 9c0a06a3388f1159e53454567cda01f7425d7ba6 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:24:50 +0200 Subject: [PATCH 15/17] feat: centralize locale-aware docs labels --- Docs/src/lib/adr/registry-filter.ts | 19 +++++++----- Docs/src/lib/chrome/content-hero.ts | 4 ++- Docs/src/lib/chrome/labels.ts | 47 +++++++++++++++++++++++++++++ Docs/src/lib/locale-messages.ts | 9 ++++++ Docs/src/lib/locale-strategy.ts | 32 ++++++++++++++++++++ 5 files changed, 102 insertions(+), 9 deletions(-) create mode 100644 Docs/src/lib/chrome/labels.ts create mode 100644 Docs/src/lib/locale-messages.ts create mode 100644 Docs/src/lib/locale-strategy.ts diff --git a/Docs/src/lib/adr/registry-filter.ts b/Docs/src/lib/adr/registry-filter.ts index a8aa5ae..5fee212 100644 --- a/Docs/src/lib/adr/registry-filter.ts +++ b/Docs/src/lib/adr/registry-filter.ts @@ -25,19 +25,22 @@ export function buildRegistryFilter(table: HTMLTableElement, labels: FilterLabel ), ] - const bar = el('div', 'adr-filter') - const input = el('input', 'adr-filter__search') + const bar = el('div', 'adr-filter mt-4 mb-0.5 flex flex-wrap items-center gap-2.5 rounded-[10px] border border-edge2 bg-panel px-3.5 py-2.5') + const input = el('input', 'adr-filter__search min-w-0 flex-[1_1_14rem] rounded-lg border border-edge2 bg-raise px-3 py-2 font-inherit text-[0.85rem] text-paper outline-none placeholder:text-faint focus:border-[#52525b]') input.type = 'search' input.placeholder = labels.search input.setAttribute('aria-label', labels.search) - const pills = el('div', 'adr-filter__pills') + const pills = el('div', 'adr-filter__pills flex flex-wrap gap-1.5') pills.setAttribute('role', 'group') let area = '' const buttons: HTMLButtonElement[] = [] - for (const name of ['', ...areas]) - { - const b = el('button', 'adr-filter__pill', name || labels.all) + for (const name of ['', ...areas]) { + const b = el( + 'button', + 'adr-filter__pill cursor-pointer rounded-full border border-edge2 bg-transparent px-3 py-1.5 font-mono text-[0.7rem] tracking-[0.06em] text-mist uppercase transition-colors hover:border-[#52525b] hover:text-paper aria-pressed:border-[#52525b] aria-pressed:bg-well aria-pressed:text-[#fafafa]', + name || labels.all, + ) b.type = 'button' b.setAttribute('aria-pressed', name === '' ? 'true' : 'false') if (name === '') b.classList.add('is-active') @@ -54,9 +57,9 @@ export function buildRegistryFilter(table: HTMLTableElement, labels: FilterLabel pills.appendChild(b) } - const count = el('span', 'adr-filter__count') + const count = el('span', 'adr-filter__count ml-auto font-mono text-[0.7rem] tracking-[0.08em] whitespace-nowrap text-faint') count.setAttribute('aria-live', 'polite') - const empty = el('p', 'adr-filter__empty', labels.empty) + const empty = el('p', 'adr-filter__empty mt-2 rounded-[10px] border border-dashed border-edge2 p-3.5 text-center text-[0.85rem] text-fog', labels.empty) empty.hidden = true function apply(): void diff --git a/Docs/src/lib/chrome/content-hero.ts b/Docs/src/lib/chrome/content-hero.ts index f89a335..c6d0f78 100644 --- a/Docs/src/lib/chrome/content-hero.ts +++ b/Docs/src/lib/chrome/content-hero.ts @@ -13,6 +13,8 @@ export interface HeroNamespace { num: string label: string nav: string + /** Optional classes for section links inside the nav (default: none). */ + link?: string } export interface HeroStat { @@ -61,7 +63,7 @@ export function appendSectionNav( const nav = el('nav', ns.nav) if (ariaLabel) nav.setAttribute('aria-label', ariaLabel) for (const { href, text } of links) { - const a = el('a', '', text) + const a = el('a', ns.link ?? '', text) a.href = href nav.appendChild(a) } diff --git a/Docs/src/lib/chrome/labels.ts b/Docs/src/lib/chrome/labels.ts new file mode 100644 index 0000000..b8698c9 --- /dev/null +++ b/Docs/src/lib/chrome/labels.ts @@ -0,0 +1,47 @@ +// Central label provider for content-chrome components (AdrChrome, +// SectionChrome, registry filter). Single source of truth: i18n/messages +// (paraglide) — no hardcoded pl/en ternaries scattered across components. +// Adding a language = adding a `chrome` section to its messages JSON. +import * as m from '$lib/paraglide/messages.js' + +export interface ChromeLabels { + decisions: string + areas: string + latestEntry: string + registrySections: string + sections: string + read: string + search: string + all: string + shown: string + empty: string +} + +type MessageFn = (params?: undefined, options?: { locale?: string }) => string + +function t(locale: string, key: string): string { + const fn = (m as unknown as Record)[key] + return fn?.(undefined, { locale }) ?? key +} + +/** Locale code from ('en', 'pl', …). Falls back to 'en'. */ +export function documentLocale(): string { + if (typeof document === 'undefined') return 'en' + return document.documentElement.lang.slice(0, 2) || 'en' +} + +/** All chrome labels for a locale. Unknown locales fall back via paraglide. */ +export function chromeLabels(locale: string): ChromeLabels { + return { + decisions: t(locale, 'chrome.decisions'), + areas: t(locale, 'chrome.areas'), + latestEntry: t(locale, 'chrome.latestEntry'), + registrySections: t(locale, 'chrome.registrySections'), + sections: t(locale, 'chrome.sections'), + read: t(locale, 'chrome.read'), + search: t(locale, 'chrome.search'), + all: t(locale, 'chrome.all'), + shown: t(locale, 'chrome.shown'), + empty: t(locale, 'chrome.empty'), + } +} diff --git a/Docs/src/lib/locale-messages.ts b/Docs/src/lib/locale-messages.ts new file mode 100644 index 0000000..ad375f4 --- /dev/null +++ b/Docs/src/lib/locale-messages.ts @@ -0,0 +1,9 @@ +/* eslint-disable */ +// GENERATED by scripts/sync-content.ts — do not edit by hand. +import en from '../../i18n/messages/en.json' +import pl from '../../i18n/messages/pl.json' + +export const localeMessages: Record>> = { + 'en': en, + 'pl': pl, +} diff --git a/Docs/src/lib/locale-strategy.ts b/Docs/src/lib/locale-strategy.ts new file mode 100644 index 0000000..f1925d7 --- /dev/null +++ b/Docs/src/lib/locale-strategy.ts @@ -0,0 +1,32 @@ +import { + defineCustomClientStrategy, + defineCustomServerStrategy, +} from './paraglide/runtime' +import { siteLocales } from './site-locales.ts' + +// SveltePress serves locales from physical URL prefixes (e.g. '/en/', +// '/pl/') defined in the generated registry (src/lib/site-locales.ts). +// The Paraglide "url" strategy is OFF on purpose (it would de-localize URLs +// and fight SveltePress routing), so this custom strategy mirrors the +// SveltePress prefix into the Paraglide locale. Bare '/' is the redirect +// page — treated as the default locale. + +const STRATEGY_NAME = 'custom-sveltepress' as const + +export function localeFromPathname(pathname: string): string { + const hit = siteLocales.find( + locale => pathname === locale.prefix.slice(0, -1) || pathname.startsWith(locale.prefix), + ) + return hit?.code ?? siteLocales[0].code +} + +defineCustomServerStrategy(STRATEGY_NAME, { + getLocale: (request) => localeFromPathname(new URL(request.url).pathname), +}) + +defineCustomClientStrategy(STRATEGY_NAME, { + getLocale: () => localeFromPathname(window.location.pathname), + setLocale: (locale) => { + document.cookie = `PARAGLIDE_LOCALE=${locale}; path=/; max-age=34560000; SameSite=Lax` + }, +}) From 353397764452feee12e1a236e086eb91dc199838 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:26:07 +0200 Subject: [PATCH 16/17] ref: improve ADR localization and added docs tooling --- Docs/i18n/messages/en.json | 19 ++++++++++- Docs/i18n/messages/pl.json | 19 ++++++++++- Docs/src/lib/adr/section-match.ts | 55 +++++++++++++++++++++++++++++++ Taskfile.yml | 20 +++++++++++ 4 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 Docs/src/lib/adr/section-match.ts diff --git a/Docs/i18n/messages/en.json b/Docs/i18n/messages/en.json index a6dd1e9..cfbc750 100644 --- a/Docs/i18n/messages/en.json +++ b/Docs/i18n/messages/en.json @@ -79,5 +79,22 @@ "feat3T": "One host, two transports", "feat3D": "The same surface over REST and gRPC. Wolverine dispatches, Marten on PostgreSQL stores the audit trail, plugins extend everything.", "mit": "AuthKit MIT" + }, + "chrome": { + "decisions": "decisions", + "areas": "areas", + "latestEntry": "latest entry", + "registrySections": "Registry sections", + "sections": "sections", + "read": "read", + "search": "Search by ID or title…", + "all": "All", + "shown": "of", + "empty": "No results for the given filters." + }, + "sections": { + "decision": "decision", + "rejected": "rejected", + "consequences": "consequences" } -} +} \ No newline at end of file diff --git a/Docs/i18n/messages/pl.json b/Docs/i18n/messages/pl.json index 67fd536..de123a6 100644 --- a/Docs/i18n/messages/pl.json +++ b/Docs/i18n/messages/pl.json @@ -79,5 +79,22 @@ "feat3T": "Jeden host, dwa transporty", "feat3D": "Ta sama powierzchnia przez REST i gRPC. Wolverine dystrybuuje, Marten na PostgreSQL trzyma ślad audytowy, wtyczki rozszerzają wszystko.", "mit": "AuthKit MIT" + }, + "chrome": { + "decisions": "decyzji", + "areas": "obszary", + "latestEntry": "ostatni wpis", + "registrySections": "Sekcje rejestru", + "sections": "sekcji", + "read": "czytania", + "search": "Szukaj po ID lub tytule…", + "all": "Wszystkie", + "shown": "z", + "empty": "Brak wyników dla podanych filtrów." + }, + "sections": { + "decision": "decyzja", + "rejected": "odrzucone", + "consequences": "konsekwencje" } -} +} \ No newline at end of file diff --git a/Docs/src/lib/adr/section-match.ts b/Docs/src/lib/adr/section-match.ts new file mode 100644 index 0000000..fc26341 --- /dev/null +++ b/Docs/src/lib/adr/section-match.ts @@ -0,0 +1,55 @@ +// Registry matching ADR section headings to wrapper classes. +// +// Heading slugs come from translated markdown (#Decyzja vs #Decision), so the +// source of truth is i18n/messages (`sections.*` per locale) — not this file. +// A new language only adds its slugs to its messages JSON. Custom (non-i18n) +// mappings can still be added at runtime via registerSection(). +import * as m from '$lib/paraglide/messages.js' + +export interface SectionEntry { + /** Heading slugs (without '#') for one-off custom mappings. */ + slugs: string[] + /** Wrapper class applied to the section. */ + cls: string +} + +const BUILTINS: { key: string; cls: string }[] = [ + { key: 'sections.decision', cls: 'adr-decision' }, + { key: 'sections.rejected', cls: 'adr-rejected' }, + { key: 'sections.consequences', cls: 'adr-consequences' }, +] + +const CUSTOM: SectionEntry[] = [] + +type MessageFn = (params?: undefined, options?: { locale?: string }) => string + +function slugFor(locale: string, key: string): string | null { + const fn = (m as unknown as Record)[key] + const value = fn?.(undefined, { locale }) + // Paraglide falls back to the key itself when untranslated — not a slug. + if (!value || value === key) return null + return value.toLowerCase() +} + +/** Register (or override) a custom section mapping. */ +export function registerSection(slugs: string[], cls: string): void { + const norm = slugs.map(s => s.toLowerCase()) + const hit = CUSTOM.findIndex(e => e.cls === cls) + if (hit >= 0) CUSTOM[hit] = { slugs: norm, cls } + else CUSTOM.push({ slugs: norm, cls }) +} + +/** + * Match an h2 anchor href (e.g. '#Decyzja', '/en/adr/001-x/#Decision') + * to a wrapper class for the given locale. Case-insensitive, + * suffix-tolerant. Returns null when nothing matches. + */ +export function matchSection(href: string, locale = 'en'): string | null { + const slug = href.split('#').pop()?.toLowerCase() ?? '' + if (!slug) return null + for (const { key, cls } of BUILTINS) { + const expected = slugFor(locale, key) + if (expected && (slug === expected || slug.endsWith(expected))) return cls + } + return CUSTOM.find(e => e.slugs.some(s => slug === s || slug.endsWith(s)))?.cls ?? null +} diff --git a/Taskfile.yml b/Taskfile.yml index 45a1e33..378316c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -71,6 +71,26 @@ tasks: cmds: - dotnet format {{.SOLUTION}} + docs:install: + desc: Install SveltePress documentation dependencies + dir: Docs + cmds: + - npm install + + docs:build: + desc: Build the SveltePress documentation site + dir: Docs + deps: [docs:install] + cmds: + - npm run build + + docs:dev: + desc: Start the SveltePress documentation site locally + dir: Docs + deps: [docs:install] + cmds: + - npm run dev + security:audit: desc: List vulnerable NuGet packages (incl. transitive) cmds: From ce70c59d02fde66b6d5797e33a7e72bb9fe53ed8 Mon Sep 17 00:00:00 2001 From: "Rian.be" Date: Wed, 23 Sep 2026 02:27:26 +0200 Subject: [PATCH 17/17] feat: introduce docs landing and content chrome --- Docs/src/lib/AdrChrome.svelte | 737 +++++++++++++++++++++++++++++ Docs/src/lib/IntroCards.svelte | 22 + Docs/src/lib/Landing.svelte | 177 +++++++ Docs/src/lib/LanguageToggle.svelte | 94 ++++ Docs/src/lib/SectionChrome.svelte | 375 +++++++++++++++ README.md | 3 +- 6 files changed, 1407 insertions(+), 1 deletion(-) create mode 100644 Docs/src/lib/AdrChrome.svelte create mode 100644 Docs/src/lib/IntroCards.svelte create mode 100644 Docs/src/lib/Landing.svelte create mode 100644 Docs/src/lib/LanguageToggle.svelte create mode 100644 Docs/src/lib/SectionChrome.svelte diff --git a/Docs/src/lib/AdrChrome.svelte b/Docs/src/lib/AdrChrome.svelte new file mode 100644 index 0000000..0d07a93 --- /dev/null +++ b/Docs/src/lib/AdrChrome.svelte @@ -0,0 +1,737 @@ + + +
+ ADR  /  {kicker} + {num ?? 'ADR'} +
+ + diff --git a/Docs/src/lib/IntroCards.svelte b/Docs/src/lib/IntroCards.svelte new file mode 100644 index 0000000..379f519 --- /dev/null +++ b/Docs/src/lib/IntroCards.svelte @@ -0,0 +1,22 @@ + + +
+ {#each cards as card} +
+ + {card.title} + {card.desc} + {#if card.href} + {card.linkLabel ?? linkLabel} + {/if} +
+ {/each} +
diff --git a/Docs/src/lib/Landing.svelte b/Docs/src/lib/Landing.svelte new file mode 100644 index 0000000..6180f35 --- /dev/null +++ b/Docs/src/lib/Landing.svelte @@ -0,0 +1,177 @@ + + + + {t('landing.metaTitle')} + + + + +
+ + + + +

{t('landing.heroTitleA')}
{t('landing.heroTitleB')}

+

{t('landing.heroSub')}

+ +
+ +
+ {#each hexes as h, i} + (open = i)} + aria-haspopup="dialog" + aria-label="{h.title} — {t('landing.detailsMore')}" + initial={{ opacity: 0, y: 16 }} + whileInView={{ opacity: 1, y: 0 }} + viewport={{ once: true, margin: '-40px' }} + transition={{ duration: 0.45, delay: i * 0.08 }} + whileHover={{ scale: 1.03 }} + whileTap={{ scale: 0.98 }} + > + + + {h.num} + {h.title} + {h.sub} + {t('landing.detailsMore')} + + + {#if i < hexes.length - 1} + + {/if} + {/each} +
+ + {#if open !== null} + {@const h = hexes[open]} + + {/if} + +
+ {#each features as f, i} + + +

{f.t}

+

{f.d}

+
+ {/each} +
+ + +
+ + diff --git a/Docs/src/lib/LanguageToggle.svelte b/Docs/src/lib/LanguageToggle.svelte new file mode 100644 index 0000000..03faec0 --- /dev/null +++ b/Docs/src/lib/LanguageToggle.svelte @@ -0,0 +1,94 @@ + + +
+ + {#if open} +
    + {#each langs as l} +
  • + +
  • + {/each} +
+ {/if} +
diff --git a/Docs/src/lib/SectionChrome.svelte b/Docs/src/lib/SectionChrome.svelte new file mode 100644 index 0000000..e667dd8 --- /dev/null +++ b/Docs/src/lib/SectionChrome.svelte @@ -0,0 +1,375 @@ + + +
+ {section}  /  {name.toUpperCase()} + {name.toUpperCase() || section} +
+ + diff --git a/README.md b/README.md index 69855a8..2069d4e 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,9 @@ The host listens on the address configured in `Server:Host` (default `http://0.0 | Topic | Link | | --- | --- | | Documentation index | [Docs](Docs/README.md) | +| SveltePress site | Run `task docs:dev` locally | | Schemas & Diagrams | [Schemas](Docs/Schemas.md) | -| Architecture Decision Records | [ADRs](Docs/ADR/README.md) | +| Architecture Decision Records | [ADRs](Docs/content/en/adr/README.md) | ## Contributing