diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index cd98e89..b9bbbab 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -116,6 +116,9 @@ jobs: needs: validate if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish-prerelease == 'true' environment: prerelease + permissions: + contents: read + id-token: write steps: - name: Checkout code @@ -138,7 +141,7 @@ jobs: - name: Install Python build tools run: | python -m pip install --upgrade pip - pip install build twine + pip install build - name: Get version and create pre-release tag id: version @@ -163,16 +166,12 @@ jobs: - name: Publish TypeScript to npm (next tag) working-directory: packages/flarelette-jwt-ts - run: npm publish --tag next --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --provenance --tag next --access public - name: Publish Python to PyPI (with pre-release classifier) - working-directory: packages/flarelette-jwt-py - run: python -m twine upload dist/* - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: packages/flarelette-jwt-py/dist/ - name: Summary run: | diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index e4377a7..4a99e86 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -22,5 +22,6 @@ jobs: with: fail-on-severity: moderate comment-summary-in-pr: always - # Allow LGPL (more permissive than GPL) - allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, LGPL-2.1, LGPL-3.0, MPL-2.0, BlueOak-1.0.0 + # SPDX allowlist for dependencies currently in this repo's lockfile. + # Keep this explicit so license policy changes are intentional in PRs. + allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, BlueOak-1.0.0, MPL-2.0, Zlib, CC0-1.0, Python-2.0, LGPL-2.0-only, LGPL-2.1, LGPL-2.1-only, LGPL-3.0, LGPL-3.0-only, LGPL-3.0-or-later diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index 2f6c40a..2556121 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -23,6 +23,9 @@ jobs: publish-npm: runs-on: ubuntu-latest if: ${{ github.event.inputs.package == 'typescript' || github.event.inputs.package == 'both' }} + permissions: + contents: read + id-token: write steps: - name: Checkout code @@ -44,13 +47,14 @@ jobs: - name: Publish to npm working-directory: packages/flarelette-jwt-ts - run: npm publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --provenance --access public publish-pypi: runs-on: ubuntu-latest if: ${{ github.event.inputs.package == 'python' || github.event.inputs.package == 'both' }} + permissions: + contents: read + id-token: write steps: - name: Checkout code @@ -66,7 +70,7 @@ jobs: - name: Install build tools run: | python -m pip install --upgrade pip - pip install build twine + pip install build - name: Build Python package working-directory: packages/flarelette-jwt-py @@ -75,8 +79,6 @@ jobs: python -m build - name: Publish to PyPI - working-directory: packages/flarelette-jwt-py - run: python -m twine upload dist/* - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: packages/flarelette-jwt-py/dist/ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e101522..8ab66da 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,6 +31,9 @@ jobs: needs: release-please runs-on: ubuntu-latest if: ${{ needs.release-please.outputs.ts_release_created }} + permissions: + contents: read + id-token: write steps: - name: Checkout code @@ -50,14 +53,15 @@ jobs: - name: Publish to npm working-directory: packages/flarelette-jwt-ts - run: npm publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --provenance --access public publish-pypi: needs: release-please runs-on: ubuntu-latest if: ${{ needs.release-please.outputs.py_release_created }} + permissions: + contents: read + id-token: write steps: - name: Checkout code @@ -71,7 +75,7 @@ jobs: - name: Install build tools run: | python -m pip install --upgrade pip - pip install build twine + pip install build - name: Build Python package working-directory: packages/flarelette-jwt-py @@ -80,8 +84,6 @@ jobs: python -m build - name: Publish to PyPI - working-directory: packages/flarelette-jwt-py - run: python -m twine upload dist/* - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: packages/flarelette-jwt-py/dist/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 458b712..7cde73b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -288,7 +288,7 @@ The project uses automated releases via [release-please](https://github.com/goog See **[RELEASING.md](RELEASING.md)** for detailed release process and **[RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md)** for setup. -**For maintainers:** Ensure `NPM_TOKEN` and `PYPI_TOKEN` secrets are configured in repository settings. +**For maintainers:** Configure npm and PyPI trusted publishing for this repository/workflow (GitHub OIDC). `NPM_TOKEN` and `PYPI_TOKEN` secrets are not required. ## Questions? diff --git a/ENHANCEMENT_JWKS_HTTP_feedback.md b/ENHANCEMENT_JWKS_HTTP_feedback.md index ebdecaf..d3dd3f4 100644 --- a/ENHANCEMENT_JWKS_HTTP_feedback.md +++ b/ENHANCEMENT_JWKS_HTTP_feedback.md @@ -15,7 +15,7 @@ I’ll call out where I think you’re solid, and then a few small polish / hard - **HS512 secret strength:** 64-byte minimum with explicit enforcement. - **Single-mode requirement:** config error if HS + asym are both set. -From a design perspective, this is _much_ safer than the majority of “roll your own JWT” setups in the wild. +From a design perspective, this is _much_ safer than the majority of "roll your own JWT" setups in the wild. --- @@ -50,9 +50,9 @@ Narrower is always safer. --- -### 2. Make the “mode determined by config” super explicit +### 2. Make the "mode determined by config" super explicit -You describe it correctly, but I’d tighten the language so nobody later “simplifies” it back to trusting `alg`: +You describe it correctly, but I’d tighten the language so nobody later "simplifies" it back to trusting `alg`: > **Mode selection** > @@ -73,7 +73,7 @@ That’s great. I’d add one short line: > When importing JWKs, the expected algorithm (`'EdDSA'`, `'RS256'`, etc.) is provided explicitly, so keys cannot be repurposed for other algorithms even within the same key family. -That signals that you’re not just whitelisting “any RS\*”, you’re actually pinning at import time too. +That signals that you’re not just whitelisting "any RS\*", you’re actually pinning at import time too. --- @@ -83,14 +83,14 @@ Returning `null` to callers is fine, but I’d explicitly say: > Internally, verification failures are **logged with structured metadata** (issuer, kid, reason category) and counted in metrics. Externally, all failures are returned as `null` to avoid leaking details. -Otherwise someone might over-interpret “fail-silent” as “we don’t log anything,” which would be painful in prod. +Otherwise someone might over-interpret "fail-silent" as "we don’t log anything," which would be painful in prod. --- ### 5. A couple of small wording / clarity tweaks -- You sometimes say **“decrypt key”** – for JWT as you’re using it, it’s **sign/verify**, not encrypt/decrypt. I’d keep wording to “signing key” / “verification key” to avoid confusion with JWE. -- In “Security Checklist,” maybe add: +- You sometimes say **"decrypt key"** – for JWT as you’re using it, it’s **sign/verify**, not encrypt/decrypt. I’d keep wording to "signing key" / "verification key" to avoid confusion with JWE. +- In "Security Checklist," maybe add: - `[ ] JWT_AUD is specific per service (no wildcard audiences)` – avoids token reuse between services. --- @@ -107,4 +107,4 @@ From a security-model standpoint, this looks **strong and well-documented**: - EdDSA with JWKS + optional thumbprint pinning - Reasonable claim validation (`iss`, `aud`, `exp`, `nbf`, `iat`) -If you clean up the minor consistency bits (RSA vs not, “decrypt” wording, explicit mention of logging), I’d feel very comfortable shipping this as the public “here’s why you can trust our JWT handling” story for flarelette. +If you clean up the minor consistency bits (RSA vs not, "decrypt" wording, explicit mention of logging), I’d feel very comfortable shipping this as the public "here’s why you can trust our JWT handling" story for flarelette. diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md index c8a6844..bbf81dc 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/IMPLEMENTATION_SUMMARY.md @@ -104,7 +104,7 @@ Added exports for all new explicit API functions and types. ### 4. Documentation -**New Guide:** `docs/explicit-config.md` +**New Guide:** `docs/user-guide/explicit-config.md` - Complete API reference - Use case examples @@ -257,7 +257,7 @@ export async function mintToken(c: Context) { - ✨ **Added:** `packages/flarelette-jwt-ts/src/explicit.ts` (489 lines) - ✨ **Added:** `packages/flarelette-jwt-ts/tests/explicit.test.ts` (470 lines) -- ✨ **Added:** `docs/explicit-config.md` (complete guide) +- ✨ **Added:** `docs/user-guide/explicit-config.md` (complete guide) - ✨ **Added:** `examples/explicit-config-example.ts` (example code) - 📝 **Updated:** `packages/flarelette-jwt-ts/src/index.ts` (added exports) - 📝 **Updated:** `README.md` (added new API section) diff --git a/README.md b/README.md index 7db6b4f..4206591 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ **Environment-driven JWT authentication for Cloudflare Workers. Like Starlette, but for the edge.** -Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, loads secrets via Cloudflare bindings, and works across Workers, Node.js, and Python runtimes. +Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, and supports ES512 and RSA for external OIDC verification. Loads secrets via Cloudflare bindings and works across Workers, Node.js, and Python runtimes. ## Part of the Flarelette Ecosystem @@ -88,7 +88,7 @@ const token = await signWithConfig({ sub: 'user123' }, config) const payload = await verifyWithConfig(token, config) ``` -> **New in v1.9.0:** The explicit configuration API eliminates environment setup complexity. See [Explicit Configuration Guide](./docs/explicit-config.md). +> **New in v1.9.0:** The explicit configuration API eliminates environment setup complexity. See [Explicit Configuration Guide](./docs/user-guide/explicit-config.md). ### Basic Example (Environment-Based) @@ -145,7 +145,7 @@ Flarelette JWT Kit is designed to prevent common JWT vulnerabilities: **Mode selection is driven exclusively by server environment variables:** - HS512 mode: `algorithms: ['HS512']` only -- EdDSA/RSA mode: `algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512']` only +- EdDSA/ECDSA/RSA mode: `algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512']` only The `alg` header is treated as untrusted input and must match the allowed algorithms for the selected mode. Mismatches are rejected. @@ -239,7 +239,7 @@ When verifying tokens, the library uses the first available key source in this o ## Documentation - **[Getting Started](./docs/getting-started.md)** — Installation, first token, and basic setup -- **[Explicit Configuration](./docs/explicit-config.md)** 🆕 — No environment setup required! Use config objects directly +- **[Explicit Configuration](./docs/user-guide/explicit-config.md)** 🆕 — No environment setup required! Use config objects directly - **[Core Concepts](./docs/core-concepts.md)** — Algorithms, modes, and architecture - **[Usage Guide](./docs/usage-guide.md)** — Complete API reference for TypeScript and Python - **[Service Delegation](./docs/service-delegation.md)** — RFC 8693 actor claims for zero-trust @@ -254,10 +254,12 @@ When verifying tokens, the library uses the first available key source in this o npx flarelette-jwt-secret --len=64 --dotenv ``` -**Generate EdDSA keypairs:** +**Generate asymmetric keypairs (EdDSA default, or ES256/ES384/ES512):** ```bash -npx flarelette-jwt-keygen --kid=ed25519-2025-01 +npx flarelette-jwt-keygen --kid=ed25519-2025-01 # EdDSA (default) +npx flarelette-jwt-keygen --alg=ES512 --kid=es512-2025-01 # ECDSA P-521 +npx flarelette-jwt-keygen --alg=EdDSA --dotenv # Output as .env assignments ``` ## Contributing diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index 9b0d9c0..2824816 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -17,10 +17,9 @@ The TypeScript package depends on the following NPM packages: @flarelette/jwt-kit-env@1.8.1 │ C:\Users\chris\git\flarelette-jwt-kit │ -└─┬ @chrislyons-dev/flarelette-jwt@1.12.0 -> .\packages\flarelette-jwt-ts - │ Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection +└─┬ @chrislyons-dev/flarelette-jwt@1.14.0 -> .\packages\flarelette-jwt-ts + │ └── jose@6.1.3 - JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes ``` --- @@ -77,4 +76,4 @@ This script: --- -**Last generated**: 2025-12-09 +**Last generated**: 2026-03-05 diff --git a/docs/architecture/.pages b/docs/architecture/.pages new file mode 100644 index 0000000..a618bcc --- /dev/null +++ b/docs/architecture/.pages @@ -0,0 +1,4 @@ +nav: + - README.md + - exclude: + - "*.md" \ No newline at end of file diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 6400b1a..454928d 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -1,7 +1,7 @@ -# 🏗️ flarelette-jwt-kit +# flarelette-jwt-kit **Architecture Documentation** -Generated 2025-12-08 19:38:11 +Generated 2026-03-05 17:59:12 ## Overview @@ -13,7 +13,7 @@ JWT authentication and authorization library The system context diagram shows how flarelette-jwt-kit fits into its environment, including external systems and users. -![System Context Diagram](./diagrams/structurizr-SystemContext.png) +System Context Diagram --- @@ -21,32 +21,12 @@ The system context diagram shows how flarelette-jwt-kit fits into its environmen The container diagram shows the high-level technology choices and how containers communicate. -![Container Diagram](./diagrams/structurizr-Containers.png) - - - - - - - - - - - - - - - - - - - - - - - - -
ContainerTypeDescriptionDetails
@chrislyons-dev/flarelette-jwtServiceEnvironment-driven JWT authentication for Cloudflare Workers with secret-name indirectionView →
flarelette-jwtServiceEnvironment-driven JWT authentication for Cloudflare Workers Python with secret-name indirectionView →
+Container Diagram + +| Container | Type | Description | Details | +| --- | --- | --- | --- | +| **@chrislyons-dev/flarelette-jwt** | `Service` | TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers | [View](./chrislyons_dev_flarelette_jwt.md) | +| **flarelette-jwt** | `Service` | Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers | [View](./flarelette_jwt.md) | --- @@ -54,3 +34,4 @@ The container diagram shows the high-level technology choices and how containers
Generated with Archlette Architecture-as-Code toolkit
+ diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt.md b/docs/architecture/chrislyons_dev_flarelette_jwt.md index 4602856..d66502a 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt.md @@ -6,33 +6,17 @@ ## Container Context -![Container Diagram](./diagrams/structurizr-Containers.png) +Container Diagram --- ## Container Information - - - - - - - - - - - - - - - - - - - -
Name@chrislyons-dev/flarelette-jwt
TypeService
DescriptionEnvironment-driven JWT authentication for Cloudflare Workers with secret-name indirection
TagsAuto-generated
- +| Field | Value | +| --- | --- | +| **Name** | @chrislyons-dev/flarelette-jwt | +| **Type** | `Service` | +| **Description** | TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers || **Tags** | `Auto-generated` | --- ## Components @@ -40,105 +24,20 @@ ### Component View -![Component Diagram](./diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png) +Component Diagram ### Component Details - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ComponentTypeDescriptionCode
coremoduleCLI utility for generating JWT secrets. - -This script provides options to generate secrets in various formats, including JSON and dotenv. -It is designed to be executed as a standalone Node.js script. | Configuration utilities for JWT operations. - -This module provides functions to read environment variables and derive JWT-related configurations. -It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. | JWT signing utilities. - -This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms. -It supports custom claims and configuration overrides.View →
explicitmoduleExplicit configuration API for JWT operations. - -This module provides functions that accept explicit configuration objects -instead of relying on environment variables or global state. Use this API -when you need full control over configuration, especially in development -environments or when working with multiple JWT configurations.View →
utilmoduleHigh-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys. - -This script generates EdDSA key pairs and exports them in JWK format. -It is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. - -This module provides functions to generate secure secrets and validate base64url-encoded secrets. -It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. - -This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. -It is designed to support core JWT functionalities.View →
mainmoduleEntry point for the flarelette-jwt library. - -This module re-exports core functionalities, including signing, verification, utilities, and type definitions. -It serves as the main interface for library consumers.View →
jwksmoduleJSON Web Key Set (JWKS) utilities. - -This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid). -It supports integration with external JWKS services.View →
typesmoduleType definitions for JWT operations. - -This module defines types for JWT headers, payloads, profiles, and related structures. -It ensures type safety and consistency across the library.View →
verifymoduleJWT verification utilities. - -This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms. -It supports integration with JWKS services and thumbprint pinning.View →
adaptersmoduleComponent inferred from directory: adaptersView →
+| Component | Type | Description | Code | +| --- | --- | --- | --- | +| **core** | `module` | CLI utility for generating JWT secrets.

This script provides options to generate secrets in various formats, including JSON and dotenv.
It is designed to be executed as a standalone Node.js script. \| Configuration utilities for JWT operations.

This module provides functions to read environment variables and derive JWT-related configurations.
It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. \| JWT signing utilities.

This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms.
It supports custom claims and configuration overrides. | [View](./chrislyons_dev_flarelette_jwt__core.md) | +| **explicit** | `module` | Explicit configuration API for JWT operations.

This module provides functions that accept explicit configuration objects
instead of relying on environment variables or global state. Use this API
when you need full control over configuration, especially in development
environments or when working with multiple JWT configurations. | [View](./chrislyons_dev_flarelette_jwt__explicit.md) | +| **util** | `module` | High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens \| Key generation utility for EdDSA and ECDSA keys.

Generates asymmetric key pairs and exports them in JWK format.
Designed to be executed as a standalone Node.js script. \| Secret generation and validation utilities.

This module provides functions to generate secure secrets and validate base64url-encoded secrets.
It ensures compatibility with JWT signing requirements. \| Utility functions for JWT operations.

This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.
It is designed to support core JWT functionalities. | [View](./chrislyons_dev_flarelette_jwt__util.md) | +| **main** | `module` | Entry point for the flarelette-jwt library.

This module re-exports core functionalities, including signing, verification, utilities, and type definitions.
It serves as the main interface for library consumers. | [View](./chrislyons_dev_flarelette_jwt__main.md) | +| **jwks** | `module` | JSON Web Key Set (JWKS) utilities.

This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid).
It supports integration with external JWKS services. | [View](./chrislyons_dev_flarelette_jwt__jwks.md) | +| **types** | `module` | Type definitions for JWT operations.

This module defines types for JWT headers, payloads, profiles, and related structures.
It ensures type safety and consistency across the library. | [View](./chrislyons_dev_flarelette_jwt__types.md) | +| **verify** | `module` | JWT verification utilities.

This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms.
It supports integration with JWKS services and thumbprint pinning. | [View](./chrislyons_dev_flarelette_jwt__verify.md) | +| **adapters** | `module` | Component inferred from directory: adapters | [View](./chrislyons_dev_flarelette_jwt__adapters.md) | --- @@ -146,3 +45,4 @@ It supports integration with JWKS services and thumbprint pinning.
← Back to System Overview | Generated with Archlette
+ diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__adapters.md b/docs/architecture/chrislyons_dev_flarelette_jwt__adapters.md index 38a08f2..9e45972 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__adapters.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__adapters.md @@ -6,27 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentadapters
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionComponent inferred from directory: adapters
- +| Field | Value | +| --- | --- | +| **Component** | adapters | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | Component inferred from directory: adapters | --- ## Code Structure @@ -48,26 +33,11 @@ Store both environment variables and service bindings globally - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsvoid
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:13
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `void` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:13` | **Parameters:** @@ -78,26 +48,11 @@ Store both environment variables and service bindings globally Get service binding by name from global storage - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilityprivate
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").Fetcher
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:35
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `private` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").Fetcher` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:35` | **Parameters:** @@ -109,26 +64,11 @@ Get service binding by name from global storage Returns a namespaced kit whose calls use the provided env bag. Automatically injects JWKS service binding if configured. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returns{ sign: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/sign").sign; verify: (token: string, opts?: Partial<{ iss: string; aud: string; leeway: number; }>) => Promise; createToken: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").createToken; checkAuth: (token: string, opts?: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").AuthzOpts) => Promise; policy: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").policy; parse: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util").parse; isExpiringSoon: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util").isExpiringSoon; }
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:45
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `{ sign: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/sign").sign; verify: (token: string, opts?: Partial<{ iss: string; aud: string; leeway: number; }>) => Promise; createToken: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").createToken; checkAuth: (token: string, opts?: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").AuthzOpts) => Promise; policy: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").policy; parse: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util").parse; isExpiringSoon: typeof import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util").isExpiringSoon; }` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/adapters/hono.ts:45` | **Parameters:** @@ -143,3 +83,4 @@ Automatically injects JWKS service binding if configured.
← Back to Container | ← Back to System | Generated with Archlette
+ diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__core.md b/docs/architecture/chrislyons_dev_flarelette_jwt__core.md index 3ab0818..22cc764 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__core.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__core.md @@ -6,36 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentcore
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionCLI utility for generating JWT secrets. - -This script provides options to generate secrets in various formats, including JSON and dotenv. -It is designed to be executed as a standalone Node.js script. | Configuration utilities for JWT operations. - -This module provides functions to read environment variables and derive JWT-related configurations. -It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. | JWT signing utilities. - -This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms. -It supports custom claims and configuration overrides.
- +| Field | Value | +| --- | --- | +| **Component** | core | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | CLI utility for generating JWT secrets.

This script provides options to generate secrets in various formats, including JSON and dotenv.
It is designed to be executed as a standalone Node.js script. \| Configuration utilities for JWT operations.

This module provides functions to read environment variables and derive JWT-related configurations.
It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. \| JWT signing utilities.

This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms.
It supports custom claims and configuration overrides. | --- ## Code Structure @@ -56,26 +32,11 @@ It supports custom claims and configuration overrides. ##### `envRead()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilityprivate
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:13
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `private` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:13` | **Parameters:** @@ -85,26 +46,11 @@ It supports custom claims and configuration overrides. ##### `envMode()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").AlgType
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:23
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").AlgType` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:23` | **Parameters:** @@ -116,26 +62,11 @@ It supports custom claims and configuration overrides. Get common JWT configuration from environment Returns partial JwtProfile-compatible configuration - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returns{ iss: string; aud: string; leeway: number; ttlSeconds: number; }
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:65
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `{ iss: string; aud: string; leeway: number; ttlSeconds: number; }` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:66` | @@ -145,26 +76,11 @@ Returns partial JwtProfile-compatible configuration Get JWT profile from environment Returns complete JwtProfile with detected algorithm - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
ReturnsPartial & { ttlSeconds: number; }
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:78
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `Partial & { ttlSeconds: number; }` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:79` | **Parameters:** @@ -174,26 +90,11 @@ Returns complete JwtProfile with detected algorithm ##### `getHSSecret()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
ReturnsUint8Array
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:93
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `Uint8Array` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:94` | @@ -201,26 +102,11 @@ Returns complete JwtProfile with detected algorithm ##### `getPrivateJwkString()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:126
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:127` | @@ -228,26 +114,11 @@ Returns complete JwtProfile with detected algorithm ##### `getPublicJwkString()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:132
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:133` | @@ -255,26 +126,11 @@ Returns complete JwtProfile with detected algorithm ##### `getJwksServiceName()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:138
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:139` | @@ -282,26 +138,11 @@ Returns complete JwtProfile with detected algorithm ##### `getJwksUrl()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:144
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:145` | @@ -309,26 +150,11 @@ Returns complete JwtProfile with detected algorithm ##### `getJwksCacheTtl()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsnumber
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:148
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `number` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts:151` | @@ -337,30 +163,11 @@ Returns complete JwtProfile with detected algorithm Sign a JWT token with HS512 or EdDSA algorithm - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/sign.ts:22
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/sign.ts:22` | **Parameters:** @@ -375,3 +182,4 @@ Sign a JWT token with HS512 or EdDSA algorithm + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__explicit.md b/docs/architecture/chrislyons_dev_flarelette_jwt__explicit.md index 4d5ea5c..f730fd9 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__explicit.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__explicit.md @@ -6,32 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentexplicit
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionExplicit configuration API for JWT operations. - -This module provides functions that accept explicit configuration objects -instead of relying on environment variables or global state. Use this API -when you need full control over configuration, especially in development -environments or when working with multiple JWT configurations.
- +| Field | Value | +| --- | --- | +| **Component** | explicit | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | Explicit configuration API for JWT operations.

This module provides functions that accept explicit configuration objects
instead of relying on environment variables or global state. Use this API
when you need full control over configuration, especially in development
environments or when working with multiple JWT configurations. | --- ## Code Structure @@ -43,7 +23,7 @@ environments or when working with multiple JWT configurations. ### Code Elements
-9 code element(s) +11 code element(s) @@ -53,30 +33,11 @@ environments or when working with multiple JWT configurations. Sign a JWT token with explicit configuration - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:122
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:150` | **Parameters:** @@ -91,30 +52,11 @@ Sign a JWT token with explicit configuration Verify a JWT token with explicit configuration - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Payload if valid, null if invalid
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:181
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Payload if valid, null if invalid || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:224` | **Parameters:** @@ -131,30 +73,11 @@ Create a signed JWT token with explicit configuration Higher-level wrapper around signWithConfig for convenience. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:246
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:293` | **Parameters:** @@ -167,30 +90,11 @@ Create a delegated JWT token with explicit configuration Implements RFC 8693 actor claim pattern for service-to-service delegation. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string with delegation claim
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:283
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string with delegation claim || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:330` | **Parameters:** @@ -205,30 +109,11 @@ Implements RFC 8693 actor claim pattern for service-to-service delegation. Verify and authorize a JWT token with explicit configuration - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — AuthUser if valid and authorized, null otherwise
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:369
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - AuthUser if valid and authorized, null otherwise || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:416` | **Parameters:** @@ -243,26 +128,11 @@ Verify and authorize a JWT token with explicit configuration Helper function to create HS512 config from base64url-encoded secret - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").HS512Config — HS512 configuration
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:423
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").HS512Config` - HS512 configuration || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:470` | **Parameters:** @@ -273,26 +143,11 @@ Helper function to create HS512 config from base64url-encoded secret Helper function to create EdDSA sign config from JWK - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").EdDSASignConfig — EdDSA sign configuration
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:452
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").EdDSASignConfig` - EdDSA sign configuration || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:499` | **Parameters:** @@ -303,66 +158,59 @@ Helper function to create EdDSA sign config from JWK Helper function to create EdDSA verify config from JWK - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").EdDSAVerifyConfig — EdDSA verify configuration
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:474
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").EdDSAVerifyConfig` - EdDSA verify configuration || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:521` | **Parameters:** - `publicJwk`: any — - Public JWK object or JSON string- `baseConfig`: Omit & Partial> — - Base JWT configuration --- -##### `createJWKSUrlVerifyConfig()` +##### `createES512SignConfig()` + +Helper function to create ES512 sign config from a P-521 EC private JWK -Helper function to create HTTP JWKS URL verification config - -Enables testing without environment variables by providing explicit configuration - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").JWKSUrlVerifyConfig — JWKS URL verification configuration
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:511
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").ES512SignConfig` - ES512 sign configuration || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:542` | **Parameters:** -- `jwksUrl`: string — - HTTP(S) URL to JWKS endpoint- `baseConfig`: Omit & Partial> — - Base JWT configuration- `cacheTtl`: number — - Optional cache TTL in seconds (default: 300) -**Examples:** -```typescript +- `privateJwk`: any — - Private JWK object or JSON string (EC P-521 key)- `baseConfig`: Omit & Partial> — - Base JWT configuration- `kid`: string — - Optional key ID -``` +--- +##### `createES512VerifyConfig()` + +Helper function to create ES512 verify config from a P-521 EC public JWK + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").ES512VerifyConfig` - ES512 verify configuration || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:564` | + +**Parameters:** + +- `publicJwk`: any — - Public JWK object or JSON string (EC P-521 key)- `baseConfig`: Omit & Partial> — - Base JWT configuration + +--- +##### `createJWKSUrlVerifyConfig()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit").JWKSUrlVerifyConfig` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts:614` | + +**Parameters:** + +- `jwksUrl`: string- `algOrBaseConfig`: "EdDSA" | (Omit & Partial>) | "ES256" | "ES384" | "ES512" | "RS256" | "RS384" | "RS512"- `baseConfigOrCacheTtl`: number | (Omit & Partial>)- `maybeCacheTtl`: number --- @@ -373,3 +221,4 @@ Enables testing without environment variables by providing explicit configuratio + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__jwks.md b/docs/architecture/chrislyons_dev_flarelette_jwt__jwks.md index de680ad..e6c3bcb 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__jwks.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__jwks.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentjwks
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionJSON Web Key Set (JWKS) utilities. - -This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid). -It supports integration with external JWKS services.
- +| Field | Value | +| --- | --- | +| **Component** | jwks | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | JSON Web Key Set (JWKS) utilities.

This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid).
It supports integration with external JWKS services. | --- ## Code Structure @@ -51,26 +33,11 @@ It supports integration with external JWKS services. Clear the JWKS cache (for testing purposes) - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsvoid
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:49
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `void` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:49` | @@ -79,26 +46,11 @@ Clear the JWKS cache (for testing purposes) Clear the HTTP JWKS cache (for testing purposes) - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsvoid
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:57
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `void` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:57` | @@ -108,30 +60,11 @@ Clear the HTTP JWKS cache (for testing purposes) Fetch JWKS from a service binding Implements 5-minute caching to reduce load on JWKS service - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:65
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:65` | **Parameters:** @@ -146,26 +79,11 @@ Requirements: - Must be valid URL format - Must use HTTPS (except localhost/127.0.0.1/[::1] for testing) - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilityprivate
ReturnsURL — Parsed URL object
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:103
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `private` | +| **Returns** | `URL` - Parsed URL object || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:103` | **Parameters:** @@ -179,30 +97,11 @@ Fetch JWKS from HTTP URL with caching Implements configurable TTL caching (default 5 minutes) Security: HTTPS-only (except localhost), 5-second timeout, 100KB size limit - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Array of JWK objects
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:138
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Array of JWK objects || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:138` | **Parameters:** @@ -216,30 +115,11 @@ Find and import a specific key from JWKS by kid Supports both EdDSA (Ed25519) and RSA (RS256/RS384/RS512) keys Algorithm is auto-detected from key type (kty) and curve (crv) - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise | CryptoKey> — CryptoKey or Uint8Array suitable for jose verification
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:209
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise \| CryptoKey>` - CryptoKey or Uint8Array suitable for jose verification || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:211` | **Parameters:** @@ -250,26 +130,11 @@ Algorithm is auto-detected from key type (kty) and curve (crv) Get allowed thumbprints for key pinning (optional security measure) - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
ReturnsSet
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:242
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `Set` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts:244` | @@ -282,3 +147,4 @@ Get allowed thumbprints for key pinning (optional security measure) + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__main.md b/docs/architecture/chrislyons_dev_flarelette_jwt__main.md index e6d6673..130e2ed 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__main.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__main.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentmain
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionEntry point for the flarelette-jwt library. - -This module re-exports core functionalities, including signing, verification, utilities, and type definitions. -It serves as the main interface for library consumers.
- +| Field | Value | +| --- | --- | +| **Component** | main | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | Entry point for the flarelette-jwt library.

This module re-exports core functionalities, including signing, verification, utilities, and type definitions.
It serves as the main interface for library consumers. | --- ## Code Structure @@ -44,3 +26,4 @@ It serves as the main interface for library consumers. + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__types.md b/docs/architecture/chrislyons_dev_flarelette_jwt__types.md index 5d4a303..5f8d720 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__types.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__types.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componenttypes
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionType definitions for JWT operations. - -This module defines types for JWT headers, payloads, profiles, and related structures. -It ensures type safety and consistency across the library.
- +| Field | Value | +| --- | --- | +| **Component** | types | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | Type definitions for JWT operations.

This module defines types for JWT headers, payloads, profiles, and related structures.
It ensures type safety and consistency across the library. | --- ## Code Structure @@ -44,3 +26,4 @@ It ensures type safety and consistency across the library. + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__util.md b/docs/architecture/chrislyons_dev_flarelette_jwt__util.md index 013cbb7..e816746 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__util.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__util.md @@ -6,36 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentutil
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionHigh-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys. - -This script generates EdDSA key pairs and exports them in JWK format. -It is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. - -This module provides functions to generate secure secrets and validate base64url-encoded secrets. -It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. - -This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. -It is designed to support core JWT functionalities.
- +| Field | Value | +| --- | --- | +| **Component** | util | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens \| Key generation utility for EdDSA and ECDSA keys.

Generates asymmetric key pairs and exports them in JWK format.
Designed to be executed as a standalone Node.js script. \| Secret generation and validation utilities.

This module provides functions to generate secure secrets and validate base64url-encoded secrets.
It ensures compatibility with JWT signing requirements. \| Utility functions for JWT operations.

This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.
It is designed to support core JWT functionalities. | --- ## Code Structure @@ -47,7 +23,7 @@ It is designed to support core JWT functionalities. ### Code Elements
-10 code element(s) +13 code element(s) @@ -57,30 +33,11 @@ It is designed to support core JWT functionalities. Create a signed JWT token with optional claims - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:18
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:19` | **Parameters:** @@ -99,30 +56,11 @@ acts on behalf of the original end user. This implements zero-trust delegation: Pattern: "I'm doing work on behalf of " - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Signed JWT token string with delegation claim
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:61
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string with delegation claim || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:62` | **Parameters:** @@ -132,35 +70,56 @@ Pattern: "I'm doing work on behalf of " ``` +--- +##### `signWithRequestBinding()` + +Sign a JWT token bound to a specific HTTP request. + +Adds a `req` claim containing base64url(SHA-256(canonical request)) to prevent +replay of a captured token against a different endpoint within the TTL window. + +Canonical form: METHOD + "\n" + pathname + search + "\n" + body bytes + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Signed JWT token string with req claim || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:112` | + +**Parameters:** + +- `payload`: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").JwtPayload — - Claims to include in the token- `request`: Request — - The HTTP request this token is minted for- `opts`: Partial<{ iss: string; aud: string | string[]; ttlSeconds: number; }> — - Optional overrides for iss, aud, ttlSeconds + +--- +##### `verifyWithRequestBinding()` + +Verify a JWT token and validate its request binding. + +Re-computes the request hash and compares it with the `req` claim. +Returns null on any mismatch (fail-silent, same as verify()). +The `req` claim is stripped from the returned payload — it's an implementation +detail that has already been validated. + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Payload (without req claim) if valid and request matches, null otherwise || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:134` | + +**Parameters:** + +- `token`: string — - JWT token string to verify- `request`: Request — - The HTTP request to validate against- `opts`: Partial<{ iss: string; aud: string | string[]; leeway: number; jwksService: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").Fetcher; }> — - Optional overrides for iss, aud, leeway + --- ##### `checkAuth()` Verify and authorize a JWT token with policy enforcement - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — AuthUser if valid and authorized, null otherwise
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:142
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - AuthUser if valid and authorized, null otherwise || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:199` | **Parameters:** @@ -171,26 +130,11 @@ Verify and authorize a JWT token with policy enforcement Fluent builder for creating authorization policies - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returns{ base(b: Partial<{ iss: string; aud: string | string[]; leeway: number; }>): any; needAll(...perms: string[]): any; needAny(...perms: string[]): any; rolesAll(...roles: string[]): any; rolesAny(...roles: string[]): any; where(fn: (payload: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").JwtPayload) => boolean): any; build(): import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").AuthzOpts; } — Policy builder with chainable methods
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:177
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `{ base(b: Partial<{ iss: string; aud: string \| string[]; leeway: number; }>): any; needAll(...perms: string[]): any; needAny(...perms: string[]): any; rolesAll(...roles: string[]): any; rolesAny(...roles: string[]): any; where(fn: (payload: import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").JwtPayload) => boolean): any; build(): import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high").AuthzOpts; }` - Policy builder with chainable methods || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts:234` | @@ -198,30 +142,11 @@ Fluent builder for creating authorization policies ##### `main()` - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilityprivate
AsyncYes
ReturnsPromise
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/keygen.ts:15
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `private` | +| **Async** | Yes || **Returns** | `Promise` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/keygen.ts:16` | @@ -229,26 +154,11 @@ Fluent builder for creating authorization policies ##### `generateSecret()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/secret.ts:13
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/secret.ts:13` | **Parameters:** @@ -258,26 +168,11 @@ Fluent builder for creating authorization policies ##### `isValidBase64UrlSecret()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsboolean
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/secret.ts:25
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `boolean` || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/secret.ts:25` | **Parameters:** @@ -288,26 +183,11 @@ Fluent builder for creating authorization policies Parse a JWT token into header and payload without verification - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsimport("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").ParsedJwt — Parsed header and payload
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:19
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `import("C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types").ParsedJwt` - Parsed header and payload || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:19` | **Parameters:** @@ -318,26 +198,11 @@ Parse a JWT token into header and payload without verification Check if JWT payload will expire within specified seconds - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsboolean — True if token expires within the threshold
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:35
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `boolean` - True if token expires within the threshold || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:35` | **Parameters:** @@ -348,31 +213,36 @@ Check if JWT payload will expire within specified seconds Map OAuth scopes to permission strings - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
Returnsstring[] — List of permission strings (currently identity mapping)
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:47
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Returns** | `string[]` - List of permission strings (currently identity mapping) || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:47` | **Parameters:** - `scopes`: string[] — - List of OAuth scope strings +--- +##### `computeRequestHash()` + +Compute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request. + +Canonical form: UTF-8(METHOD + "\n" + pathname + search + "\n") || body_bytes +- Method is uppercased +- Binds to path and query string only (not host/scheme — internal Workers use different hostnames) +- Body is consumed from a clone to preserve the original stream + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - base64url-encoded SHA-256 hash of the canonical request representation || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts:62` | + +**Parameters:** + +- `request`: Request — - Fetch API Request object + ---
@@ -382,3 +252,4 @@ Map OAuth scopes to permission strings + diff --git a/docs/architecture/chrislyons_dev_flarelette_jwt__verify.md b/docs/architecture/chrislyons_dev_flarelette_jwt__verify.md index fa7c4ca..41bfee7 100644 --- a/docs/architecture/chrislyons_dev_flarelette_jwt__verify.md +++ b/docs/architecture/chrislyons_dev_flarelette_jwt__verify.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentverify
Container@chrislyons-dev/flarelette-jwt
Typemodule
DescriptionJWT verification utilities. - -This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms. -It supports integration with JWKS services and thumbprint pinning.
- +| Field | Value | +| --- | --- | +| **Component** | verify | +| **Container** | @chrislyons-dev/flarelette-jwt | +| **Type** | `module` | +| **Description** | JWT verification utilities.

This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms.
It supports integration with JWKS services and thumbprint pinning. | --- ## Code Structure @@ -57,30 +39,11 @@ Implements key resolution strategy pattern: - Strategy 3: Service binding JWKS - Strategy 4: HTTP JWKS URL - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilityprivate
AsyncYes
ReturnsPromise<{ key: Uint8Array | CryptoKey; algorithms: string[]; }> — Key and allowed algorithms
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/verify.ts:47
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `private` | +| **Async** | Yes || **Returns** | `Promise<{ key: Uint8Array \| CryptoKey; algorithms: string[]; }>` - Key and allowed algorithms || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/verify.ts:47` | **Parameters:** @@ -93,30 +56,11 @@ Verify a JWT token with HS512, EdDSA, or RSA algorithms Supports multiple key resolution strategies with automatic algorithm detection - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibilitypublic
AsyncYes
ReturnsPromise — Decoded payload if valid, null otherwise
LocationC:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/verify.ts:132
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `public` | +| **Async** | Yes || **Returns** | `Promise` - Decoded payload if valid, null otherwise || **Location** | `C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/verify.ts:131` | **Parameters:** @@ -131,3 +75,4 @@ Supports multiple key resolution strategies with automatic algorithm detection + diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.mmd index 5c35ac0..13cbd5d 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.mmd @@ -1,18 +1,18 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 50("
adapters.bindEnv
[Component: function]
Store both environment
variables and service
bindings globally
") - style 50 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 51("
adapters.getServiceBinding
[Component: function]
Get service binding by name
from global storage
") - style 51 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 52("
adapters.makeKit
[Component: function]
Returns a namespaced kit
whose calls use the provided
env bag. Automatically
injects JWKS service binding
if configured.
") - style 52 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 55("
adapters.bindEnv
[Component: function]
Store both environment
variables and service
bindings globally
") + style 55 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 56("
adapters.getServiceBinding
[Component: function]
Get service binding by name
from global storage
") + style 56 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 57("
adapters.makeKit
[Component: function]
Returns a namespaced kit
whose calls use the provided
env bag. Automatically
injects JWKS service binding
if configured.
") + style 57 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.mmd index 8604b32..82a2c2e 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.mmd @@ -1,34 +1,34 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 11("
core.envRead
[Component: function]
") - style 11 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 11 fill:#d4e8fc,stroke:#94a2b0,color:#000000 12("
core.envMode
[Component: function]
") - style 12 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 12 fill:#d4e8fc,stroke:#94a2b0,color:#000000 13("
core.getCommon
[Component: function]
Get common JWT configuration
from environment Returns
partial JwtProfile-compatible
configuration
") - style 13 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 13 fill:#d4e8fc,stroke:#94a2b0,color:#000000 14("
core.getProfile
[Component: function]
Get JWT profile from
environment Returns complete
JwtProfile with detected
algorithm
") - style 14 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 14 fill:#d4e8fc,stroke:#94a2b0,color:#000000 15("
core.getHSSecret
[Component: function]
") - style 15 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 15 fill:#d4e8fc,stroke:#94a2b0,color:#000000 16("
core.getPrivateJwkString
[Component: function]
") - style 16 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 16 fill:#d4e8fc,stroke:#94a2b0,color:#000000 17("
core.getPublicJwkString
[Component: function]
") - style 17 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 17 fill:#d4e8fc,stroke:#94a2b0,color:#000000 18("
core.getJwksServiceName
[Component: function]
") - style 18 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 18 fill:#d4e8fc,stroke:#94a2b0,color:#000000 19("
core.getJwksUrl
[Component: function]
") - style 19 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 19 fill:#d4e8fc,stroke:#94a2b0,color:#000000 20("
core.getJwksCacheTtl
[Component: function]
") - style 20 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 44("
core.sign
[Component: function]
Sign a JWT token with HS512
or EdDSA algorithm
") - style 44 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 20 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 48("
core.sign
[Component: function]
Sign a JWT token with HS512
or EdDSA algorithm
") + style 48 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.mmd index ee6cd86..359858f 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.mmd @@ -1,30 +1,34 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 21("
explicit.signWithConfig
[Component: function]
Sign a JWT token with
explicit configuration
") - style 21 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 21 fill:#d4e8fc,stroke:#94a2b0,color:#000000 22("
explicit.verifyWithConfig
[Component: function]
Verify a JWT token with
explicit configuration
") - style 22 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 22 fill:#d4e8fc,stroke:#94a2b0,color:#000000 23("
explicit.createTokenWithConfig
[Component: function]
Create a signed JWT token
with explicit configuration
Higher-level wrapper around
signWithConfig for
convenience.
") - style 23 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 23 fill:#d4e8fc,stroke:#94a2b0,color:#000000 24("
explicit.createDelegatedTokenWithConfig
[Component: function]
Create a delegated JWT token
with explicit configuration
Implements RFC 8693 actor
claim pattern for
service-to-service
delegation.
") - style 24 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 24 fill:#d4e8fc,stroke:#94a2b0,color:#000000 25("
explicit.checkAuthWithConfig
[Component: function]
Verify and authorize a JWT
token with explicit
configuration
") - style 25 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 25 fill:#d4e8fc,stroke:#94a2b0,color:#000000 26("
explicit.createHS512Config
[Component: function]
Helper function to create
HS512 config from
base64url-encoded secret
") - style 26 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 26 fill:#d4e8fc,stroke:#94a2b0,color:#000000 27("
explicit.createEdDSASignConfig
[Component: function]
Helper function to create
EdDSA sign config from JWK
") - style 27 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 27 fill:#d4e8fc,stroke:#94a2b0,color:#000000 28("
explicit.createEdDSAVerifyConfig
[Component: function]
Helper function to create
EdDSA verify config from JWK
") - style 28 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 29("
explicit.createJWKSUrlVerifyConfig
[Component: function]
Helper function to create
HTTP JWKS URL verification
config Enables testing
without environment variables
by providing explicit
configuration
") - style 29 fill:#85bbf0,stroke:#5d82a8,color:#000000 + style 28 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 29("
explicit.createES512SignConfig
[Component: function]
Helper function to create
ES512 sign config from a
P-521 EC private JWK
") + style 29 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 30("
explicit.createES512VerifyConfig
[Component: function]
Helper function to create
ES512 verify config from a
P-521 EC public JWK
") + style 30 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 31("
explicit.createJWKSUrlVerifyConfig
[Component: function]
") + style 31 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.mmd index 850c013..eb8720f 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.mmd @@ -1,26 +1,26 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 34("
jwks.clearJwksCache
[Component: function]
Clear the JWKS cache (for
testing purposes)
") - style 34 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 35("
jwks.clearHttpJwksCache
[Component: function]
Clear the HTTP JWKS cache
(for testing purposes)
") - style 35 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 36("
jwks.fetchJwksFromService
[Component: function]
Fetch JWKS from a service
binding Implements 5-minute
caching to reduce load on
JWKS service
") - style 36 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 37("
jwks.validateJwksUrl
[Component: function]
Validate JWKS URL for
security requirements
Requirements: - Must be valid
URL format - Must use HTTPS
(except
localhost/127.0.0.1/[::1] for
testing)
") - style 37 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 38("
jwks.fetchJwksFromUrl
[Component: function]
Fetch JWKS from HTTP URL with
caching Implements
configurable TTL caching
(default 5 minutes) Security:
HTTPS-only (except
localhost), 5-second timeout,
100KB size limit
") - style 38 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 39("
jwks.getKeyFromJwks
[Component: function]
Find and import a specific
key from JWKS by kid Supports
both EdDSA (Ed25519) and RSA
(RS256/RS384/RS512) keys
Algorithm is auto-detected
from key type (kty) and curve
(crv)
") - style 39 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 40("
jwks.allowedThumbprints
[Component: function]
Get allowed thumbprints for
key pinning (optional
security measure)
") - style 40 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 38("
jwks.clearJwksCache
[Component: function]
Clear the JWKS cache (for
testing purposes)
") + style 38 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 39("
jwks.clearHttpJwksCache
[Component: function]
Clear the HTTP JWKS cache
(for testing purposes)
") + style 39 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 40("
jwks.fetchJwksFromService
[Component: function]
Fetch JWKS from a service
binding Implements 5-minute
caching to reduce load on
JWKS service
") + style 40 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 41("
jwks.validateJwksUrl
[Component: function]
Validate JWKS URL for
security requirements
Requirements: - Must be valid
URL format - Must use HTTPS
(except
localhost/127.0.0.1/[::1] for
testing)
") + style 41 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 42("
jwks.fetchJwksFromUrl
[Component: function]
Fetch JWKS from HTTP URL with
caching Implements
configurable TTL caching
(default 5 minutes) Security:
HTTPS-only (except
localhost), 5-second timeout,
100KB size limit
") + style 42 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 43("
jwks.getKeyFromJwks
[Component: function]
Find and import a specific
key from JWKS by kid Supports
both EdDSA (Ed25519) and RSA
(RS256/RS384/RS512) keys
Algorithm is auto-detected
from key type (kty) and curve
(crv)
") + style 43 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 44("
jwks.allowedThumbprints
[Component: function]
Get allowed thumbprints for
key pinning (optional
security measure)
") + style 44 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.mmd index 7145f66..1374864 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.mmd @@ -1,32 +1,38 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 30("
util.createToken
[Component: function]
Create a signed JWT token
with optional claims
") - style 30 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 31("
util.createDelegatedToken
[Component: function]
Create a delegated JWT token
following RFC 8693 actor
claim pattern Mints a new
short-lived token for use
within service boundaries
where a service acts on
behalf of the original end
user. This implements
zero-trust delegation: -
Preserves original user
identity (sub) and
permissions - Identifies the
acting service via 'act'
claim - Prevents permission
escalation by copying
original permissions Pattern:
"I'm doing
work on behalf of user>"
") - style 31 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 32("
util.checkAuth
[Component: function]
Verify and authorize a JWT
token with policy enforcement
") - style 32 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 33("
util.policy
[Component: function]
Fluent builder for creating
authorization policies
") - style 33 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 41("
util.main
[Component: function]
") - style 41 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 42("
util.generateSecret
[Component: function]
") - style 42 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 43("
util.isValidBase64UrlSecret
[Component: function]
") - style 43 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 45("
util.parse
[Component: function]
Parse a JWT token into header
and payload without
verification
") - style 45 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 46("
util.isExpiringSoon
[Component: function]
Check if JWT payload will
expire within specified
seconds
") - style 46 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 47("
util.mapScopesToPermissions
[Component: function]
Map OAuth scopes to
permission strings
") - style 47 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 32("
util.createToken
[Component: function]
Create a signed JWT token
with optional claims
") + style 32 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 33("
util.createDelegatedToken
[Component: function]
Create a delegated JWT token
following RFC 8693 actor
claim pattern Mints a new
short-lived token for use
within service boundaries
where a service acts on
behalf of the original end
user. This implements
zero-trust delegation: -
Preserves original user
identity (sub) and
permissions - Identifies the
acting service via 'act'
claim - Prevents permission
escalation by copying
original permissions Pattern:
"I'm doing
work on behalf of user>"
") + style 33 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 34("
util.signWithRequestBinding
[Component: function]
Sign a JWT token bound to a
specific HTTP request. Adds a
`req` claim containing
base64url(SHA-256(canonical
request)) to prevent replay
of a captured token against a
different endpoint within the
TTL window. Canonical form:
METHOD + "\ " + pathname +
search + "\ " + body bytes
") + style 34 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 35("
util.verifyWithRequestBinding
[Component: function]
Verify a JWT token and
validate its request binding.
Re-computes the request hash
and compares it with the
`req` claim. Returns null on
any mismatch (fail-silent,
same as verify()). The `req`
claim is stripped from the
returned payload — it's an
implementation detail that
has already been validated.
") + style 35 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 36("
util.checkAuth
[Component: function]
Verify and authorize a JWT
token with policy enforcement
") + style 36 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 37("
util.policy
[Component: function]
Fluent builder for creating
authorization policies
") + style 37 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 45("
util.main
[Component: function]
") + style 45 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 46("
util.generateSecret
[Component: function]
") + style 46 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 47("
util.isValidBase64UrlSecret
[Component: function]
") + style 47 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 49("
util.parse
[Component: function]
Parse a JWT token into header
and payload without
verification
") + style 49 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 50("
util.isExpiringSoon
[Component: function]
Check if JWT payload will
expire within specified
seconds
") + style 50 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 51("
util.mapScopesToPermissions
[Component: function]
Map OAuth scopes to
permission strings
") + style 51 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 52("
util.computeRequestHash
[Component: function]
Compute a deterministic
SHA-256 hash that binds a JWT
to a specific HTTP request.
Canonical form: UTF-8(METHOD
+ "\ " + pathname + search +
"\ ") || body_bytes - Method
is uppercased - Binds to path
and query string only (not
host/scheme — internal
Workers use different
hostnames) - Body is consumed
from a clone to preserve the
original stream
") + style 52 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.mmd index de12492..5150aae 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.mmd @@ -1,16 +1,16 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 48("
verify.resolveVerificationKey
[Component: function]
Resolve verification key from
configured sources Implements
key resolution strategy
pattern: - Strategy 1: HS512
shared secret - Strategy 2:
Inline public JWK - Strategy
3: Service binding JWKS -
Strategy 4: HTTP JWKS URL
") - style 48 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 49("
verify.verify
[Component: function]
Verify a JWT token with
HS512, EdDSA, or RSA
algorithms Supports multiple
key resolution strategies
with automatic algorithm
detection
") - style 49 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 53("
verify.resolveVerificationKey
[Component: function]
Resolve verification key from
configured sources Implements
key resolution strategy
pattern: - Strategy 1: HS512
shared secret - Strategy 2:
Inline public JWK - Strategy
3: Service binding JWKS -
Strategy 4: HTTP JWKS URL
") + style 53 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 54("
verify.verify
[Component: function]
Verify a JWT token with
HS512, EdDSA, or RSA
algorithms Supports multiple
key resolution strategies
with automatic algorithm
detection
") + style 54 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__adapters.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__adapters.mmd index 0ac0ab7..a48ddca 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__adapters.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__adapters.mmd @@ -1,14 +1,14 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 60 ["flarelette-jwt"] - style 60 fill:#ffffff,stroke:#2e6295,color:#2e6295 + subgraph 65 [" "] + style 65 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 65("
adapters.apply_env_bindings
[Component: function]
Copy a Cloudflare Worker
`env` mapping into os.environ
so the kit can read it.
") - style 65 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 70("
adapters.apply_env_bindings
[Component: function]
Copy a Cloudflare Worker
`env` mapping into os.environ
so the kit can read it.
") + style 70 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__explicit.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__explicit.mmd index 0db7663..886049e 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__explicit.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__explicit.mmd @@ -1,48 +1,74 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 60 ["flarelette-jwt"] - style 60 fill:#ffffff,stroke:#2e6295,color:#2e6295 + subgraph 65 [" "] + style 65 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 80("
explicit.BaseJwtConfig
[Component: class]
Base JWT configuration shared
by HS512 and EdDSA modes.
") - style 80 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 81("
explicit.HS512Config
[Component: class]
HS512 (HMAC-SHA512) symmetric
configuration.
") - style 81 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 82("
explicit.EdDSASignConfig
[Component: class]
EdDSA (Ed25519) asymmetric
configuration for signing.
") - style 82 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 83("
explicit.EdDSAVerifyConfig
[Component: class]
EdDSA (Ed25519) asymmetric
configuration for
verification.
") - style 83 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 84("
explicit.AuthzOptsWithConfig
[Component: class]
Authorization options for
check_auth_with_config.
") - style 84 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 85("
explicit.AuthUser
[Component: class]
Authenticated user
information.
") - style 85 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 86("
explicit._b64url
[Component: function]
Encode bytes to base64url
without padding.
") - style 86 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 87("
explicit._b64url_decode
[Component: function]
Decode base64url string (with
or without padding).
") - style 87 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 88("
explicit.sign_with_config
[Component: function]
Sign a JWT token with
explicit configuration.
") - style 88 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 89("
explicit.verify_with_config
[Component: function]
Verify a JWT token with
explicit configuration.
") - style 89 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 90("
explicit.create_token_with_config
[Component: function]
Create a signed JWT token
with explicit configuration.
") - style 90 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 91("
explicit.create_delegated_token_with_config
[Component: function]
Create a delegated JWT token
with explicit configuration.
") - style 91 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 92("
explicit.check_auth_with_config
[Component: function]
Verify and authorize a JWT
token with explicit
configuration.
") - style 92 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 93("
explicit.create_hs512_config
[Component: function]
Helper function to create
HS512 config from
base64url-encoded secret.
") - style 93 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 94("
explicit.create_eddsa_sign_config
[Component: function]
Helper function to create
EdDSA sign config from JWK.
") - style 94 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 95("
explicit.create_eddsa_verify_config
[Component: function]
Helper function to create
EdDSA verify config from JWK.
") - style 95 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 96("
explicit.SignConfig
[Component: type]
") - style 96 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 97("
explicit.VerifyConfig
[Component: type]
") - style 97 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 100("
explicit._find_jwk_by_kid
[Component: function]
") + style 100 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 101("
explicit._import_verify_key
[Component: function]
") + style 101 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 102("
explicit._has_public_jwk
[Component: function]
") + style 102 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 103("
explicit._has_jwks_url
[Component: function]
") + style 103 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 104("
explicit._verify_asymmetric_signature
[Component: function]
") + style 104 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 105("
explicit.sign_with_config
[Component: function]
Sign a JWT token with
explicit configuration.
") + style 105 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 106("
explicit.verify_with_config
[Component: function]
Verify a JWT token with
explicit configuration.
") + style 106 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 107("
explicit.create_token_with_config
[Component: function]
Create a signed JWT token
with explicit configuration.
") + style 107 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 108("
explicit.create_delegated_token_with_config
[Component: function]
Create a delegated JWT token
with explicit configuration.
") + style 108 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 109("
explicit.check_auth_with_config
[Component: function]
Verify and authorize a JWT
token with explicit
configuration.
") + style 109 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 110("
explicit.create_hs512_config
[Component: function]
Helper function to create
HS512 config from
base64url-encoded secret.
") + style 110 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 111("
explicit.create_eddsa_sign_config
[Component: function]
Helper function to create
EdDSA sign config from JWK.
") + style 111 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 112("
explicit.create_eddsa_verify_config
[Component: function]
Helper function to create
EdDSA verify config from JWK.
") + style 112 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 113("
explicit.create_es512_verify_config
[Component: function]
Helper function to create
ES512 verify config from a
public JWK.
") + style 113 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 114("
explicit.create_jwks_url_verify_config
[Component: function]
Helper function to create
JWKS URL verification config.
") + style 114 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 115("
explicit.SignConfig
[Component: type]
") + style 115 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 116("
explicit.VerifyConfig
[Component: type]
") + style 116 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 86("
explicit.BaseJwtConfig
[Component: class]
Base JWT configuration shared
by HS512 and EdDSA modes.
") + style 86 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 87("
explicit.HS512Config
[Component: class]
HS512 (HMAC-SHA512) symmetric
configuration.
") + style 87 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 88("
explicit.EdDSASignConfig
[Component: class]
EdDSA (Ed25519) asymmetric
configuration for signing.
") + style 88 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 89("
explicit.EdDSAVerifyConfig
[Component: class]
EdDSA (Ed25519) asymmetric
configuration for
verification.
") + style 89 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 90("
explicit.ES512VerifyConfig
[Component: class]
ES512 (ECDSA P-521)
asymmetric configuration for
verification.
") + style 90 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 91("
explicit.JWKSUrlVerifyConfig
[Component: class]
Asymmetric verification
configuration backed by a
remote JWKS URL.
") + style 91 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 92("
explicit.AuthzOptsWithConfig
[Component: class]
Authorization options for
check_auth_with_config.
") + style 92 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 93("
explicit.AuthUser
[Component: class]
Authenticated user
information.
") + style 93 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 94("
explicit._b64url
[Component: function]
Encode bytes to base64url
without padding.
") + style 94 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 95("
explicit._b64url_decode
[Component: function]
Decode base64url string (with
or without padding).
") + style 95 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 96("
explicit._validate_jwks_url
[Component: function]
") + style 96 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 97("
explicit._ecdsa_curve_name
[Component: function]
") + style 97 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 98("
explicit._hash_name
[Component: function]
") + style 98 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 99("
explicit._fetch_jwks_from_url
[Component: function]
") + style 99 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__util.mmd b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__util.mmd index a6caace..fac6b81 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__util.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Classes_flarelette_jwt__util.mmd @@ -1,104 +1,106 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 60 ["flarelette-jwt"] - style 60 fill:#ffffff,stroke:#2e6295,color:#2e6295 + subgraph 65 [" "] + style 65 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 100("
util.PolicyBuilder.base
[Component: method]
") - style 100 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 101("
util.PolicyBuilder.need_all
[Component: method]
") - style 101 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 102("
util.PolicyBuilder.need_any
[Component: method]
") - style 102 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 103("
util.PolicyBuilder.roles_all
[Component: method]
") - style 103 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 104("
util.PolicyBuilder.roles_any
[Component: method]
") - style 104 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 105("
util.PolicyBuilder.where
[Component: method]
") - style 105 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 106("
util.PolicyBuilder.build
[Component: method]
") - style 106 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 107("
util.Builder
[Component: class]
") - style 107 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 108("
util.Builder.base
[Component: method]
") - style 108 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 109("
util.Builder.need_all
[Component: method]
") - style 109 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 110("
util.Builder.need_any
[Component: method]
") - style 110 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 111("
util.Builder.roles_all
[Component: method]
") - style 111 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 112("
util.Builder.roles_any
[Component: method]
") - style 112 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 113("
util.Builder.where
[Component: method]
") - style 113 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 114("
util.Builder.build
[Component: method]
") - style 114 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 115("
util.create_token
[Component: function]
Create a signed JWT token
with optional claims.
") - style 115 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 116("
util.create_delegated_token
[Component: function]
Create a delegated JWT token
following RFC 8693 actor
claim pattern.
") - style 116 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 117("
util.check_auth
[Component: function]
Verify and authorize a JWT
token with policy
enforcement.
") - style 117 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 118("
util.policy
[Component: function]
Fluent builder for creating
authorization policies.
") - style 118 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 119("
util.generate_secret
[Component: function]
") - style 119 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 120("
util.is_valid_base64url_secret
[Component: function]
") - style 120 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 121("
util.main
[Component: function]
") - style 121 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 122("
util._b64url
[Component: function]
") - style 122 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 123("
util.sign
[Component: function]
Sign a JWT token with HS512
or EdDSA algorithm.
") - style 123 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 124("
util.ParsedJwt
[Component: class]
Parsed JWT token structure.
") - style 124 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 125("
util.parse
[Component: function]
Parse a JWT token into header
and payload without
verification.
") - style 125 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 126("
util.is_expiring_soon
[Component: function]
Check if JWT payload will
expire within specified
seconds.
") - style 126 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 127("
util.map_scopes_to_permissions
[Component: function]
Map OAuth scopes to
permission strings.
") - style 127 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 128("
util._b64url_decode
[Component: function]
") - style 128 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 129("
util.verify
[Component: function]
Verify a JWT token with HS512
or EdDSA algorithm.
") - style 129 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 66("
util.JwtHeader
[Component: class]
JWT token header structure.
") - style 66 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 67("
util.ActorClaim
[Component: class]
Actor claim for service
delegation (RFC 8693).
") - style 67 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 68("
util.JwtPayload
[Component: class]
JWT token payload/claims
structure.
") - style 68 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 69("
util.JwtProfile
[Component: class]
JWT Profile structure
matching
flarelette-jwt.profile.schema.json.
") - style 69 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 70("
util.JwtCommonConfig
[Component: class]
Common JWT configuration from
environment variables.
") - style 70 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 71("
util.mode
[Component: function]
Detect JWT algorithm mode
from environment variables
based on role.
") - style 71 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 72("
util.common
[Component: function]
Get common JWT configuration
from environment.
") - style 72 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 73("
util.profile
[Component: function]
Get JWT profile from
environment.
") - style 73 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 74("
util._get_indirect
[Component: function]
") - style 74 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 75("
util.get_hs_secret_bytes
[Component: function]
") - style 75 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 76("
util.get_public_jwk_string
[Component: function]
") - style 76 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 77("
util.AlgType
[Component: type]
") - style 77 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 78("
util.JwtValue
[Component: type]
") - style 78 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 79("
util.ClaimsDict
[Component: type]
") - style 79 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 98("
util.AuthUser
[Component: class]
Authenticated user
information returned by
check_auth.
") - style 98 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 99("
util.PolicyBuilder
[Component: class]
Builder interface for
creating JWT authorization
policies.
") - style 99 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 117("
util.AuthUser
[Component: class]
Authenticated user
information returned by
check_auth.
") + style 117 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 118("
util.PolicyBuilder
[Component: class]
Builder interface for
creating JWT authorization
policies.
") + style 118 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 119("
util.PolicyBuilder.base
[Component: method]
") + style 119 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 120("
util.PolicyBuilder.need_all
[Component: method]
") + style 120 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 121("
util.PolicyBuilder.need_any
[Component: method]
") + style 121 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 122("
util.PolicyBuilder.roles_all
[Component: method]
") + style 122 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 123("
util.PolicyBuilder.roles_any
[Component: method]
") + style 123 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 124("
util.PolicyBuilder.where
[Component: method]
") + style 124 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 125("
util.PolicyBuilder.build
[Component: method]
") + style 125 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 126("
util.Builder
[Component: class]
") + style 126 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 127("
util.Builder.base
[Component: method]
") + style 127 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 128("
util.Builder.need_all
[Component: method]
") + style 128 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 129("
util.Builder.need_any
[Component: method]
") + style 129 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 130("
util.Builder.roles_all
[Component: method]
") + style 130 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 131("
util.Builder.roles_any
[Component: method]
") + style 131 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 132("
util.Builder.where
[Component: method]
") + style 132 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 133("
util.Builder.build
[Component: method]
") + style 133 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 134("
util.create_token
[Component: function]
Create a signed JWT token
with optional claims.
") + style 134 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 135("
util.create_delegated_token
[Component: function]
Create a delegated JWT token
following RFC 8693 actor
claim pattern.
") + style 135 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 136("
util.check_auth
[Component: function]
Verify and authorize a JWT
token with policy
enforcement.
") + style 136 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 137("
util.policy
[Component: function]
Fluent builder for creating
authorization policies.
") + style 137 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 138("
util.generate_secret
[Component: function]
") + style 138 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 139("
util.is_valid_base64url_secret
[Component: function]
") + style 139 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 140("
util.main
[Component: function]
") + style 140 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 141("
util._b64url
[Component: function]
") + style 141 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 142("
util.sign
[Component: function]
Sign a JWT token with HS512
or EdDSA algorithm.
") + style 142 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 143("
util.ParsedJwt
[Component: class]
Parsed JWT token structure.
") + style 143 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 144("
util.parse
[Component: function]
Parse a JWT token into header
and payload without
verification.
") + style 144 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 145("
util.is_expiring_soon
[Component: function]
Check if JWT payload will
expire within specified
seconds.
") + style 145 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 146("
util.map_scopes_to_permissions
[Component: function]
Map OAuth scopes to
permission strings.
") + style 146 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 147("
util._b64url_decode
[Component: function]
") + style 147 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 148("
util.verify
[Component: function]
Verify a JWT token with HS512
or EdDSA algorithm.
") + style 148 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 71("
util.JwtHeader
[Component: class]
JWT token header structure.
") + style 71 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 72("
util.ActorClaim
[Component: class]
Actor claim for service
delegation (RFC 8693).
") + style 72 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 73("
util.JwtPayload
[Component: class]
JWT token payload/claims
structure.
") + style 73 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 74("
util.JwtProfile
[Component: class]
JWT Profile structure
matching
flarelette-jwt.profile.schema.json.
") + style 74 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 75("
util.JwtCommonConfig
[Component: class]
Common JWT configuration from
environment variables.
") + style 75 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 76("
util.mode
[Component: function]
Detect JWT algorithm mode
from environment variables
based on role.
") + style 76 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 77("
util.common
[Component: function]
Get common JWT configuration
from environment.
") + style 77 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 78("
util.profile
[Component: function]
Get JWT profile from
environment.
") + style 78 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 79("
util._get_indirect
[Component: function]
") + style 79 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 80("
util.get_hs_secret_bytes
[Component: function]
") + style 80 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 81("
util.get_public_jwk_string
[Component: function]
") + style 81 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 82("
util.get_jwks_url
[Component: function]
") + style 82 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 83("
util.AlgType
[Component: type]
") + style 83 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 84("
util.JwtValue
[Component: type]
") + style 84 fill:#d4e8fc,stroke:#94a2b0,color:#000000 + 85("
util.ClaimsDict
[Component: type]
") + style 85 fill:#d4e8fc,stroke:#94a2b0,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Components__chrislyons_dev_flarelette_jwt.mmd b/docs/architecture/diagrams/mermaid/structurizr-Components__chrislyons_dev_flarelette_jwt.mmd index f38b815..47472fc 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Components__chrislyons_dev_flarelette_jwt.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Components__chrislyons_dev_flarelette_jwt.mmd @@ -1,10 +1,10 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 2 ["@chrislyons-dev/flarelette-jwt"] + subgraph 2 [" "] style 2 fill:#ffffff,stroke:#2e6295,color:#2e6295 10("
adapters
[Component: module]
Component inferred from
directory: adapters
") @@ -13,7 +13,7 @@ graph TB style 3 fill:#85bbf0,stroke:#5d82a8,color:#000000 4("
explicit
[Component: module]
Explicit configuration API
for JWT operations. This
module provides functions
that accept explicit
configuration objects instead
of relying on environment
variables or global state.
Use this API when you need
full control over
configuration, especially in
development environments or
when working with multiple
JWT configurations.
") style 4 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 5("
util
[Component: module]
High-level JWT utilities for
creating, delegating,
verifying, and authorizing
JWT tokens | Key generation
utility for EdDSA keys. This
script generates EdDSA key
pairs and exports them in JWK
format. It is designed to be
executed as a standalone
Node.js script. | Secret
generation and validation
utilities. This module
provides functions to
generate secure secrets and
validate base64url-encoded
secrets. It ensures
compatibility with JWT
signing requirements. |
Utility functions for JWT
operations. This module
provides helper functions for
parsing JWTs, checking
expiration, and mapping OAuth
scopes. It is designed to
support core JWT
functionalities.
") + 5("
util
[Component: module]
High-level JWT utilities for
creating, delegating,
verifying, and authorizing
JWT tokens | Key generation
utility for EdDSA and ECDSA
keys. Generates asymmetric
key pairs and exports them in
JWK format. Designed to be
executed as a standalone
Node.js script. | Secret
generation and validation
utilities. This module
provides functions to
generate secure secrets and
validate base64url-encoded
secrets. It ensures
compatibility with JWT
signing requirements. |
Utility functions for JWT
operations. This module
provides helper functions for
parsing JWTs, checking
expiration, and mapping OAuth
scopes. It is designed to
support core JWT
functionalities.
") style 5 fill:#85bbf0,stroke:#5d82a8,color:#000000 6("
main
[Component: module]
Entry point for the
flarelette-jwt library. This
module re-exports core
functionalities, including
signing, verification,
utilities, and type
definitions. It serves as the
main interface for library
consumers.
") style 6 fill:#85bbf0,stroke:#5d82a8,color:#000000 diff --git a/docs/architecture/diagrams/mermaid/structurizr-Components_flarelette_jwt.mmd b/docs/architecture/diagrams/mermaid/structurizr-Components_flarelette_jwt.mmd index bfd601c..62ae96d 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Components_flarelette_jwt.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Components_flarelette_jwt.mmd @@ -1,20 +1,20 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - flarelette-jwt - Components"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 60 ["flarelette-jwt"] - style 60 fill:#ffffff,stroke:#2e6295,color:#2e6295 + subgraph 65 [" "] + style 65 fill:#ffffff,stroke:#2e6295,color:#2e6295 - 61("
adapters
[Component: module]
Adapters for Cloudflare
Workers Environment This
module provides utilities to
adapt Cloudflare Workers
environment variables for use
with the Flarelette JWT
library.
") - style 61 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 62("
util
[Component: module]
Environment Configuration for
JWT Operations This module
provides functions to read
environment variables and
derive JWT-related
configurations. It supports
both symmetric (HS512) and
asymmetric (EdDSA)
algorithms.
") - style 62 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 63("
explicit
[Component: module]
Explicit Configuration API
for JWT Operations This
module provides functions
that accept explicit
configuration objects instead
of relying on environment
variables or global state.
Use this API when you need
full control over
configuration, especially in
development environments or
when working with multiple
JWT configurations.
") - style 63 fill:#85bbf0,stroke:#5d82a8,color:#000000 - 64("
flarelette_jwt
[Component: module]
Component derived from
directory: flarelette_jwt
") - style 64 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 66("
adapters
[Component: module]
Adapters for Cloudflare
Workers Environment This
module provides utilities to
adapt Cloudflare Workers
environment variables for use
with the Flarelette JWT
library.
") + style 66 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 67("
util
[Component: module]
Environment Configuration for
JWT Operations This module
provides functions to read
environment variables and
derive JWT-related
configurations. It supports
both symmetric (HS512) and
asymmetric (EdDSA)
algorithms.
") + style 67 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 68("
explicit
[Component: module]
Explicit Configuration API
for JWT Operations This
module provides functions
that accept explicit
configuration objects instead
of relying on environment
variables or global state.
Use this API when you need
full control over
configuration, especially in
development environments or
when working with multiple
JWT configurations.
") + style 68 fill:#85bbf0,stroke:#5d82a8,color:#000000 + 69("
flarelette_jwt
[Component: module]
Component derived from
directory: flarelette_jwt
") + style 69 fill:#85bbf0,stroke:#5d82a8,color:#000000 end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-Containers.mmd b/docs/architecture/diagrams/mermaid/structurizr-Containers.mmd index 083e179..c03c130 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-Containers.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-Containers.mmd @@ -1,16 +1,16 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - Containers"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff - subgraph 1 ["flarelette-jwt-kit"] + subgraph 1 [" "] style 1 fill:#ffffff,stroke:#0b4884,color:#0b4884 - 2("
@chrislyons-dev/flarelette-jwt
[Container: Service]
Environment-driven JWT
authentication for Cloudflare
Workers with secret-name
indirection
") + 2("
@chrislyons-dev/flarelette-jwt
[Container: Service]
TypeScript implementation of
the Flarelette JWT Kit: An
environment-driven JWT
authentication package for
Cloudflare Workers
") style 2 fill:#438dd5,stroke:#2e6295,color:#ffffff - 60("
flarelette-jwt
[Container: Service]
Environment-driven JWT
authentication for Cloudflare
Workers Python with
secret-name indirection
") - style 60 fill:#438dd5,stroke:#2e6295,color:#ffffff + 65("
flarelette-jwt
[Container: Service]
Python implementation of the
Flarelette JWT Kit: An
environment-driven JWT
authentication package for
Cloudflare Workers
") + style 65 fill:#438dd5,stroke:#2e6295,color:#ffffff end end \ No newline at end of file diff --git a/docs/architecture/diagrams/mermaid/structurizr-SystemContext.mmd b/docs/architecture/diagrams/mermaid/structurizr-SystemContext.mmd index 5f8e5da..59b3eed 100644 --- a/docs/architecture/diagrams/mermaid/structurizr-SystemContext.mmd +++ b/docs/architecture/diagrams/mermaid/structurizr-SystemContext.mmd @@ -1,7 +1,7 @@ -graph TB +graph LR linkStyle default fill:#ffffff - subgraph diagram ["flarelette-jwt-kit - System Context"] + subgraph diagram [" "] style diagram fill:#ffffff,stroke:#ffffff 1("
flarelette-jwt-kit
[Software System]
JWT authentication and
authorization library
") diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.puml index 7c1529a..5256a01 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,23 +17,23 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.puml index a6abeb9..3d0da52 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,79 +17,79 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.puml index 08d212e..6d1bbc8 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,65 +17,79 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } @@ -94,7 +108,9 @@ rectangle "@chrislyons-dev/flarelette-jwt\n[Container: Service]" rectangle "==explicit.createHS512Config\n[Component: function]\n\nHelper function to create HS512 config from base64url-encoded secret" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateHS512Config rectangle "==explicit.createEdDSASignConfig\n[Component: function]\n\nHelper function to create EdDSA sign config from JWK" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateEdDSASignConfig rectangle "==explicit.createEdDSAVerifyConfig\n[Component: function]\n\nHelper function to create EdDSA verify config from JWK" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateEdDSAVerifyConfig - rectangle "==explicit.createJWKSUrlVerifyConfig\n[Component: function]\n\nHelper function to create HTTP JWKS URL verification config Enables testing without environment variables by providing explicit configuration" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateJWKSUrlVerifyConfig + rectangle "==explicit.createES512SignConfig\n[Component: function]\n\nHelper function to create ES512 sign config from a P-521 EC private JWK" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateES512SignConfig + rectangle "==explicit.createES512VerifyConfig\n[Component: function]\n\nHelper function to create ES512 verify config from a P-521 EC public JWK" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateES512VerifyConfig + rectangle "==explicit.createJWKSUrlVerifyConfig\n[Component: function]" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicitcreateJWKSUrlVerifyConfig } @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.puml index a047d39..3ac3acd 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,51 +17,51 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.puml index 4cac45f..7d0eba1 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,72 +17,93 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } @@ -95,6 +116,8 @@ skinparam rectangle<> { rectangle "@chrislyons-dev/flarelette-jwt\n[Container: Service]" <> { rectangle "==util.createToken\n[Component: function]\n\nCreate a signed JWT token with optional claims" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilcreateToken rectangle "==util.createDelegatedToken\n[Component: function]\n\nCreate a delegated JWT token following RFC 8693 actor claim pattern Mints a new short-lived token for use within service boundaries where a service acts on behalf of the original end user. This implements zero-trust delegation: - Preserves original user identity (sub) and permissions - Identifies the acting service via 'act' claim - Prevents permission escalation by copying original permissions Pattern: "I'm doing work on behalf of "" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilcreateDelegatedToken + rectangle "==util.signWithRequestBinding\n[Component: function]\n\nSign a JWT token bound to a specific HTTP request. Adds a `req` claim containing base64url(SHA-256(canonical request)) to prevent replay of a captured token against a different endpoint within the TTL window. Canonical form: METHOD + "\\n" + pathname + search + "\\n" + body bytes" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilsignWithRequestBinding + rectangle "==util.verifyWithRequestBinding\n[Component: function]\n\nVerify a JWT token and validate its request binding. Re-computes the request hash and compares it with the `req` claim. Returns null on any mismatch (fail-silent, same as verify()). The `req` claim is stripped from the returned payload — it's an implementation detail that has already been validated." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilverifyWithRequestBinding rectangle "==util.checkAuth\n[Component: function]\n\nVerify and authorize a JWT token with policy enforcement" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilcheckAuth rectangle "==util.policy\n[Component: function]\n\nFluent builder for creating authorization policies" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilpolicy rectangle "==util.main\n[Component: function]" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilmain @@ -103,6 +126,7 @@ rectangle "@chrislyons-dev/flarelette-jwt\n[Container: Service]" rectangle "==util.parse\n[Component: function]\n\nParse a JWT token into header and payload without verification" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilparse rectangle "==util.isExpiringSoon\n[Component: function]\n\nCheck if JWT payload will expire within specified seconds" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilisExpiringSoon rectangle "==util.mapScopesToPermissions\n[Component: function]\n\nMap OAuth scopes to permission strings" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilmapScopesToPermissions + rectangle "==util.computeRequestHash\n[Component: function]\n\nCompute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request. Canonical form: UTF-8(METHOD + "\\n" + pathname + search + "\\n") || body_bytes - Method is uppercased - Binds to path and query string only (not host/scheme — internal Workers use different hostnames) - Body is consumed from a clone to preserve the original stream" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.utilcomputeRequestHash } @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.puml index 50f4330..9e64577 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,16 +17,16 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters.puml index 46dc8a0..5d9bf9a 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__adapters.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,9 +17,9 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit.puml index c5c1724..5091be4 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__explicit.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,128 +17,219 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } @@ -149,14 +240,11 @@ skinparam rectangle<> { } rectangle "flarelette-jwt\n[Container: Service]" <> { - rectangle "==explicit.BaseJwtConfig\n[Component: class]\n\nBase JWT configuration shared by HS512 and EdDSA modes." <> as flarelettejwtkit.flarelettejwt.explicitBaseJwtConfig - rectangle "==explicit.HS512Config\n[Component: class]\n\nHS512 (HMAC-SHA512) symmetric configuration." <> as flarelettejwtkit.flarelettejwt.explicitHS512Config - rectangle "==explicit.EdDSASignConfig\n[Component: class]\n\nEdDSA (Ed25519) asymmetric configuration for signing." <> as flarelettejwtkit.flarelettejwt.explicitEdDSASignConfig - rectangle "==explicit.EdDSAVerifyConfig\n[Component: class]\n\nEdDSA (Ed25519) asymmetric configuration for verification." <> as flarelettejwtkit.flarelettejwt.explicitEdDSAVerifyConfig - rectangle "==explicit.AuthzOptsWithConfig\n[Component: class]\n\nAuthorization options for check_auth_with_config." <> as flarelettejwtkit.flarelettejwt.explicitAuthzOptsWithConfig - rectangle "==explicit.AuthUser\n[Component: class]\n\nAuthenticated user information." <> as flarelettejwtkit.flarelettejwt.explicitAuthUser - rectangle "==explicit._b64url\n[Component: function]\n\nEncode bytes to base64url without padding." <> as flarelettejwtkit.flarelettejwt.explicit_b64url - rectangle "==explicit._b64url_decode\n[Component: function]\n\nDecode base64url string (with or without padding)." <> as flarelettejwtkit.flarelettejwt.explicit_b64url_decode + rectangle "==explicit._find_jwk_by_kid\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_find_jwk_by_kid + rectangle "==explicit._import_verify_key\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_import_verify_key + rectangle "==explicit._has_public_jwk\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_has_public_jwk + rectangle "==explicit._has_jwks_url\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_has_jwks_url + rectangle "==explicit._verify_asymmetric_signature\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_verify_asymmetric_signature rectangle "==explicit.sign_with_config\n[Component: function]\n\nSign a JWT token with explicit configuration." <> as flarelettejwtkit.flarelettejwt.explicitsign_with_config rectangle "==explicit.verify_with_config\n[Component: function]\n\nVerify a JWT token with explicit configuration." <> as flarelettejwtkit.flarelettejwt.explicitverify_with_config rectangle "==explicit.create_token_with_config\n[Component: function]\n\nCreate a signed JWT token with explicit configuration." <> as flarelettejwtkit.flarelettejwt.explicitcreate_token_with_config @@ -165,8 +253,24 @@ rectangle "flarelette-jwt\n[Container: Service]" <[Component: function]\n\nHelper function to create HS512 config from base64url-encoded secret." <> as flarelettejwtkit.flarelettejwt.explicitcreate_hs512_config rectangle "==explicit.create_eddsa_sign_config\n[Component: function]\n\nHelper function to create EdDSA sign config from JWK." <> as flarelettejwtkit.flarelettejwt.explicitcreate_eddsa_sign_config rectangle "==explicit.create_eddsa_verify_config\n[Component: function]\n\nHelper function to create EdDSA verify config from JWK." <> as flarelettejwtkit.flarelettejwt.explicitcreate_eddsa_verify_config + rectangle "==explicit.create_es512_verify_config\n[Component: function]\n\nHelper function to create ES512 verify config from a public JWK." <> as flarelettejwtkit.flarelettejwt.explicitcreate_es512_verify_config + rectangle "==explicit.create_jwks_url_verify_config\n[Component: function]\n\nHelper function to create JWKS URL verification config." <> as flarelettejwtkit.flarelettejwt.explicitcreate_jwks_url_verify_config rectangle "==explicit.SignConfig\n[Component: type]" <> as flarelettejwtkit.flarelettejwt.explicitSignConfig rectangle "==explicit.VerifyConfig\n[Component: type]" <> as flarelettejwtkit.flarelettejwt.explicitVerifyConfig + rectangle "==explicit.BaseJwtConfig\n[Component: class]\n\nBase JWT configuration shared by HS512 and EdDSA modes." <> as flarelettejwtkit.flarelettejwt.explicitBaseJwtConfig + rectangle "==explicit.HS512Config\n[Component: class]\n\nHS512 (HMAC-SHA512) symmetric configuration." <> as flarelettejwtkit.flarelettejwt.explicitHS512Config + rectangle "==explicit.EdDSASignConfig\n[Component: class]\n\nEdDSA (Ed25519) asymmetric configuration for signing." <> as flarelettejwtkit.flarelettejwt.explicitEdDSASignConfig + rectangle "==explicit.EdDSAVerifyConfig\n[Component: class]\n\nEdDSA (Ed25519) asymmetric configuration for verification." <> as flarelettejwtkit.flarelettejwt.explicitEdDSAVerifyConfig + rectangle "==explicit.ES512VerifyConfig\n[Component: class]\n\nES512 (ECDSA P-521) asymmetric configuration for verification." <> as flarelettejwtkit.flarelettejwt.explicitES512VerifyConfig + rectangle "==explicit.JWKSUrlVerifyConfig\n[Component: class]\n\nAsymmetric verification configuration backed by a remote JWKS URL." <> as flarelettejwtkit.flarelettejwt.explicitJWKSUrlVerifyConfig + rectangle "==explicit.AuthzOptsWithConfig\n[Component: class]\n\nAuthorization options for check_auth_with_config." <> as flarelettejwtkit.flarelettejwt.explicitAuthzOptsWithConfig + rectangle "==explicit.AuthUser\n[Component: class]\n\nAuthenticated user information." <> as flarelettejwtkit.flarelettejwt.explicitAuthUser + rectangle "==explicit._b64url\n[Component: function]\n\nEncode bytes to base64url without padding." <> as flarelettejwtkit.flarelettejwt.explicit_b64url + rectangle "==explicit._b64url_decode\n[Component: function]\n\nDecode base64url string (with or without padding)." <> as flarelettejwtkit.flarelettejwt.explicit_b64url_decode + rectangle "==explicit._validate_jwks_url\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_validate_jwks_url + rectangle "==explicit._ecdsa_curve_name\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_ecdsa_curve_name + rectangle "==explicit._hash_name\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_hash_name + rectangle "==explicit._fetch_jwks_from_url\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.explicit_fetch_jwks_from_url } @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util-key.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util-key.puml index da75bcd..d2ad682 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util-key.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util-key.puml @@ -18,12 +18,12 @@ skinparam rectangle<<_transparent>> { } skinparam rectangle<<1>> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 } -rectangle "==Component" <<1>> +rectangle "==Component, Code" <<1>> @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util.puml b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util.puml index 64ba91f..1a4646e 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Classes_flarelette_jwt__util.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -17,324 +17,331 @@ skinparam { hide stereotype skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 + roundCorner 20 + shadowing false +} +skinparam rectangle<> { + BackgroundColor #d4e8fc + FontColor #000000 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } skinparam rectangle<> { - BackgroundColor #85bbf0 + BackgroundColor #d4e8fc FontColor #000000 - BorderColor #5d82a8 + BorderColor #94a2b0 roundCorner 20 shadowing false } @@ -345,6 +352,8 @@ skinparam rectangle<> { } rectangle "flarelette-jwt\n[Container: Service]" <> { + rectangle "==util.AuthUser\n[Component: class]\n\nAuthenticated user information returned by check_auth." <> as flarelettejwtkit.flarelettejwt.utilAuthUser + rectangle "==util.PolicyBuilder\n[Component: class]\n\nBuilder interface for creating JWT authorization policies." <> as flarelettejwtkit.flarelettejwt.utilPolicyBuilder rectangle "==util.PolicyBuilder.base\n[Component: method]" <> as flarelettejwtkit.flarelettejwt.utilPolicyBuilderbase rectangle "==util.PolicyBuilder.need_all\n[Component: method]" <> as flarelettejwtkit.flarelettejwt.utilPolicyBuilderneed_all rectangle "==util.PolicyBuilder.need_any\n[Component: method]" <> as flarelettejwtkit.flarelettejwt.utilPolicyBuilderneed_any @@ -386,11 +395,10 @@ rectangle "flarelette-jwt\n[Container: Service]" <[Component: function]" <> as flarelettejwtkit.flarelettejwt.util_get_indirect rectangle "==util.get_hs_secret_bytes\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.utilget_hs_secret_bytes rectangle "==util.get_public_jwk_string\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.utilget_public_jwk_string + rectangle "==util.get_jwks_url\n[Component: function]" <> as flarelettejwtkit.flarelettejwt.utilget_jwks_url rectangle "==util.AlgType\n[Component: type]" <> as flarelettejwtkit.flarelettejwt.utilAlgType rectangle "==util.JwtValue\n[Component: type]" <> as flarelettejwtkit.flarelettejwt.utilJwtValue rectangle "==util.ClaimsDict\n[Component: type]" <> as flarelettejwtkit.flarelettejwt.utilClaimsDict - rectangle "==util.AuthUser\n[Component: class]\n\nAuthenticated user information returned by check_auth." <> as flarelettejwtkit.flarelettejwt.utilAuthUser - rectangle "==util.PolicyBuilder\n[Component: class]\n\nBuilder interface for creating JWT authorization policies." <> as flarelettejwtkit.flarelettejwt.utilPolicyBuilder } @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-Components__chrislyons_dev_flarelette_jwt.puml b/docs/architecture/diagrams/plantuml/structurizr-Components__chrislyons_dev_flarelette_jwt.puml index 28d0b85..85523cf 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Components__chrislyons_dev_flarelette_jwt.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Components__chrislyons_dev_flarelette_jwt.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - @chrislyons-dev/flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -82,7 +82,7 @@ rectangle "@chrislyons-dev/flarelette-jwt\n[Container: Service]" rectangle "==adapters\n[Component: module]\n\nComponent inferred from directory: adapters" <> as flarelettejwtkit.chrislyonsdevflarelettejwt.adapters rectangle "==core\n[Component: module]\n\nCLI utility for generating JWT secrets. This script provides options to generate secrets in various formats, including JSON and dotenv. It is designed to be executed as a standalone Node.js script. | Configuration utilities for JWT operations. This module provides functions to read environment variables and derive JWT-related configurations. It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. | JWT signing utilities. This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms. It supports custom claims and configuration overrides." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.core rectangle "==explicit\n[Component: module]\n\nExplicit configuration API for JWT operations. This module provides functions that accept explicit configuration objects instead of relying on environment variables or global state. Use this API when you need full control over configuration, especially in development environments or when working with multiple JWT configurations." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.explicit - rectangle "==util\n[Component: module]\n\nHigh-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys. This script generates EdDSA key pairs and exports them in JWK format. It is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. This module provides functions to generate secure secrets and validate base64url-encoded secrets. It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. It is designed to support core JWT functionalities." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.util + rectangle "==util\n[Component: module]\n\nHigh-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA and ECDSA keys. Generates asymmetric key pairs and exports them in JWK format. Designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. This module provides functions to generate secure secrets and validate base64url-encoded secrets. It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. It is designed to support core JWT functionalities." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.util rectangle "==main\n[Component: module]\n\nEntry point for the flarelette-jwt library. This module re-exports core functionalities, including signing, verification, utilities, and type definitions. It serves as the main interface for library consumers." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.main rectangle "==jwks\n[Component: module]\n\nJSON Web Key Set (JWKS) utilities. This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid). It supports integration with external JWKS services." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.jwks rectangle "==types\n[Component: module]\n\nType definitions for JWT operations. This module defines types for JWT headers, payloads, profiles, and related structures. It ensures type safety and consistency across the library." <> as flarelettejwtkit.chrislyonsdevflarelettejwt.types diff --git a/docs/architecture/diagrams/plantuml/structurizr-Components_flarelette_jwt.puml b/docs/architecture/diagrams/plantuml/structurizr-Components_flarelette_jwt.puml index c42b2f1..0316030 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Components_flarelette_jwt.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Components_flarelette_jwt.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - flarelette-jwt - Components -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 diff --git a/docs/architecture/diagrams/plantuml/structurizr-Containers.puml b/docs/architecture/diagrams/plantuml/structurizr-Containers.puml index af2cae8..202ad03 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-Containers.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-Containers.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - Containers -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 @@ -37,8 +37,8 @@ skinparam rectangle<> { } rectangle "flarelette-jwt-kit\n[Software System]" <> { - rectangle "==@chrislyons-dev/flarelette-jwt\n[Container: Service]\n\nEnvironment-driven JWT authentication for Cloudflare Workers with secret-name indirection" <> as flarelettejwtkit.chrislyonsdevflarelettejwt - rectangle "==flarelette-jwt\n[Container: Service]\n\nEnvironment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection" <> as flarelettejwtkit.flarelettejwt + rectangle "==@chrislyons-dev/flarelette-jwt\n[Container: Service]\n\nTypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers" <> as flarelettejwtkit.chrislyonsdevflarelettejwt + rectangle "==flarelette-jwt\n[Container: Service]\n\nPython implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers" <> as flarelettejwtkit.flarelettejwt } @enduml \ No newline at end of file diff --git a/docs/architecture/diagrams/plantuml/structurizr-SystemContext.puml b/docs/architecture/diagrams/plantuml/structurizr-SystemContext.puml index bf36118..eff5995 100644 --- a/docs/architecture/diagrams/plantuml/structurizr-SystemContext.puml +++ b/docs/architecture/diagrams/plantuml/structurizr-SystemContext.puml @@ -2,9 +2,9 @@ set separator none title flarelette-jwt-kit - System Context -top to bottom direction -skinparam ranksep 60 -skinparam nodesep 30 +left to right direction +skinparam ranksep 20 +skinparam nodesep 10 skinparam { arrowFontSize 10 diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.png index 55d9155..1e62fd6 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__adapters.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.png index d148af1..681ab20 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__core.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.png index 1c2c5d3..4177ce1 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__explicit.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.png index c665501..a51705a 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__jwks.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.png index 20eb2ee..ab1eae0 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__util.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.png b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.png index 3988c79..78794ee 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.png and b/docs/architecture/diagrams/structurizr-Classes_chrislyons_dev_flarelette_jwt__verify.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters-key.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters-key.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters.png index d6f99dd..a9f2c3d 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__adapters.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit-key.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit-key.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit.png index 94521a4..8d44340 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__explicit.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util-key.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util-key.png index d4d2249..5847cb9 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util-key.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util-key.png differ diff --git a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util.png b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util.png index 4042baa..10fe927 100644 Binary files a/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util.png and b/docs/architecture/diagrams/structurizr-Classes_flarelette_jwt__util.png differ diff --git a/docs/architecture/diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png b/docs/architecture/diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png index 7b08648..6b56753 100644 Binary files a/docs/architecture/diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png and b/docs/architecture/diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png differ diff --git a/docs/architecture/diagrams/structurizr-Components_flarelette_jwt.png b/docs/architecture/diagrams/structurizr-Components_flarelette_jwt.png index 9c1eb2f..316d288 100644 Binary files a/docs/architecture/diagrams/structurizr-Components_flarelette_jwt.png and b/docs/architecture/diagrams/structurizr-Components_flarelette_jwt.png differ diff --git a/docs/architecture/diagrams/structurizr-Containers.png b/docs/architecture/diagrams/structurizr-Containers.png index eac044a..485bc5b 100644 Binary files a/docs/architecture/diagrams/structurizr-Containers.png and b/docs/architecture/diagrams/structurizr-Containers.png differ diff --git a/docs/architecture/diagrams/structurizr-SystemContext.png b/docs/architecture/diagrams/structurizr-SystemContext.png index 1915f38..998e00a 100644 Binary files a/docs/architecture/diagrams/structurizr-SystemContext.png and b/docs/architecture/diagrams/structurizr-SystemContext.png differ diff --git a/docs/architecture/flarelette-jwt-kit-ir.json b/docs/architecture/flarelette-jwt-kit-ir.json index 2455295..049ed92 100644 --- a/docs/architecture/flarelette-jwt-kit-ir.json +++ b/docs/architecture/flarelette-jwt-kit-ir.json @@ -8,7 +8,7 @@ "actors": [], "containers": [ { - "description": "Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection", + "description": "TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers", "tags": [ "Auto-generated" ], @@ -18,7 +18,7 @@ "layer": "Application" }, { - "description": "Environment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection", + "description": "Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers", "tags": [ "Auto-generated" ], @@ -37,21 +37,21 @@ "type": "module" }, { - "description": "Explicit configuration API for JWT operations.\r\n\r\nThis module provides functions that accept explicit configuration objects\r\ninstead of relying on environment variables or global state. Use this API\r\nwhen you need full control over configuration, especially in development\r\nenvironments or when working with multiple JWT configurations.", + "description": "Explicit configuration API for JWT operations.\n\nThis module provides functions that accept explicit configuration objects\ninstead of relying on environment variables or global state. Use this API\nwhen you need full control over configuration, especially in development\nenvironments or when working with multiple JWT configurations.", "id": "chrislyons_dev_flarelette_jwt__explicit", "containerId": "chrislyons_dev_flarelette_jwt", "name": "explicit", "type": "module" }, { - "description": "High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys.\n\nThis script generates EdDSA key pairs and exports them in JWK format.\nIt is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities.\n\nThis module provides functions to generate secure secrets and validate base64url-encoded secrets.\nIt ensures compatibility with JWT signing requirements. | Utility functions for JWT operations.\n\nThis module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.\nIt is designed to support core JWT functionalities.", + "description": "High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA and ECDSA keys.\n\nGenerates asymmetric key pairs and exports them in JWK format.\nDesigned to be executed as a standalone Node.js script. | Secret generation and validation utilities.\n\nThis module provides functions to generate secure secrets and validate base64url-encoded secrets.\nIt ensures compatibility with JWT signing requirements. | Utility functions for JWT operations.\n\nThis module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.\nIt is designed to support core JWT functionalities.", "id": "chrislyons_dev_flarelette_jwt__util", "containerId": "chrislyons_dev_flarelette_jwt", "name": "util", "type": "module" }, { - "description": "Entry point for the flarelette-jwt library.\r\n\r\nThis module re-exports core functionalities, including signing, verification, utilities, and type definitions.\r\nIt serves as the main interface for library consumers.", + "description": "Entry point for the flarelette-jwt library.\n\nThis module re-exports core functionalities, including signing, verification, utilities, and type definitions.\nIt serves as the main interface for library consumers.", "id": "chrislyons_dev_flarelette_jwt__main", "containerId": "chrislyons_dev_flarelette_jwt", "name": "main", @@ -165,7 +165,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 65 + "lineNumber": 66 }, { "description": "Get JWT profile from environment\nReturns complete JwtProfile with detected algorithm", @@ -187,7 +187,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 78 + "lineNumber": 79 }, { "id": "chrislyons_dev_flarelette_jwt__core__gethssecret", @@ -199,7 +199,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 93 + "lineNumber": 94 }, { "id": "chrislyons_dev_flarelette_jwt__core__getprivatejwkstring", @@ -211,7 +211,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 126 + "lineNumber": 127 }, { "id": "chrislyons_dev_flarelette_jwt__core__getpublicjwkstring", @@ -223,7 +223,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 132 + "lineNumber": 133 }, { "id": "chrislyons_dev_flarelette_jwt__core__getjwksservicename", @@ -235,7 +235,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 138 + "lineNumber": 139 }, { "id": "chrislyons_dev_flarelette_jwt__core__getjwksurl", @@ -247,7 +247,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 144 + "lineNumber": 145 }, { "id": "chrislyons_dev_flarelette_jwt__core__getjwkscachettl", @@ -259,7 +259,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/config.ts", - "lineNumber": 148 + "lineNumber": 151 }, { "description": "Sign a JWT token with explicit configuration", @@ -270,7 +270,7 @@ "documentation": { "summary": "Sign a JWT token with explicit configuration", "examples": [ - "```typescript\r\n// HS512 mode\r\nconst config: HS512Config = {\r\n alg: 'HS512',\r\n secret: new Uint8Array(32), // Your secret\r\n iss: 'https://gateway.example.com',\r\n aud: 'api.example.com',\r\n ttlSeconds: 900\r\n}\r\nconst token = await signWithConfig({ sub: 'user123' }, config)\r\n\r\n// EdDSA mode\r\nconst config: EdDSASignConfig = {\r\n alg: 'EdDSA',\r\n privateJwk: { kty: 'OKP', crv: 'Ed25519', d: '...', x: '...' },\r\n kid: 'ed25519-2025-01',\r\n iss: 'https://gateway.example.com',\r\n aud: 'api.example.com'\r\n}\r\nconst token = await signWithConfig({ sub: 'user123' }, config)\r\n```" + "```typescript\n// HS512 mode\nconst config: HS512Config = {\n alg: 'HS512',\n secret: new Uint8Array(32), // Your secret\n iss: 'https://gateway.example.com',\n aud: 'api.example.com',\n ttlSeconds: 900\n}\nconst token = await signWithConfig({ sub: 'user123' }, config)\n\n// EdDSA mode\nconst config: EdDSASignConfig = {\n alg: 'EdDSA',\n privateJwk: { kty: 'OKP', crv: 'Ed25519', d: '...', x: '...' },\n kid: 'ed25519-2025-01',\n iss: 'https://gateway.example.com',\n aud: 'api.example.com'\n}\nconst token = await signWithConfig({ sub: 'user123' }, config)\n```" ] }, "returnType": "Promise", @@ -298,7 +298,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 122 + "lineNumber": 150 }, { "description": "Verify a JWT token with explicit configuration", @@ -309,7 +309,7 @@ "documentation": { "summary": "Verify a JWT token with explicit configuration", "examples": [ - "```typescript\r\n// HS512 mode\r\nconst config: HS512Config = {\r\n alg: 'HS512',\r\n secret: new Uint8Array(32), // Same secret used for signing\r\n iss: 'https://gateway.example.com',\r\n aud: 'api.example.com'\r\n}\r\nconst payload = await verifyWithConfig(token, config)\r\n\r\n// EdDSA mode\r\nconst config: EdDSAVerifyConfig = {\r\n alg: 'EdDSA',\r\n publicJwk: { kty: 'OKP', crv: 'Ed25519', x: '...' },\r\n iss: 'https://gateway.example.com',\r\n aud: 'api.example.com'\r\n}\r\nconst payload = await verifyWithConfig(token, config)\r\n```" + "```typescript\n// HS512 mode\nconst config: HS512Config = {\n alg: 'HS512',\n secret: new Uint8Array(32), // Same secret used for signing\n iss: 'https://gateway.example.com',\n aud: 'api.example.com'\n}\nconst payload = await verifyWithConfig(token, config)\n\n// EdDSA mode\nconst config: EdDSAVerifyConfig = {\n alg: 'EdDSA',\n publicJwk: { kty: 'OKP', crv: 'Ed25519', x: '...' },\n iss: 'https://gateway.example.com',\n aud: 'api.example.com'\n}\nconst payload = await verifyWithConfig(token, config)\n```" ] }, "returnType": "Promise", @@ -337,16 +337,16 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 181 + "lineNumber": 224 }, { - "description": "Create a signed JWT token with explicit configuration\r\n\r\nHigher-level wrapper around signWithConfig for convenience.", + "description": "Create a signed JWT token with explicit configuration\n\nHigher-level wrapper around signWithConfig for convenience.", "id": "chrislyons_dev_flarelette_jwt__explicit__createtokenwithconfig", "componentId": "chrislyons_dev_flarelette_jwt__explicit", "name": "createTokenWithConfig", "type": "function", "documentation": { - "summary": "Create a signed JWT token with explicit configuration\r\n\r\nHigher-level wrapper around signWithConfig for convenience." + "summary": "Create a signed JWT token with explicit configuration\n\nHigher-level wrapper around signWithConfig for convenience." }, "returnType": "Promise", "returnDescription": "Signed JWT token string", @@ -373,18 +373,18 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 246 + "lineNumber": 293 }, { - "description": "Create a delegated JWT token with explicit configuration\r\n\r\nImplements RFC 8693 actor claim pattern for service-to-service delegation.", + "description": "Create a delegated JWT token with explicit configuration\n\nImplements RFC 8693 actor claim pattern for service-to-service delegation.", "id": "chrislyons_dev_flarelette_jwt__explicit__createdelegatedtokenwithconfig", "componentId": "chrislyons_dev_flarelette_jwt__explicit", "name": "createDelegatedTokenWithConfig", "type": "function", "documentation": { - "summary": "Create a delegated JWT token with explicit configuration\r\n\r\nImplements RFC 8693 actor claim pattern for service-to-service delegation.", + "summary": "Create a delegated JWT token with explicit configuration\n\nImplements RFC 8693 actor claim pattern for service-to-service delegation.", "examples": [ - "```typescript\r\nconst config: HS512Config = {\r\n alg: 'HS512',\r\n secret: mySecret,\r\n iss: 'https://gateway.example.com',\r\n aud: 'internal-api'\r\n}\r\n\r\n// Gateway receives Auth0 token and creates delegated token\r\nconst auth0Payload = await verifyAuth0Token(externalToken)\r\nconst internalToken = await createDelegatedTokenWithConfig(\r\n auth0Payload,\r\n 'gateway-service',\r\n config\r\n)\r\n```" + "```typescript\nconst config: HS512Config = {\n alg: 'HS512',\n secret: mySecret,\n iss: 'https://gateway.example.com',\n aud: 'internal-api'\n}\n\n// Gateway receives Auth0 token and creates delegated token\nconst auth0Payload = await verifyAuth0Token(externalToken)\nconst internalToken = await createDelegatedTokenWithConfig(\n auth0Payload,\n 'gateway-service',\n config\n)\n```" ] }, "returnType": "Promise", @@ -418,7 +418,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 283 + "lineNumber": 330 }, { "description": "Verify and authorize a JWT token with explicit configuration", @@ -429,7 +429,7 @@ "documentation": { "summary": "Verify and authorize a JWT token with explicit configuration", "examples": [ - "```typescript\r\nconst config: HS512Config = {\r\n alg: 'HS512',\r\n secret: mySecret,\r\n iss: 'https://gateway.example.com',\r\n aud: 'api.example.com'\r\n}\r\n\r\nconst user = await checkAuthWithConfig(token, config, {\r\n require_all_permissions: ['read:data'],\r\n require_any_permission: ['admin', 'editor']\r\n})\r\n\r\nif (user) {\r\n console.log('Authorized user:', user.sub)\r\n}\r\n```" + "```typescript\nconst config: HS512Config = {\n alg: 'HS512',\n secret: mySecret,\n iss: 'https://gateway.example.com',\n aud: 'api.example.com'\n}\n\nconst user = await checkAuthWithConfig(token, config, {\n require_all_permissions: ['read:data'],\n require_any_permission: ['admin', 'editor']\n})\n\nif (user) {\n console.log('Authorized user:', user.sub)\n}\n```" ] }, "returnType": "Promise", @@ -463,7 +463,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 369 + "lineNumber": 416 }, { "description": "Helper function to create HS512 config from base64url-encoded secret", @@ -493,7 +493,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 423 + "lineNumber": 470 }, { "description": "Helper function to create EdDSA sign config from JWK", @@ -528,7 +528,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 452 + "lineNumber": 499 }, { "description": "Helper function to create EdDSA verify config from JWK", @@ -557,27 +557,58 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 474 + "lineNumber": 521 }, { - "description": "Helper function to create HTTP JWKS URL verification config\r\n\r\nEnables testing without environment variables by providing explicit configuration", - "id": "chrislyons_dev_flarelette_jwt__explicit__createjwksurlverifyconfig", + "description": "Helper function to create ES512 sign config from a P-521 EC private JWK", + "id": "chrislyons_dev_flarelette_jwt__explicit__createes512signconfig", "componentId": "chrislyons_dev_flarelette_jwt__explicit", - "name": "createJWKSUrlVerifyConfig", + "name": "createES512SignConfig", "type": "function", "documentation": { - "summary": "Helper function to create HTTP JWKS URL verification config\r\n\r\nEnables testing without environment variables by providing explicit configuration", - "examples": [ - "```typescript\r\n// Auth0 configuration\r\nconst config = createJWKSUrlVerifyConfig(\r\n 'https://tenant.auth0.com/.well-known/jwks.json',\r\n {\r\n iss: 'https://tenant.auth0.com/',\r\n aud: 'my-client-id'\r\n }\r\n)\r\n\r\nconst payload = await verifyWithConfig(token, config)\r\n```" - ] + "summary": "Helper function to create ES512 sign config from a P-521 EC private JWK" }, - "returnType": "import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit\").JWKSUrlVerifyConfig", - "returnDescription": "JWKS URL verification configuration", + "returnType": "import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit\").ES512SignConfig", + "returnDescription": "ES512 sign configuration", "parameters": [ { - "name": "jwksUrl", + "name": "privateJwk", + "description": "- Private JWK object or JSON string (EC P-521 key)", + "optional": false + }, + { + "name": "baseConfig", + "type": "Omit & Partial>", + "description": "- Base JWT configuration", + "optional": false + }, + { + "name": "kid", "type": "string", - "description": "- HTTP(S) URL to JWKS endpoint", + "description": "- Optional key ID", + "optional": true + } + ], + "visibility": "public", + "isAsync": false, + "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", + "lineNumber": 542 + }, + { + "description": "Helper function to create ES512 verify config from a P-521 EC public JWK", + "id": "chrislyons_dev_flarelette_jwt__explicit__createes512verifyconfig", + "componentId": "chrislyons_dev_flarelette_jwt__explicit", + "name": "createES512VerifyConfig", + "type": "function", + "documentation": { + "summary": "Helper function to create ES512 verify config from a P-521 EC public JWK" + }, + "returnType": "import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit\").ES512VerifyConfig", + "returnDescription": "ES512 verify configuration", + "parameters": [ + { + "name": "publicJwk", + "description": "- Public JWK object or JSON string (EC P-521 key)", "optional": false }, { @@ -585,18 +616,45 @@ "type": "Omit & Partial>", "description": "- Base JWT configuration", "optional": false + } + ], + "visibility": "public", + "isAsync": false, + "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", + "lineNumber": 564 + }, + { + "id": "chrislyons_dev_flarelette_jwt__explicit__createjwksurlverifyconfig", + "componentId": "chrislyons_dev_flarelette_jwt__explicit", + "name": "createJWKSUrlVerifyConfig", + "type": "function", + "returnType": "import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit\").JWKSUrlVerifyConfig", + "parameters": [ + { + "name": "jwksUrl", + "type": "string", + "optional": false }, { - "name": "cacheTtl", + "name": "algOrBaseConfig", + "type": "\"EdDSA\" | (Omit & Partial>) | \"ES256\" | \"ES384\" | \"ES512\" | \"RS256\" | \"RS384\" | \"RS512\"", + "optional": false + }, + { + "name": "baseConfigOrCacheTtl", + "type": "number | (Omit & Partial>)", + "optional": true + }, + { + "name": "maybeCacheTtl", "type": "number", - "description": "- Optional cache TTL in seconds (default: 300)", "optional": true } ], "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/explicit.ts", - "lineNumber": 511 + "lineNumber": 614 }, { "description": "Create a signed JWT token with optional claims", @@ -626,7 +684,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", - "lineNumber": 18 + "lineNumber": 19 }, { "description": "Create a delegated JWT token following RFC 8693 actor claim pattern\n\nMints a new short-lived token for use within service boundaries where a service\nacts on behalf of the original end user. This implements zero-trust delegation:\n- Preserves original user identity (sub) and permissions\n- Identifies the acting service via 'act' claim\n- Prevents permission escalation by copying original permissions\n\nPattern: \"I'm doing work on behalf of \"", @@ -669,7 +727,79 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", - "lineNumber": 61 + "lineNumber": 62 + }, + { + "description": "Sign a JWT token bound to a specific HTTP request.\n\nAdds a `req` claim containing base64url(SHA-256(canonical request)) to prevent\nreplay of a captured token against a different endpoint within the TTL window.\n\nCanonical form: METHOD + \"\\n\" + pathname + search + \"\\n\" + body bytes", + "id": "chrislyons_dev_flarelette_jwt__util__signwithrequestbinding", + "componentId": "chrislyons_dev_flarelette_jwt__util", + "name": "signWithRequestBinding", + "type": "function", + "documentation": { + "summary": "Sign a JWT token bound to a specific HTTP request.\n\nAdds a `req` claim containing base64url(SHA-256(canonical request)) to prevent\nreplay of a captured token against a different endpoint within the TTL window.\n\nCanonical form: METHOD + \"\\n\" + pathname + search + \"\\n\" + body bytes" + }, + "returnType": "Promise", + "returnDescription": "Signed JWT token string with req claim", + "parameters": [ + { + "name": "payload", + "type": "import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types\").JwtPayload", + "description": "- Claims to include in the token", + "optional": false + }, + { + "name": "request", + "type": "Request", + "description": "- The HTTP request this token is minted for", + "optional": false + }, + { + "name": "opts", + "type": "Partial<{ iss: string; aud: string | string[]; ttlSeconds: number; }>", + "description": "- Optional overrides for iss, aud, ttlSeconds", + "optional": true + } + ], + "visibility": "public", + "isAsync": true, + "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", + "lineNumber": 112 + }, + { + "description": "Verify a JWT token and validate its request binding.\n\nRe-computes the request hash and compares it with the `req` claim.\nReturns null on any mismatch (fail-silent, same as verify()).\nThe `req` claim is stripped from the returned payload — it's an implementation\ndetail that has already been validated.", + "id": "chrislyons_dev_flarelette_jwt__util__verifywithrequestbinding", + "componentId": "chrislyons_dev_flarelette_jwt__util", + "name": "verifyWithRequestBinding", + "type": "function", + "documentation": { + "summary": "Verify a JWT token and validate its request binding.\n\nRe-computes the request hash and compares it with the `req` claim.\nReturns null on any mismatch (fail-silent, same as verify()).\nThe `req` claim is stripped from the returned payload — it's an implementation\ndetail that has already been validated." + }, + "returnType": "Promise", + "returnDescription": "Payload (without req claim) if valid and request matches, null otherwise", + "parameters": [ + { + "name": "token", + "type": "string", + "description": "- JWT token string to verify", + "optional": false + }, + { + "name": "request", + "type": "Request", + "description": "- The HTTP request to validate against", + "optional": false + }, + { + "name": "opts", + "type": "Partial<{ iss: string; aud: string | string[]; leeway: number; jwksService: import(\"C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/types\").Fetcher; }>", + "description": "- Optional overrides for iss, aud, leeway", + "optional": true + } + ], + "visibility": "public", + "isAsync": true, + "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", + "lineNumber": 134 }, { "description": "Verify and authorize a JWT token with policy enforcement", @@ -699,7 +829,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", - "lineNumber": 142 + "lineNumber": 199 }, { "description": "Fluent builder for creating authorization policies", @@ -716,7 +846,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", - "lineNumber": 177 + "lineNumber": 234 }, { "description": "Clear the JWKS cache (for testing purposes)", @@ -855,7 +985,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts", - "lineNumber": 209 + "lineNumber": 211 }, { "description": "Get allowed thumbprints for key pinning (optional security measure)", @@ -871,7 +1001,7 @@ "visibility": "public", "isAsync": false, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/jwks.ts", - "lineNumber": 242 + "lineNumber": 244 }, { "id": "chrislyons_dev_flarelette_jwt__util__main", @@ -883,7 +1013,7 @@ "visibility": "private", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/keygen.ts", - "lineNumber": 15 + "lineNumber": 16 }, { "id": "chrislyons_dev_flarelette_jwt__util__generatesecret", @@ -1036,6 +1166,30 @@ "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts", "lineNumber": 47 }, + { + "description": "Compute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request.\n\nCanonical form: UTF-8(METHOD + \"\\n\" + pathname + search + \"\\n\") || body_bytes\n- Method is uppercased\n- Binds to path and query string only (not host/scheme — internal Workers use different hostnames)\n- Body is consumed from a clone to preserve the original stream", + "id": "chrislyons_dev_flarelette_jwt__util__computerequesthash", + "componentId": "chrislyons_dev_flarelette_jwt__util", + "name": "computeRequestHash", + "type": "function", + "documentation": { + "summary": "Compute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request.\n\nCanonical form: UTF-8(METHOD + \"\\n\" + pathname + search + \"\\n\") || body_bytes\n- Method is uppercased\n- Binds to path and query string only (not host/scheme — internal Workers use different hostnames)\n- Body is consumed from a clone to preserve the original stream" + }, + "returnType": "Promise", + "returnDescription": "base64url-encoded SHA-256 hash of the canonical request representation", + "parameters": [ + { + "name": "request", + "type": "Request", + "description": "- Fetch API Request object", + "optional": false + } + ], + "visibility": "public", + "isAsync": true, + "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/util.ts", + "lineNumber": 62 + }, { "description": "Resolve verification key from configured sources\n\nImplements key resolution strategy pattern:\n- Strategy 1: HS512 shared secret\n- Strategy 2: Inline public JWK\n- Strategy 3: Service binding JWKS\n- Strategy 4: HTTP JWKS URL", "id": "chrislyons_dev_flarelette_jwt__verify__resolveverificationkey", @@ -1094,7 +1248,7 @@ "visibility": "public", "isAsync": true, "filePath": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/verify.ts", - "lineNumber": 132 + "lineNumber": 131 }, { "description": "Store both environment variables and service bindings globally", @@ -1232,7 +1386,7 @@ "details": "Identifies a service acting on behalf of another principal.\nCan be nested for delegation chains.\n\nStructure:\n sub: Service identifier acting on behalf of original subject\n iss: The issuer of the actor token.\n act: Nested ActorClaim with same structure (recursive delegation chain)" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 49, + "lineNumber": 51, "metadata": { "language": "python", "baseClasses": [ @@ -1257,7 +1411,7 @@ "details": "Includes standard JWT claims, OIDC claims, and common custom claims.\nNote: At runtime, can contain any string key with JwtValue-compatible values,\nbut only defined fields get type checking." }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 68, + "lineNumber": 70, "metadata": { "language": "python", "baseClasses": [ @@ -1282,7 +1436,7 @@ "details": "Represents the complete configuration profile for JWT operations.\nEnvironment-driven: populated from JWT_* environment variables via profile() function.\nValidates against the JSON Schema at project root for consistency across languages." }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 110, + "lineNumber": 112, "metadata": { "language": "python", "baseClasses": [ @@ -1307,7 +1461,7 @@ "details": "Subset of JwtProfile containing the fields shared across all operations\n(signing, verification, policy checks). Extracted by common() function\nand merged with algorithm-specific configuration in profile()." }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 125, + "lineNumber": 127, "metadata": { "language": "python", "baseClasses": [ @@ -1343,7 +1497,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 139, + "lineNumber": 141, "metadata": { "language": "python", "decorators": [], @@ -1369,7 +1523,7 @@ "parameters": [], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 169, + "lineNumber": 182, "metadata": { "language": "python", "decorators": [], @@ -1402,7 +1556,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 183, + "lineNumber": 196, "metadata": { "language": "python", "decorators": [], @@ -1434,7 +1588,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 206, + "lineNumber": 219, "metadata": { "language": "python", "decorators": [], @@ -1455,7 +1609,7 @@ "parameters": [], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 213, + "lineNumber": 226, "metadata": { "language": "python", "decorators": [], @@ -1476,7 +1630,28 @@ "parameters": [], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", - "lineNumber": 228, + "lineNumber": 254, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": true + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__util__get_jwks_url", + "componentId": "flarelette_jwt__util", + "name": "get_jwks_url", + "type": "function", + "documentation": {}, + "returnType": "str | None", + "parameters": [], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\env.py", + "lineNumber": 258, "metadata": { "language": "python", "decorators": [], @@ -1552,7 +1727,7 @@ "details": "Attributes:\n iss: Token issuer (iss claim)\n aud: Token audience (aud claim) - can be string or list\n ttl_seconds: Token lifetime in seconds (default: 900 = 15 minutes)\n leeway: Clock skew tolerance in seconds for verification (default: 90)" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 25, + "lineNumber": 27, "metadata": { "language": "python", "baseClasses": [ @@ -1577,7 +1752,7 @@ "details": "Uses a shared secret for both signing and verification.\n\nAttributes:\n alg: Must be 'HS512'\n secret: Shared secret key as bytes (minimum 32 bytes)" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 41, + "lineNumber": 43, "metadata": { "language": "python", "baseClasses": [ @@ -1602,7 +1777,7 @@ "details": "Uses a private key to sign tokens.\n\nAttributes:\n alg: Must be 'EdDSA'\n private_jwk: Private JWK dictionary for signing\n kid: Key ID to include in JWT header (optional)" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 55, + "lineNumber": 57, "metadata": { "language": "python", "baseClasses": [ @@ -1627,7 +1802,55 @@ "details": "Uses a public key to verify tokens.\n\nAttributes:\n alg: Must be 'EdDSA'\n public_jwk: Public JWK dictionary for verification" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 71, + "lineNumber": 73, + "metadata": { + "language": "python", + "baseClasses": [ + "BaseJwtConfig" + ], + "decorators": [], + "decoratorDetails": [], + "isExported": true + } + }, + { + "description": "ES512 (ECDSA P-521) asymmetric configuration for verification.", + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit__es512verifyconfig", + "componentId": "flarelette_jwt__explicit", + "name": "ES512VerifyConfig", + "type": "class", + "documentation": { + "summary": "ES512 (ECDSA P-521) asymmetric configuration for verification." + }, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 87, + "metadata": { + "language": "python", + "baseClasses": [ + "BaseJwtConfig" + ], + "decorators": [], + "decoratorDetails": [], + "isExported": true + } + }, + { + "description": "Asymmetric verification configuration backed by a remote JWKS URL.", + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit__jwksurlverifyconfig", + "componentId": "flarelette_jwt__explicit", + "name": "JWKSUrlVerifyConfig", + "type": "class", + "documentation": { + "summary": "Asymmetric verification configuration backed by a remote JWKS URL." + }, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 94, "metadata": { "language": "python", "baseClasses": [ @@ -1652,7 +1875,7 @@ "details": "Attributes:\n require_all_permissions: All permissions must be present\n require_any_permission: At least one permission must be present\n require_roles_all: All roles must be present\n require_roles_any: At least one role must be present\n predicates: Custom predicate functions that must all return True" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 399, + "lineNumber": 582, "metadata": { "language": "python", "baseClasses": [ @@ -1677,7 +1900,7 @@ "details": "Returned when a token passes both verification and authorization.\n\nAttributes:\n sub: Subject identifier\n permissions: List of permission strings\n roles: List of role strings\n jti: JWT ID\n payload: Complete JWT payload" }, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 417, + "lineNumber": 600, "metadata": { "language": "python", "baseClasses": [ @@ -1710,7 +1933,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 90, + "lineNumber": 117, "metadata": { "language": "python", "decorators": [], @@ -1740,7 +1963,275 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 95, + "lineNumber": 122, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___validate_jwks_url", + "componentId": "flarelette_jwt__explicit", + "name": "_validate_jwks_url", + "type": "function", + "documentation": {}, + "returnType": "None", + "parameters": [ + { + "name": "url", + "type": "str", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 127, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___ecdsa_curve_name", + "componentId": "flarelette_jwt__explicit", + "name": "_ecdsa_curve_name", + "type": "function", + "documentation": {}, + "returnType": "str", + "parameters": [ + { + "name": "alg", + "type": "str", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 138, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___hash_name", + "componentId": "flarelette_jwt__explicit", + "name": "_hash_name", + "type": "function", + "documentation": {}, + "returnType": "str", + "parameters": [ + { + "name": "alg", + "type": "str", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 147, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___fetch_jwks_from_url", + "componentId": "flarelette_jwt__explicit", + "name": "_fetch_jwks_from_url", + "type": "function", + "documentation": {}, + "returnType": "list[dict[str, Any]]", + "parameters": [ + { + "name": "url", + "type": "str", + "optional": false + } + ], + "isAsync": true, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 159, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___find_jwk_by_kid", + "componentId": "flarelette_jwt__explicit", + "name": "_find_jwk_by_kid", + "type": "function", + "documentation": {}, + "returnType": "dict[str, Any] | None", + "parameters": [ + { + "name": "kid", + "type": "str | None", + "optional": false + }, + { + "name": "jwks", + "type": "list[dict[str, Any]]", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 189, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___import_verify_key", + "componentId": "flarelette_jwt__explicit", + "name": "_import_verify_key", + "type": "function", + "documentation": {}, + "returnType": "tuple[Any, dict[str, str]]", + "parameters": [ + { + "name": "alg", + "type": "str", + "optional": false + }, + { + "name": "jwk", + "type": "dict[str, Any]", + "optional": false + } + ], + "isAsync": true, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 200, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___has_public_jwk", + "componentId": "flarelette_jwt__explicit", + "name": "_has_public_jwk", + "type": "function", + "documentation": {}, + "returnType": "TypeGuard[EdDSAVerifyConfig | ES512VerifyConfig]", + "parameters": [ + { + "name": "config", + "type": "VerifyConfig", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 244, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___has_jwks_url", + "componentId": "flarelette_jwt__explicit", + "name": "_has_jwks_url", + "type": "function", + "documentation": {}, + "returnType": "TypeGuard[JWKSUrlVerifyConfig]", + "parameters": [ + { + "name": "config", + "type": "VerifyConfig", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 250, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": false + } + }, + { + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit___verify_asymmetric_signature", + "componentId": "flarelette_jwt__explicit", + "name": "_verify_asymmetric_signature", + "type": "function", + "documentation": {}, + "returnType": "bool", + "parameters": [ + { + "name": "header", + "type": "JwtHeader", + "optional": false + }, + { + "name": "signing_input", + "type": "bytes", + "optional": false + }, + { + "name": "sig", + "type": "bytes", + "optional": false + }, + { + "name": "jwk", + "type": "dict[str, Any]", + "optional": false + } + ], + "isAsync": true, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 254, "metadata": { "language": "python", "decorators": [], @@ -1782,7 +2273,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 100, + "lineNumber": 274, "metadata": { "language": "python", "decorators": [], @@ -1824,7 +2315,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 187, + "lineNumber": 364, "metadata": { "language": "python", "decorators": [], @@ -1863,7 +2354,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 296, + "lineNumber": 479, "metadata": { "language": "python", "decorators": [], @@ -1911,7 +2402,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 323, + "lineNumber": 506, "metadata": { "language": "python", "decorators": [], @@ -1960,7 +2451,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 437, + "lineNumber": 620, "metadata": { "language": "python", "decorators": [], @@ -1987,13 +2478,13 @@ { "name": "secret", "type": "str | bytes", - "description": "Base64url-encoded secret string or raw bytes (minimum 32 bytes)", + "description": "Base64url-encoded secret string or raw bytes (minimum 64 bytes)", "optional": false } ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 519, + "lineNumber": 702, "metadata": { "language": "python", "decorators": [], @@ -2026,7 +2517,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 561, + "lineNumber": 747, "metadata": { "language": "python", "decorators": [], @@ -2059,7 +2550,67 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 596, + "lineNumber": 782, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": true + } + }, + { + "description": "Helper function to create ES512 verify config from a public JWK.", + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit__create_es512_verify_config", + "componentId": "flarelette_jwt__explicit", + "name": "create_es512_verify_config", + "type": "function", + "documentation": { + "summary": "Helper function to create ES512 verify config from a public JWK." + }, + "returnType": "ES512VerifyConfig", + "parameters": [ + { + "name": "public_jwk", + "type": "dict[str, Any] | str", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 814, + "metadata": { + "language": "python", + "decorators": [], + "decoratorDetails": [], + "isExported": true + } + }, + { + "description": "Helper function to create JWKS URL verification config.", + "tags": [ + "Code" + ], + "id": "flarelette_jwt__explicit__create_jwks_url_verify_config", + "componentId": "flarelette_jwt__explicit", + "name": "create_jwks_url_verify_config", + "type": "function", + "documentation": { + "summary": "Helper function to create JWKS URL verification config." + }, + "returnType": "JWKSUrlVerifyConfig", + "parameters": [ + { + "name": "jwks_url", + "type": "str", + "optional": false + } + ], + "isAsync": false, + "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", + "lineNumber": 835, "metadata": { "language": "python", "decorators": [], @@ -2077,7 +2628,7 @@ "name": "SignConfig", "type": "type", "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 86, + "lineNumber": 103, "metadata": { "language": "python", "typeCategory": "TypeAlias", @@ -2095,11 +2646,11 @@ "name": "VerifyConfig", "type": "type", "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\explicit.py", - "lineNumber": 87, + "lineNumber": 104, "metadata": { "language": "python", "typeCategory": "TypeAlias", - "typeDefinition": "HS512Config | EdDSAVerifyConfig", + "typeDefinition": "HS512Config | EdDSAVerifyConfig | ES512VerifyConfig | JWKSUrlVerifyConfig", "isExported": true } }, @@ -3011,7 +3562,7 @@ ], "isAsync": false, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\verify.py", - "lineNumber": 29, + "lineNumber": 35, "metadata": { "language": "python", "decorators": [], @@ -3044,7 +3595,7 @@ ], "isAsync": true, "filePath": "C:\\Users\\chris\\git\\flarelette-jwt-kit\\packages\\flarelette-jwt-py\\flarelette_jwt\\verify.py", - "lineNumber": 33, + "lineNumber": 39, "metadata": { "language": "python", "decorators": [], @@ -3116,6 +3667,12 @@ "destination": "./verify.js", "stereotype": "import" }, + { + "description": "imports computeRequestHash", + "source": "chrislyons_dev_flarelette_jwt__util", + "destination": "./util.js", + "stereotype": "import" + }, { "description": "Fetcher | JwtPayload", "source": "chrislyons_dev_flarelette_jwt__util", @@ -3255,11 +3812,23 @@ "stereotype": "import" }, { - "description": "TYPE_CHECKING | Any | Literal | TypedDict", + "description": "TYPE_CHECKING | Any | Literal | TypedDict | TypeGuard", "source": "flarelette_jwt__explicit", "destination": "typing", "stereotype": "import" }, + { + "description": "urlparse", + "source": "flarelette_jwt__explicit", + "destination": "urllib.parse", + "stereotype": "import" + }, + { + "description": "urlopen", + "source": "flarelette_jwt__explicit", + "destination": "urllib.request", + "stereotype": "import" + }, { "description": "annotations", "source": "flarelette_jwt__util", @@ -3406,6 +3975,12 @@ "destination": "./verify.js:verify", "stereotype": "import" }, + { + "description": "imports computeRequestHash", + "source": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", + "destination": "./util.js:computeRequestHash", + "stereotype": "import" + }, { "description": "imports Fetcher", "source": "C:/Users/chris/git/flarelette-jwt-kit/packages/flarelette-jwt-ts/src/high.ts", diff --git a/docs/architecture/flarelette-jwt-kit.dsl b/docs/architecture/flarelette-jwt-kit.dsl index 5b5d1f4..3f525b1 100644 --- a/docs/architecture/flarelette-jwt-kit.dsl +++ b/docs/architecture/flarelette-jwt-kit.dsl @@ -10,7 +10,7 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { chrislyons_dev_flarelette_jwt = container "@chrislyons-dev/flarelette-jwt" { - description "Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection" + description "TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers" technology "Service" tags "Service,Auto-generated" @@ -24,7 +24,7 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "module" } chrislyons_dev_flarelette_jwt__util = component "util" { - description "High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys. This script generates EdDSA key pairs and exports them in JWK format. It is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. This module provides functions to generate secure secrets and validate base64url-encoded secrets. It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. It is designed to support core JWT functionalities." + description "High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA and ECDSA keys. Generates asymmetric key pairs and exports them in JWK format. Designed to be executed as a standalone Node.js script. | Secret generation and validation utilities. This module provides functions to generate secure secrets and validate base64url-encoded secrets. It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations. This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes. It is designed to support core JWT functionalities." technology "module" } chrislyons_dev_flarelette_jwt__main = component "main" { @@ -131,8 +131,17 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code" } + chrislyons_dev_flarelette_jwt__explicit__createes512signconfig = component "explicit.createES512SignConfig" { + description "Helper function to create ES512 sign config from a P-521 EC private JWK" + technology "function" + tags "Code" + } + chrislyons_dev_flarelette_jwt__explicit__createes512verifyconfig = component "explicit.createES512VerifyConfig" { + description "Helper function to create ES512 verify config from a P-521 EC public JWK" + technology "function" + tags "Code" + } chrislyons_dev_flarelette_jwt__explicit__createjwksurlverifyconfig = component "explicit.createJWKSUrlVerifyConfig" { - description "Helper function to create HTTP JWKS URL verification config Enables testing without environment variables by providing explicit configuration" technology "function" tags "Code" } @@ -146,6 +155,16 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code" } + chrislyons_dev_flarelette_jwt__util__signwithrequestbinding = component "util.signWithRequestBinding" { + description "Sign a JWT token bound to a specific HTTP request. Adds a `req` claim containing base64url(SHA-256(canonical request)) to prevent replay of a captured token against a different endpoint within the TTL window. Canonical form: METHOD + \"\\n\" + pathname + search + \"\\n\" + body bytes" + technology "function" + tags "Code" + } + chrislyons_dev_flarelette_jwt__util__verifywithrequestbinding = component "util.verifyWithRequestBinding" { + description "Verify a JWT token and validate its request binding. Re-computes the request hash and compares it with the `req` claim. Returns null on any mismatch (fail-silent, same as verify()). The `req` claim is stripped from the returned payload — it's an implementation detail that has already been validated." + technology "function" + tags "Code" + } chrislyons_dev_flarelette_jwt__util__checkauth = component "util.checkAuth" { description "Verify and authorize a JWT token with policy enforcement" technology "function" @@ -223,6 +242,11 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code" } + chrislyons_dev_flarelette_jwt__util__computerequesthash = component "util.computeRequestHash" { + description "Compute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request. Canonical form: UTF-8(METHOD + \"\\n\" + pathname + search + \"\\n\") || body_bytes - Method is uppercased - Binds to path and query string only (not host/scheme — internal Workers use different hostnames) - Body is consumed from a clone to preserve the original stream" + technology "function" + tags "Code" + } chrislyons_dev_flarelette_jwt__verify__resolveverificationkey = component "verify.resolveVerificationKey" { description "Resolve verification key from configured sources Implements key resolution strategy pattern: - Strategy 1: HS512 shared secret - Strategy 2: Inline public JWK - Strategy 3: Service binding JWKS - Strategy 4: HTTP JWKS URL" technology "function" @@ -264,7 +288,7 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { flarelette_jwt = container "flarelette-jwt" { - description "Environment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection" + description "Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers" technology "Service" tags "Service,Auto-generated" @@ -344,6 +368,10 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code,Code" } + flarelette_jwt__util__get_jwks_url = component "util.get_jwks_url" { + technology "function" + tags "Code,Code" + } flarelette_jwt__util__algtype = component "util.AlgType" { technology "type" tags "Code,Code,Type" @@ -376,6 +404,16 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "class" tags "Code,Code" } + flarelette_jwt__explicit__es512verifyconfig = component "explicit.ES512VerifyConfig" { + description "ES512 (ECDSA P-521) asymmetric configuration for verification." + technology "class" + tags "Code,Code" + } + flarelette_jwt__explicit__jwksurlverifyconfig = component "explicit.JWKSUrlVerifyConfig" { + description "Asymmetric verification configuration backed by a remote JWKS URL." + technology "class" + tags "Code,Code" + } flarelette_jwt__explicit__authzoptswithconfig = component "explicit.AuthzOptsWithConfig" { description "Authorization options for check_auth_with_config." technology "class" @@ -396,6 +434,42 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code,Code" } + flarelette_jwt__explicit___validate_jwks_url = component "explicit._validate_jwks_url" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___ecdsa_curve_name = component "explicit._ecdsa_curve_name" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___hash_name = component "explicit._hash_name" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___fetch_jwks_from_url = component "explicit._fetch_jwks_from_url" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___find_jwk_by_kid = component "explicit._find_jwk_by_kid" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___import_verify_key = component "explicit._import_verify_key" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___has_public_jwk = component "explicit._has_public_jwk" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___has_jwks_url = component "explicit._has_jwks_url" { + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit___verify_asymmetric_signature = component "explicit._verify_asymmetric_signature" { + technology "function" + tags "Code,Code" + } flarelette_jwt__explicit__sign_with_config = component "explicit.sign_with_config" { description "Sign a JWT token with explicit configuration." technology "function" @@ -436,6 +510,16 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { technology "function" tags "Code,Code" } + flarelette_jwt__explicit__create_es512_verify_config = component "explicit.create_es512_verify_config" { + description "Helper function to create ES512 verify config from a public JWK." + technology "function" + tags "Code,Code" + } + flarelette_jwt__explicit__create_jwks_url_verify_config = component "explicit.create_jwks_url_verify_config" { + description "Helper function to create JWKS URL verification config." + technology "function" + tags "Code,Code" + } flarelette_jwt__explicit__signconfig = component "explicit.SignConfig" { technology "type" tags "Code,Code,Type" @@ -590,197 +674,15 @@ workspace "flarelette-jwt-kit" "JWT authentication and authorization library" { } views { -/** - * Default Structurizr theme for Archlette - * - * This theme provides a modern, professional color scheme for architecture diagrams - * with clear visual hierarchy and accessibility considerations. - */ - -theme default - -// Element styles -styles { - // Person/Actor styles - element "Person" { - background #08427b - color #ffffff - shape Person - fontSize 22 - } - - // External System styles - element "External System" { - background #999999 - color #ffffff - shape RoundedBox - fontSize 22 - } - - element "External" { - background #999999 - color #ffffff - shape RoundedBox - fontSize 22 - } - - // System styles - element "Software System" { - background #1168bd - color #ffffff - shape RoundedBox - fontSize 24 - } - - // Container styles - element "Container" { - background #438dd5 - color #ffffff - shape RoundedBox - fontSize 20 - } - - element "Database" { - background #438dd5 - color #ffffff - shape Cylinder - fontSize 20 - } - - element "Web Browser" { - background #438dd5 - color #ffffff - shape WebBrowser - fontSize 20 - } - - element "Mobile App" { - background #438dd5 - color #ffffff - shape MobileDevicePortrait - fontSize 20 - } - - // Component styles - element "Component" { - background #85bbf0 - color #000000 - shape RoundedBox - fontSize 18 - } - - // Technology-specific styles - element "Cloudflare Worker" { - background #f6821f - color #ffffff - shape RoundedBox - fontSize 18 - } - - element "Service" { - background #438dd5 - color #ffffff - shape RoundedBox - fontSize 18 - } - - element "API" { - background #85bbf0 - color #000000 - shape Hexagon - fontSize 18 - } - - element "Queue" { - background #85bbf0 - color #000000 - shape Pipe - fontSize 18 - } - - // Tag-based styles - element "Internal System" { - background #1168bd - color #ffffff - } - - element "Deprecated" { - background #cc0000 - color #ffffff - opacity 60 - } - - element "Future" { - background #dddddd - color #000000 - opacity 50 - stroke #999999 - strokeWidth 2 - } - - element "Auto Generated" { - stroke #999999 - strokeWidth 1 - } - - // Infrastructure styles - element "Infrastructure" { - background #92278f - color #ffffff - shape RoundedBox - } - - element "Message Bus" { - background #85bbf0 - color #000000 - shape Pipe - } - - // Relationship styles - relationship "Relationship" { - color #707070 - dashed false - routing Curved - fontSize 12 - thickness 2 - } - - relationship "Async" { - dashed true - color #707070 - } - - relationship "Sync" { - dashed false - color #707070 - } - - relationship "Uses" { - color #707070 - dashed false - } - - relationship "Depends On" { - color #707070 - dashed true - } -} - -// Diagram customization -branding { - font "Arial" -} - - systemContext flarelette_jwt_kit "SystemContext" { include flarelette_jwt_kit - autoLayout + autoLayout lr 100 100 } container flarelette_jwt_kit "Containers" { include chrislyons_dev_flarelette_jwt include flarelette_jwt - autoLayout + autoLayout lr 100 100 } @@ -794,7 +696,7 @@ branding { include chrislyons_dev_flarelette_jwt__verify include chrislyons_dev_flarelette_jwt__adapters exclude "element.tag==Code" - autoLayout + autoLayout lr 100 100 } @@ -804,7 +706,7 @@ branding { include flarelette_jwt__explicit include flarelette_jwt__flarelette_jwt exclude "element.tag==Code" - autoLayout + autoLayout lr 100 100 } @@ -820,7 +722,7 @@ branding { include chrislyons_dev_flarelette_jwt__core__getjwksurl include chrislyons_dev_flarelette_jwt__core__getjwkscachettl include chrislyons_dev_flarelette_jwt__core__sign - autoLayout + autoLayout lr 100 100 } @@ -833,14 +735,18 @@ branding { include chrislyons_dev_flarelette_jwt__explicit__createhs512config include chrislyons_dev_flarelette_jwt__explicit__createeddsasignconfig include chrislyons_dev_flarelette_jwt__explicit__createeddsaverifyconfig + include chrislyons_dev_flarelette_jwt__explicit__createes512signconfig + include chrislyons_dev_flarelette_jwt__explicit__createes512verifyconfig include chrislyons_dev_flarelette_jwt__explicit__createjwksurlverifyconfig - autoLayout + autoLayout lr 100 100 } component chrislyons_dev_flarelette_jwt "Classes_chrislyons_dev_flarelette_jwt__util" { include chrislyons_dev_flarelette_jwt__util__createtoken include chrislyons_dev_flarelette_jwt__util__createdelegatedtoken + include chrislyons_dev_flarelette_jwt__util__signwithrequestbinding + include chrislyons_dev_flarelette_jwt__util__verifywithrequestbinding include chrislyons_dev_flarelette_jwt__util__checkauth include chrislyons_dev_flarelette_jwt__util__policy include chrislyons_dev_flarelette_jwt__util__main @@ -849,7 +755,8 @@ branding { include chrislyons_dev_flarelette_jwt__util__parse include chrislyons_dev_flarelette_jwt__util__isexpiringsoon include chrislyons_dev_flarelette_jwt__util__mapscopestopermissions - autoLayout + include chrislyons_dev_flarelette_jwt__util__computerequesthash + autoLayout lr 100 100 } @@ -861,14 +768,14 @@ branding { include chrislyons_dev_flarelette_jwt__jwks__fetchjwksfromurl include chrislyons_dev_flarelette_jwt__jwks__getkeyfromjwks include chrislyons_dev_flarelette_jwt__jwks__allowedthumbprints - autoLayout + autoLayout lr 100 100 } component chrislyons_dev_flarelette_jwt "Classes_chrislyons_dev_flarelette_jwt__verify" { include chrislyons_dev_flarelette_jwt__verify__resolveverificationkey include chrislyons_dev_flarelette_jwt__verify__verify - autoLayout + autoLayout lr 100 100 } @@ -876,13 +783,13 @@ branding { include chrislyons_dev_flarelette_jwt__adapters__bindenv include chrislyons_dev_flarelette_jwt__adapters__getservicebinding include chrislyons_dev_flarelette_jwt__adapters__makekit - autoLayout + autoLayout lr 100 100 } component flarelette_jwt "Classes_flarelette_jwt__adapters" { include flarelette_jwt__adapters__apply_env_bindings - autoLayout + autoLayout lr 100 100 } @@ -898,6 +805,7 @@ branding { include flarelette_jwt__util___get_indirect include flarelette_jwt__util__get_hs_secret_bytes include flarelette_jwt__util__get_public_jwk_string + include flarelette_jwt__util__get_jwks_url include flarelette_jwt__util__algtype include flarelette_jwt__util__jwtvalue include flarelette_jwt__util__claimsdict @@ -933,7 +841,7 @@ branding { include flarelette_jwt__util__map_scopes_to_permissions include flarelette_jwt__util___b64url_decode include flarelette_jwt__util__verify - autoLayout + autoLayout lr 100 100 } @@ -942,10 +850,21 @@ branding { include flarelette_jwt__explicit__hs512config include flarelette_jwt__explicit__eddsasignconfig include flarelette_jwt__explicit__eddsaverifyconfig + include flarelette_jwt__explicit__es512verifyconfig + include flarelette_jwt__explicit__jwksurlverifyconfig include flarelette_jwt__explicit__authzoptswithconfig include flarelette_jwt__explicit__authuser include flarelette_jwt__explicit___b64url include flarelette_jwt__explicit___b64url_decode + include flarelette_jwt__explicit___validate_jwks_url + include flarelette_jwt__explicit___ecdsa_curve_name + include flarelette_jwt__explicit___hash_name + include flarelette_jwt__explicit___fetch_jwks_from_url + include flarelette_jwt__explicit___find_jwk_by_kid + include flarelette_jwt__explicit___import_verify_key + include flarelette_jwt__explicit___has_public_jwk + include flarelette_jwt__explicit___has_jwks_url + include flarelette_jwt__explicit___verify_asymmetric_signature include flarelette_jwt__explicit__sign_with_config include flarelette_jwt__explicit__verify_with_config include flarelette_jwt__explicit__create_token_with_config @@ -954,11 +873,237 @@ branding { include flarelette_jwt__explicit__create_hs512_config include flarelette_jwt__explicit__create_eddsa_sign_config include flarelette_jwt__explicit__create_eddsa_verify_config + include flarelette_jwt__explicit__create_es512_verify_config + include flarelette_jwt__explicit__create_jwks_url_verify_config include flarelette_jwt__explicit__signconfig include flarelette_jwt__explicit__verifyconfig - autoLayout + autoLayout lr 100 100 } + +/** + * Default Structurizr theme for Archlette + * + * This theme provides a modern, professional color scheme for architecture diagrams + * with clear visual hierarchy and accessibility considerations. + */ + +theme default + +// Element styles +styles { + // Person/Actor styles + element "Person" { + background #08427b + color #ffffff + shape Person + width 200 + height 120 + fontSize 14 + } + + // External System styles + element "External System" { + background #999999 + color #ffffff + shape RoundedBox + width 240 + height 140 + fontSize 14 + } + + element "External" { + background #999999 + color #ffffff + shape RoundedBox + width 240 + height 140 + fontSize 14 + } + + // System styles + element "Software System" { + background #1168bd + color #ffffff + shape RoundedBox + width 280 + height 160 + fontSize 16 + } + + // Container styles + element "Container" { + background #438dd5 + color #ffffff + shape RoundedBox + width 260 + height 150 + fontSize 14 + } + + element "Database" { + background #438dd5 + color #ffffff + shape Cylinder + width 200 + height 140 + fontSize 14 + } + + element "Web Browser" { + background #438dd5 + color #ffffff + shape WebBrowser + width 240 + height 150 + fontSize 14 + } + + element "Mobile App" { + background #438dd5 + color #ffffff + shape MobileDevicePortrait + width 180 + height 200 + fontSize 14 + } + + // Component styles + element "Component" { + background #85bbf0 + color #000000 + shape RoundedBox + width 220 + height 130 + fontSize 12 + } + + // Code element styles (classes, functions, etc.) + element "Code" { + background #d4e8fc + color #000000 + shape RoundedBox + width 200 + height 100 + fontSize 11 + } + + // Technology-specific styles + element "Cloudflare Worker" { + background #f6821f + color #ffffff + shape RoundedBox + width 220 + height 130 + fontSize 12 + } + + element "Service" { + background #438dd5 + color #ffffff + shape RoundedBox + width 220 + height 130 + fontSize 12 + } + + element "API" { + background #85bbf0 + color #000000 + shape Hexagon + width 180 + height 120 + fontSize 12 + } + + element "Queue" { + background #85bbf0 + color #000000 + shape Pipe + width 200 + height 100 + fontSize 12 + } + + // Tag-based styles + element "Internal System" { + background #1168bd + color #ffffff + } + + element "Deprecated" { + background #cc0000 + color #ffffff + opacity 60 + } + + element "Future" { + background #dddddd + color #000000 + opacity 50 + stroke #999999 + strokeWidth 2 + } + + element "Auto Generated" { + stroke #999999 + strokeWidth 1 + } + + // Infrastructure styles + element "Infrastructure" { + background #92278f + color #ffffff + shape RoundedBox + width 220 + height 130 + fontSize 12 + } + + element "Message Bus" { + background #85bbf0 + color #000000 + shape Pipe + width 200 + height 100 + fontSize 12 + } + + // Relationship styles + relationship "Relationship" { + color #707070 + dashed false + routing Curved + fontSize 12 + thickness 2 + } + + relationship "Async" { + dashed true + color #707070 + } + + relationship "Sync" { + dashed false + color #707070 + } + + relationship "Uses" { + color #707070 + dashed false + } + + relationship "Depends On" { + color #707070 + dashed true + } +} + +// Diagram customization +branding { + font "Arial" +} + } } diff --git a/docs/architecture/flarelette_jwt.md b/docs/architecture/flarelette_jwt.md index 703177b..55f04b5 100644 --- a/docs/architecture/flarelette_jwt.md +++ b/docs/architecture/flarelette_jwt.md @@ -6,33 +6,17 @@ ## Container Context -![Container Diagram](./diagrams/structurizr-Containers.png) +Container Diagram --- ## Container Information - - - - - - - - - - - - - - - - - - - -
Nameflarelette-jwt
TypeService
DescriptionEnvironment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection
TagsAuto-generated
- +| Field | Value | +| --- | --- | +| **Name** | flarelette-jwt | +| **Type** | `Service` | +| **Description** | Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers || **Tags** | `Auto-generated` | --- ## Components @@ -40,58 +24,17 @@ ### Component View -![Component Diagram](./diagrams/structurizr-Components_flarelette_jwt.png) -![Component Diagram](./diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png) +Component Diagram +Component Diagram ### Component Details - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ComponentTypeDescriptionCode
adaptersmoduleAdapters for Cloudflare Workers Environment - -This module provides utilities to adapt Cloudflare Workers environment variables -for use with the Flarelette JWT library.View →
utilmoduleEnvironment Configuration for JWT Operations - -This module provides functions to read environment variables and derive JWT-related configurations. -It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms.View →
explicitmoduleExplicit Configuration API for JWT Operations - -This module provides functions that accept explicit configuration objects -instead of relying on environment variables or global state. Use this API -when you need full control over configuration, especially in development -environments or when working with multiple JWT configurations.View →
flarelette_jwtmoduleComponent derived from directory: flarelette_jwtView →
+| Component | Type | Description | Code | +| --- | --- | --- | --- | +| **adapters** | `module` | Adapters for Cloudflare Workers Environment

This module provides utilities to adapt Cloudflare Workers environment variables
for use with the Flarelette JWT library. | [View](./flarelette_jwt__adapters.md) | +| **util** | `module` | Environment Configuration for JWT Operations

This module provides functions to read environment variables and derive JWT-related configurations.
It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms. | [View](./flarelette_jwt__util.md) | +| **explicit** | `module` | Explicit Configuration API for JWT Operations

This module provides functions that accept explicit configuration objects
instead of relying on environment variables or global state. Use this API
when you need full control over configuration, especially in development
environments or when working with multiple JWT configurations. | [View](./flarelette_jwt__explicit.md) | +| **flarelette_jwt** | `module` | Component derived from directory: flarelette_jwt | [View](./flarelette_jwt__flarelette_jwt.md) | --- @@ -99,3 +42,4 @@ environments or when working with multiple JWT configurations. + diff --git a/docs/architecture/flarelette_jwt__adapters.md b/docs/architecture/flarelette_jwt__adapters.md index 054baec..636d159 100644 --- a/docs/architecture/flarelette_jwt__adapters.md +++ b/docs/architecture/flarelette_jwt__adapters.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentadapters
Containerflarelette-jwt
Typemodule
DescriptionAdapters for Cloudflare Workers Environment - -This module provides utilities to adapt Cloudflare Workers environment variables -for use with the Flarelette JWT library.
- +| Field | Value | +| --- | --- | +| **Component** | adapters | +| **Container** | flarelette-jwt | +| **Type** | `module` | +| **Description** | Adapters for Cloudflare Workers Environment

This module provides utilities to adapt Cloudflare Workers environment variables
for use with the Flarelette JWT library. | --- ## Code Structure @@ -52,26 +34,11 @@ for use with the Flarelette JWT library. Copy a Cloudflare Worker `env` mapping into os.environ so the kit can read it. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsNone
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\adapters.py:15
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\adapters.py:15` | **Parameters:** @@ -86,3 +53,4 @@ Copy a Cloudflare Worker `env` mapping into os.environ so the kit can read it. + diff --git a/docs/architecture/flarelette_jwt__explicit.md b/docs/architecture/flarelette_jwt__explicit.md index 2fcf656..22af758 100644 --- a/docs/architecture/flarelette_jwt__explicit.md +++ b/docs/architecture/flarelette_jwt__explicit.md @@ -6,32 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentexplicit
Containerflarelette-jwt
Typemodule
DescriptionExplicit Configuration API for JWT Operations - -This module provides functions that accept explicit configuration objects -instead of relying on environment variables or global state. Use this API -when you need full control over configuration, especially in development -environments or when working with multiple JWT configurations.
- +| Field | Value | +| --- | --- | +| **Component** | explicit | +| **Container** | flarelette-jwt | +| **Type** | `module` | +| **Description** | Explicit Configuration API for JWT Operations

This module provides functions that accept explicit configuration objects
instead of relying on environment variables or global state. Use this API
when you need full control over configuration, especially in development
environments or when working with multiple JWT configurations. | --- ## Code Structure @@ -44,7 +24,7 @@ environments or when working with multiple JWT configurations. ### Code Elements
-18 code element(s) +31 code element(s) #### Classes @@ -53,22 +33,11 @@ environments or when working with multiple JWT configurations. Base JWT configuration shared by HS512 and EdDSA modes. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:25
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:27` | --- @@ -76,22 +45,11 @@ Base JWT configuration shared by HS512 and EdDSA modes. HS512 (HMAC-SHA512) symmetric configuration. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:41
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:43` | --- @@ -99,22 +57,11 @@ HS512 (HMAC-SHA512) symmetric configuration. EdDSA (Ed25519) asymmetric configuration for signing. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:55
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:57` | --- @@ -122,22 +69,35 @@ EdDSA (Ed25519) asymmetric configuration for signing. EdDSA (Ed25519) asymmetric configuration for verification. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:71
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:73` | + + +--- +##### `ES512VerifyConfig` + +ES512 (ECDSA P-521) asymmetric configuration for verification. + +| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:87` | + + +--- +##### `JWKSUrlVerifyConfig` + +Asymmetric verification configuration backed by a remote JWKS URL. + +| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:94` | --- @@ -145,22 +105,11 @@ EdDSA (Ed25519) asymmetric configuration for verification. Authorization options for check_auth_with_config. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:399
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:582` | --- @@ -168,22 +117,11 @@ Authorization options for check_auth_with_config. Authenticated user information. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:417
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:600` | --- @@ -194,26 +132,11 @@ Authenticated user information. Encode bytes to base64url without padding. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsstr
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:90
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:117` | **Parameters:** @@ -224,60 +147,152 @@ Encode bytes to base64url without padding. Decode base64url string (with or without padding). - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsbytes
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:95
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `bytes` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:122` | **Parameters:** - `s`: str +--- +##### `_validate_jwks_url()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:127` | + +**Parameters:** + +- `url`: str + +--- +##### `_ecdsa_curve_name()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:138` | + +**Parameters:** + +- `alg`: str + +--- +##### `_hash_name()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:147` | + +**Parameters:** + +- `alg`: str + +--- +##### `_fetch_jwks_from_url()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `list[dict[str, Any]]` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:159` | + +**Parameters:** + +- `url`: str + +--- +##### `_find_jwk_by_kid()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `dict[str, Any] \| None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:189` | + +**Parameters:** + +- `kid`: str | None- `jwks`: list[dict[str, Any]] + +--- +##### `_import_verify_key()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `tuple[Any, dict[str, str]]` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:200` | + +**Parameters:** + +- `alg`: str- `jwk`: dict[str, Any] + +--- +##### `_has_public_jwk()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `TypeGuard[EdDSAVerifyConfig \| ES512VerifyConfig]` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:244` | + +**Parameters:** + +- `config`: VerifyConfig + +--- +##### `_has_jwks_url()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `TypeGuard[JWKSUrlVerifyConfig]` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:250` | + +**Parameters:** + +- `config`: VerifyConfig + +--- +##### `_verify_asymmetric_signature()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `bool` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:254` | + +**Parameters:** + +- `header`: JwtHeader- `signing_input`: bytes- `sig`: bytes- `jwk`: dict[str, Any] + --- ##### `sign_with_config()` Sign a JWT token with explicit configuration. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:100
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:274` | **Parameters:** @@ -292,30 +307,11 @@ Sign a JWT token with explicit configuration. Verify a JWT token with explicit configuration. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
ReturnsJwtPayload | None — Payload if valid, None if invalid
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:187
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `JwtPayload \| None` - Payload if valid, None if invalid || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:364` | **Parameters:** @@ -330,30 +326,11 @@ Verify a JWT token with explicit configuration. Create a signed JWT token with explicit configuration. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:296
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:479` | **Parameters:** @@ -364,30 +341,11 @@ Create a signed JWT token with explicit configuration. Create a delegated JWT token with explicit configuration. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string with delegation claim
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:323
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string with delegation claim || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:506` | **Parameters:** @@ -402,30 +360,11 @@ Create a delegated JWT token with explicit configuration. Verify and authorize a JWT token with explicit configuration. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
ReturnsAuthUser | None — AuthUser if valid and authorized, None otherwise
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:437
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `AuthUser \| None` - AuthUser if valid and authorized, None otherwise || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:620` | **Parameters:** @@ -440,56 +379,26 @@ Verify and authorize a JWT token with explicit configuration. Helper function to create HS512 config from base64url-encoded secret. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsHS512Config — HS512Config
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:519
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `HS512Config` - HS512Config || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:702` | **Parameters:** -- `secret`: str | bytes — Base64url-encoded secret string or raw bytes (minimum 32 bytes) +- `secret`: str | bytes — Base64url-encoded secret string or raw bytes (minimum 64 bytes) --- ##### `create_eddsa_sign_config()` Helper function to create EdDSA sign config from JWK. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsEdDSASignConfig — EdDSASignConfig
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:561
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `EdDSASignConfig` - EdDSASignConfig || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:747` | **Parameters:** @@ -500,31 +409,46 @@ Helper function to create EdDSA sign config from JWK. Helper function to create EdDSA verify config from JWK. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsEdDSAVerifyConfig — EdDSAVerifyConfig
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:596
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `EdDSAVerifyConfig` - EdDSAVerifyConfig || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:782` | **Parameters:** - `public_jwk`: dict[str, Any] | str — Public JWK dictionary or JSON string +--- +##### `create_es512_verify_config()` + +Helper function to create ES512 verify config from a public JWK. + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `ES512VerifyConfig` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:814` | + +**Parameters:** + +- `public_jwk`: dict[str, Any] | str + +--- +##### `create_jwks_url_verify_config()` + +Helper function to create JWKS URL verification config. + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `JWKSUrlVerifyConfig` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\explicit.py:835` | + +**Parameters:** + +- `jwks_url`: str + ---
@@ -534,3 +458,4 @@ Helper function to create EdDSA verify config from JWK. + diff --git a/docs/architecture/flarelette_jwt__flarelette_jwt.md b/docs/architecture/flarelette_jwt__flarelette_jwt.md index 99e412c..6ae42e6 100644 --- a/docs/architecture/flarelette_jwt__flarelette_jwt.md +++ b/docs/architecture/flarelette_jwt__flarelette_jwt.md @@ -6,27 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentflarelette_jwt
Containerflarelette-jwt
Typemodule
DescriptionComponent derived from directory: flarelette_jwt
- +| Field | Value | +| --- | --- | +| **Component** | flarelette_jwt | +| **Container** | flarelette-jwt | +| **Type** | `module` | +| **Description** | Component derived from directory: flarelette_jwt | --- ## Code Structure @@ -41,3 +26,4 @@ + diff --git a/docs/architecture/flarelette_jwt__util.md b/docs/architecture/flarelette_jwt__util.md index 069cad5..ede7f1e 100644 --- a/docs/architecture/flarelette_jwt__util.md +++ b/docs/architecture/flarelette_jwt__util.md @@ -6,30 +6,12 @@ ## Component Information - - - - - - - - - - - - - - - - - - - -
Componentutil
Containerflarelette-jwt
Typemodule
DescriptionEnvironment Configuration for JWT Operations - -This module provides functions to read environment variables and derive JWT-related configurations. -It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms.
- +| Field | Value | +| --- | --- | +| **Component** | util | +| **Container** | flarelette-jwt | +| **Type** | `module` | +| **Description** | Environment Configuration for JWT Operations

This module provides functions to read environment variables and derive JWT-related configurations.
It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms. | --- ## Code Structure @@ -42,7 +24,7 @@ It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms. ### Code Elements
-46 code element(s) +47 code element(s) #### Classes @@ -51,22 +33,11 @@ It supports both symmetric (HS512) and asymmetric (EdDSA) algorithms. JWT token header structure. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:35
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:35` | --- @@ -74,22 +45,11 @@ JWT token header structure. Actor claim for service delegation (RFC 8693). - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:49
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:51` | --- @@ -97,22 +57,11 @@ Actor claim for service delegation (RFC 8693). JWT token payload/claims structure. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:68
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:70` | --- @@ -120,22 +69,11 @@ JWT token payload/claims structure. JWT Profile structure matching flarelette-jwt.profile.schema.json. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:110
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:112` | --- @@ -143,22 +81,11 @@ JWT Profile structure matching flarelette-jwt.profile.schema.json. Common JWT configuration from environment variables. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:125
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:127` | --- @@ -166,22 +93,11 @@ Common JWT configuration from environment variables. Authenticated user information returned by check_auth. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:24
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:24` | --- @@ -189,44 +105,22 @@ Authenticated user information returned by check_auth. Builder interface for creating JWT authorization policies. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:40
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:40` | --- ##### `Builder` - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:227
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:227` | --- @@ -234,22 +128,11 @@ Builder interface for creating JWT authorization policies. Parsed JWT token structure. - - - - - - - - - - - - - - - -
Typeclass
Visibility
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:19
+| Field | Value | +| --- | --- | +| **Type** | `class` | +| **Visibility** | `-` | +| **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:19` | --- @@ -260,26 +143,11 @@ Parsed JWT token structure. Detect JWT algorithm mode from environment variables based on role. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsAlgType — Either "HS512" or "EdDSA"
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:139
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `AlgType` - Either "HS512" or "EdDSA" || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:141` | **Parameters:** @@ -290,26 +158,11 @@ Detect JWT algorithm mode from environment variables based on role. Get common JWT configuration from environment. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsJwtCommonConfig — Configuration with iss, aud, leeway, ttl_seconds
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:169
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `JwtCommonConfig` - Configuration with iss, aud, leeway, ttl_seconds || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:182` | @@ -318,26 +171,11 @@ Get common JWT configuration from environment. Get JWT profile from environment. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsdict[str, Any] — dict containing alg, iss, aud, leeway_seconds, and ttl_seconds
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:183
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `dict[str, Any]` - dict containing alg, iss, aud, leeway_seconds, and ttl_seconds || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:196` | **Parameters:** @@ -347,26 +185,11 @@ Get JWT profile from environment. ##### `_get_indirect()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsstr | None
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:206
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str \| None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:219` | **Parameters:** @@ -376,26 +199,11 @@ Get JWT profile from environment. ##### `get_hs_secret_bytes()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsbytes
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:213
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `bytes` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:226` | @@ -403,26 +211,23 @@ Get JWT profile from environment. ##### `get_public_jwk_string()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsstr | None
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:228
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str \| None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:254` | + + + +--- +##### `get_jwks_url()` + + +| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str \| None` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\env.py:258` | @@ -431,30 +236,11 @@ Get JWT profile from environment. Create a signed JWT token with optional claims. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:58
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:58` | **Parameters:** @@ -465,34 +251,11 @@ Create a signed JWT token with optional claims. Create a delegated JWT token following RFC 8693 actor claim pattern. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string with delegation claim - -See Also: - - RFC 8693: OAuth 2.0 Token Exchange - - security.md: Service Delegation Pattern section
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:79
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string with delegation claim

See Also:
- RFC 8693: OAuth 2.0 Token Exchange
- security.md: Service Delegation Pattern section || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:79` | **Parameters:** @@ -507,30 +270,11 @@ See Also: Verify and authorize a JWT token with policy enforcement. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
ReturnsAuthUser | None — AuthUser if valid and authorized, None otherwise
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:166
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `AuthUser \| None` - AuthUser if valid and authorized, None otherwise || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:166` | **Parameters:** @@ -541,26 +285,11 @@ Verify and authorize a JWT token with policy enforcement. Fluent builder for creating authorization policies. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsPolicyBuilder — PolicyBuilder with chainable methods
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:219
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `PolicyBuilder` - PolicyBuilder with chainable methods || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\high.py:219` | @@ -568,26 +297,11 @@ Fluent builder for creating authorization policies. ##### `generate_secret()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsstr
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:18
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:18` | **Parameters:** @@ -597,26 +311,11 @@ Fluent builder for creating authorization policies. ##### `is_valid_base64url_secret()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsbool
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:23
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `bool` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:23` | **Parameters:** @@ -626,26 +325,11 @@ Fluent builder for creating authorization policies. ##### `main()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsint
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:32
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `int` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\secret.py:32` | **Parameters:** @@ -655,26 +339,11 @@ Fluent builder for creating authorization policies. ##### `_b64url()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsstr
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\sign.py:21
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `str` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\sign.py:21` | **Parameters:** @@ -685,30 +354,11 @@ Fluent builder for creating authorization policies. Sign a JWT token with HS512 or EdDSA algorithm. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
Returnsstr — Signed JWT token string
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\sign.py:25
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `str` - Signed JWT token string || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\sign.py:25` | **Parameters:** @@ -719,26 +369,11 @@ Sign a JWT token with HS512 or EdDSA algorithm. Parse a JWT token into header and payload without verification. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
ReturnsParsedJwt — Dictionary with 'header' and 'payload' keys
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:31
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `ParsedJwt` - Dictionary with 'header' and 'payload' keys || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:31` | **Parameters:** @@ -749,26 +384,11 @@ Parse a JWT token into header and payload without verification. Check if JWT payload will expire within specified seconds. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsbool — True if token expires within the threshold
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:49
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `bool` - True if token expires within the threshold || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:49` | **Parameters:** @@ -779,26 +399,11 @@ Check if JWT payload will expire within specified seconds. Map OAuth scopes to permission strings. - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnslist[str] — List of permission strings (currently identity mapping)
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:63
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `list[str]` - List of permission strings (currently identity mapping) || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\util.py:63` | **Parameters:** @@ -808,26 +413,11 @@ Map OAuth scopes to permission strings. ##### `_b64url_decode()` - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
Returnsbytes
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\verify.py:29
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Returns** | `bytes` || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\verify.py:35` | **Parameters:** @@ -838,30 +428,11 @@ Map OAuth scopes to permission strings. Verify a JWT token with HS512 or EdDSA algorithm. - - - - - - - - - - - - - - - - - - - - - - - -
Typefunction
Visibility
AsyncYes
ReturnsJwtPayload | None — Decoded payload if valid, None otherwise
LocationC:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\verify.py:33
+| Field | Value | +| --- | --- | +| **Type** | `function` | +| **Visibility** | `-` | +| **Async** | Yes || **Returns** | `JwtPayload \| None` - Decoded payload if valid, None otherwise || **Location** | `C:\Users\chris\git\flarelette-jwt-kit\packages\flarelette-jwt-py\flarelette_jwt\verify.py:39` | **Parameters:** @@ -876,3 +447,4 @@ Verify a JWT token with HS512 or EdDSA algorithm. + diff --git a/docs/cloudflare-workers.md b/docs/cloudflare-workers.md index dcb9885..78cb7f3 100644 --- a/docs/cloudflare-workers.md +++ b/docs/cloudflare-workers.md @@ -1,4 +1,4 @@ -# Cloudflare Workers +# Deployment Deploy Flarelette JWT Kit to Cloudflare Workers with proper secret management and service bindings. @@ -354,6 +354,126 @@ export default app wrangler deploy --config wrangler.consumer.toml ``` +## Internal JWKS via Service Binding + +Service bindings are the right way to distribute keys inside a Cloudflare mesh — not public HTTPS endpoints. + +### Why not a public JWKS endpoint? + +Exposing JWKS over HTTPS creates unnecessary public surface: + +- Any client on the internet can discover your key material +- You need TLS termination, DNS, and public routing just for internal key distribution +- It invites SSRF probes and unsolicited JWKS abuse + +Service bindings keep the JWKS exchange internal: Worker-to-Worker RPC, no internet route, no DNS round-trip. + +### How it works + +`makeKit(env)` automatically detects a service binding when `JWT_JWKS_SERVICE_NAME` is set. It reads the binding name from the env, fetches `/.well-known/jwks.json` from the gateway Worker via RPC, caches the result for 5 minutes, and uses the matching key to verify the token. + +### Gateway setup + +Expose the JWKS on an internal-only route (no public `[[routes]]` entry): + +**`src/gateway.ts` (relevant excerpt):** + +```typescript +import { Hono } from 'hono' +import { makeKit } from '@chrislyons-dev/flarelette-jwt/adapters/hono' + +const app = new Hono() + +app.use('*', async (c, next) => { + c.set('jwt', makeKit(c.env)) + await next() +}) + +// Internal JWKS — only reachable via service binding, not public internet +app.get('/.well-known/jwks.json', async c => { + const publicJwk = JSON.parse(c.env.GATEWAY_PUBLIC) + return c.json({ keys: [publicJwk] }) +}) + +export default app +``` + +**`wrangler.gateway.toml`:** + +```toml +name = "jwt-gateway" +main = "src/gateway.ts" + +[vars] +JWT_PRIVATE_JWK_NAME = "GATEWAY_PRIVATE" +JWT_PUBLIC_JWK_NAME = "GATEWAY_PUBLIC" +JWT_KID = "ed25519-2025-01" +JWT_ISS = "https://gateway.internal" +JWT_AUD = "internal-api" +``` + +```bash +npx flarelette-jwt-keygen --kid=ed25519-2025-01 > keys.json +wrangler secret put GATEWAY_PRIVATE --config wrangler.gateway.toml # paste privateJwk +wrangler secret put GATEWAY_PUBLIC --config wrangler.gateway.toml # paste publicJwk +wrangler deploy --config wrangler.gateway.toml +``` + +### Consumer setup + +Declare the service binding and point `JWT_JWKS_SERVICE_NAME` at its binding name: + +**`wrangler.consumer.toml`:** + +```toml +name = "consumer-api" +main = "src/consumer.ts" + +[vars] +JWT_JWKS_SERVICE_NAME = "GATEWAY_BINDING" +JWT_ISS = "https://gateway.internal" +JWT_AUD = "internal-api" + +[[services]] +binding = "GATEWAY_BINDING" +service = "jwt-gateway" +environment = "production" +``` + +**`src/consumer.ts`:** + +```typescript +import { Hono } from 'hono' +import { makeKit } from '@chrislyons-dev/flarelette-jwt/adapters/hono' + +const app = new Hono() + +app.use('*', async (c, next) => { + c.set('jwt', makeKit(c.env)) // Detects GATEWAY_BINDING automatically + await next() +}) + +app.get('/secure', async c => { + const jwt = c.get('jwt') + const token = c.req.header('Authorization')?.replace('Bearer ', '') + const auth = await jwt.checkAuth(token, jwt.policy().build()) + if (!auth) return c.json({ error: 'Unauthorized' }, 401) + return c.json({ data: 'secure', user: auth.sub }) +}) + +export default app +``` + +```bash +wrangler deploy --config wrangler.consumer.toml +``` + +### JWKS caching + +Keys are cached in-memory for 5 minutes. On first verification, the consumer fetches `/.well-known/jwks.json` from the gateway via RPC. Subsequent requests within the TTL window hit the cache. After 5 minutes, the next verification triggers a refresh. + +No configuration required — the 5-minute TTL is fixed to match jose's `cooldownDuration`. + ## Testing Locally **With Wrangler:** @@ -462,5 +582,5 @@ console.log({ - **[Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/)** - **[Service Bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/)** - **[Secrets Management](https://developers.cloudflare.com/workers/configuration/secrets/)** -- **[Core Concepts](./core-concepts.md)** — Algorithm selection and architecture +- **[Core Concepts](./user-guide/core-concepts.md)** — Algorithm selection and architecture - **[Security Guide](./security-guide.md)** — Best practices and threat model diff --git a/docs/getting-started.md b/docs/getting-started.md index e557078..b87beed 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -245,12 +245,12 @@ console.log('User:', payload?.sub) - Testing (isolated configs per test) - Multi-tenant apps (different configs per tenant) -**Full documentation:** [Explicit Configuration API](./explicit-config.md) +**Full documentation:** [Explicit Configuration API](./user-guide/explicit-config.md) ## Next Steps -- **[Core Concepts](./core-concepts.md)** — Understand algorithms, modes, and architecture -- **[Usage Guide](./usage-guide.md)** — Explore the complete API +- **[Core Concepts](./user-guide/core-concepts.md)** — Understand algorithms, modes, and architecture +- **[Usage Guide](./user-guide/usage-guide.md)** — Explore the complete API - **[Cloudflare Workers](./cloudflare-workers.md)** — Deploy to Workers with proper secret management - **[Security Guide](./security-guide.md)** — Learn cryptographic profiles and best practices @@ -274,7 +274,7 @@ console.log('User:', payload?.sub) - Verify both producer and consumer use the same environment configuration - Check which mode is active using the `envMode()` function (TypeScript) or `mode()` function (Python) -- See [Core Concepts](./core-concepts.md) for mode detection rules +- See [Core Concepts](./user-guide/core-concepts.md) for mode detection rules ### Token Always Returns Null diff --git a/docs/images/archlette-stainedglassA-dark.png b/docs/images/archlette-stainedglassA-dark.png new file mode 100644 index 0000000..e708215 Binary files /dev/null and b/docs/images/archlette-stainedglassA-dark.png differ diff --git a/docs/images/archlette-stainedglassA-dark.svg b/docs/images/archlette-stainedglassA-dark.svg new file mode 100644 index 0000000..9d8c0db --- /dev/null +++ b/docs/images/archlette-stainedglassA-dark.svg @@ -0,0 +1,34 @@ + + \n \n \n \n \n \n \n \n + + + + + + + + + + + + + + \n \n \n \n \n \n \n \n \n + + + \n \n \n \n \n \n + + + + + + \n \n \n + + + + + + \n \n \n \n \n \n + + + \ No newline at end of file diff --git a/docs/images/archlette-stainedglassA-light.png b/docs/images/archlette-stainedglassA-light.png new file mode 100644 index 0000000..a8aa74a Binary files /dev/null and b/docs/images/archlette-stainedglassA-light.png differ diff --git a/docs/images/archlette-stainedglassA-light.svg b/docs/images/archlette-stainedglassA-light.svg new file mode 100644 index 0000000..02ce4c8 --- /dev/null +++ b/docs/images/archlette-stainedglassA-light.svg @@ -0,0 +1,34 @@ + + \n \n \n \n \n \n \n \n + + + + + + + + + + + + + + \n \n \n \n \n \n \n \n \n + + + \n \n \n \n \n \n + + + + + + \n \n \n + + + + + + \n \n \n \n \n \n + + + \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 3b9a329..e618ced 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,10 +13,10 @@ Welcome to the Flarelette JWT Kit documentation! Below is a list of available gu ## Guides - [Setup Guide](./getting-started.md): Learn how to set up the development environment, install dependencies, and configure the project. -- [Usage Guide](./usage-guide.md): Explore how to use Flarelette JWT Kit for signing, verifying, and managing JWTs. +- [Usage Guide](./user-guide/usage-guide.md): Explore how to use Flarelette JWT Kit for signing, verifying, and managing JWTs. - [Security Guide](./security-guide.md): Learn about the security features and requirements of the project. -- [Service Delegation](./service-delegation.md): Understand how to implement zero-trust delegation patterns. -- [Core Concepts](./core-concepts.md): Dive into the architecture and key principles of the toolkit. +- [Service Delegation](./user-guide/service-delegation.md): Understand how to implement zero-trust delegation patterns. +- [Core Concepts](./user-guide/core-concepts.md): Dive into the architecture and key principles of the toolkit. ## References @@ -30,7 +30,7 @@ For more information, visit the individual files linked above or explore the rep **Environment-driven JWT authentication for Cloudflare Workers. Like Starlette, but for the edge.** -Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, loads secrets via Cloudflare bindings, and works across Workers, Node.js, and Python runtimes. +Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, and supports ES512 and RSA for external OIDC verification. Loads secrets via Cloudflare bindings and works across Workers, Node.js, and Python runtimes. ## Part of the Flarelette Ecosystem @@ -95,7 +95,7 @@ Flarelette JWT Kit provides the core cryptographic operations for the **Flarelet ## Key Features -- **Algorithm auto-detection** — Chooses HS512 or EdDSA based on environment variables +- **Algorithm auto-detection** — Chooses HS512 or EdDSA based on environment variables; ECDSA/RSA for external OIDC verification - **Secret-name indirection** — References Cloudflare secret bindings instead of raw values - **Identical TypeScript + Python APIs** — Same function names and behavior across languages - **Service bindings for JWKS** — Direct Worker-to-Worker RPC for key distribution @@ -166,7 +166,7 @@ npx flarelette-jwt-keygen --kid=ed25519-2025-01 Learn about algorithms, modes, and architecture patterns - [:octicons-arrow-right-24: Core concepts](core-concepts.md) + [:octicons-arrow-right-24: Core concepts](user-guide/core-concepts.md) - :material-api:{ .lg .middle } **Usage Guide** @@ -174,7 +174,7 @@ npx flarelette-jwt-keygen --kid=ed25519-2025-01 Complete API reference for TypeScript and Python - [:octicons-arrow-right-24: API reference](usage-guide.md) + [:octicons-arrow-right-24: API reference](user-guide/usage-guide.md) - :material-shield-lock:{ .lg .middle } **Security Guide** diff --git a/docs/security-guide.md b/docs/security-guide.md index 7ea96b8..46eb7c6 100644 --- a/docs/security-guide.md +++ b/docs/security-guide.md @@ -1,6 +1,6 @@ # Security Guide -Comprehensive security baseline for Flarelette JWT Kit across HS512, EdDSA, and RSA profiles. +Comprehensive security baseline for Flarelette JWT Kit across HS512, EdDSA, ECDSA, and RSA profiles. ## Trust Model: Why This Library Is Secure @@ -17,7 +17,7 @@ Flarelette JWT Kit is designed from the ground up to prevent the most common JWT - **Mode determined by server configuration only** — Verification mode (HS512 vs EdDSA/RSA) is chosen exclusively from server environment variables, never from the token header - **Strict algorithm whitelists** — Each mode has an explicit whitelist of allowed algorithms: - HS512 mode: `['HS512']` only - - EdDSA/RSA mode: `['EdDSA', 'RS256', 'RS384', 'RS512']` only + - EdDSA/ECDSA/RSA mode: `['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512']` only - **No `none` algorithm support** — The `none` algorithm is never included in any whitelist - **Token `alg` treated as untrusted input** — The `alg` header must match the allowed algorithms for the selected mode. Mismatches are rejected. @@ -108,13 +108,16 @@ if (buf.length < 64) { When importing JWKs, the expected algorithm is provided explicitly to the `jose` library: ```typescript -// Inline JWK import with explicit algorithm -const key = await importJWK(jwk, 'EdDSA') // Algorithm pinned at import time +// Inline JWK import — EdDSA requires explicit algorithm hint; EC/RSA auto-detected +const key = + jwk.kty === 'OKP' + ? await importJWK(jwk, 'EdDSA') // OKP keys need explicit algorithm + : await importJWK(jwk) // EC/RSA keys: jose auto-detects from kty+crv ``` -This ensures keys cannot be repurposed for other algorithms, even within the same key family (e.g., cannot use Ed25519 key for RS256). +The algorithm whitelist in `jwtVerify()` provides the primary protection (only whitelisted algorithms accepted). Explicit algorithm specification at import time adds a second layer of defense. -**Code location:** `src/verify.ts:73` +**Code location:** `src/verify.ts:71-73` ### Fail-Silent Pattern with Observability @@ -146,7 +149,7 @@ if (!payload) { ## Cryptographic Profiles -The kit supports three JWT algorithm profiles by design. Each has specific security properties and use cases. +The kit supports four JWT algorithm profiles by design. Each has specific security properties and use cases. ### HS512 (Symmetric) @@ -195,6 +198,31 @@ The kit supports three JWT algorithm profiles by design. Each has specific secur - Zero-trust architecture with distributed services - Public verification needed (consumers don't need signing capability) +### ECDSA (ES256/ES384/ES512) — TypeScript Only + +| Property | Value | +| ---------------- | ------------------------------------------------------------ | +| Algorithm | ECDSA with P-256, P-384, or P-521 curves | +| Key material | EC private/public key pair (JSON Web Keys) | +| Security level | 128–256-bit depending on curve | +| Key distribution | Public key distributed via JWKS or inline | +| Use case | Self-hosted OIDC gateway (ES512); external OIDC verification | + +**Security properties:** + +- Asymmetric: private key signs, public key verifies +- ES512 (P-521) signing available via TypeScript explicit API (`createES512SignConfig`) +- Verification supports tokens from OIDC providers using any ECDSA curve +- jose auto-detects EC algorithm from JWK `kty`/`crv` fields at import + +**When to use:** + +- Verifying tokens from OIDC providers that use ECDSA (ES256 is common; ES512 is FIPS-preferred) +- Self-hosted OIDC gateway that must sign with P-521 for compliance +- When standards requirements mandate ECDSA over EdDSA + +**Note:** ECDSA signing is TypeScript explicit API only. Environment-driven mode detection (`JWT_PRIVATE_JWK*`) triggers EdDSA, not ECDSA. + ## Key Generation ### HS512 Secrets @@ -237,24 +265,52 @@ secret = generate_secret(64) print(f"JWT_SECRET={secret}") ``` -### EdDSA Keypairs +### Asymmetric Keypairs (EdDSA and ECDSA) -**Generate with CLI:** +The `flarelette-jwt-keygen` CLI generates EdDSA (Ed25519) or ECDSA (P-256/P-384/P-521) keypairs. EdDSA is the default. + +**Flags:** + +| Flag | Description | Default | +| ------------- | --------------------------------------------- | ------------------- | +| `--alg=` | Algorithm: `EdDSA`, `ES256`, `ES384`, `ES512` | `EdDSA` | +| `--kid=` | Key ID to embed in JWK | `-` | +| `--dotenv` | Output as `.env` `JWT_*` variable assignments | JSON object | + +**Generate EdDSA keypair (default — recommended for new deployments):** ```bash +# Ed25519: fast, compact signatures, strong security. Preferred for new internal services. npx flarelette-jwt-keygen --kid=ed25519-2025-01 ``` -**Output:** +**Generate ES512 keypair (ECDSA P-521 — use when FIPS or ECDSA compatibility is required):** + +```bash +# ES512: FIPS-compliant ECDSA P-521. Use when standards mandate ECDSA over EdDSA. +npx flarelette-jwt-keygen --alg=ES512 --kid=es512-2025-01 +``` + +**Generate as `.env` assignments for direct use:** + +```bash +npx flarelette-jwt-keygen --alg=EdDSA --dotenv +# Outputs: +# JWT_PUBLIC_JWK='{"kty":"OKP","crv":"Ed25519",...}' +# JWT_PRIVATE_JWK='{"kty":"OKP","crv":"Ed25519","d":"...",...}' +``` + +**JSON output format:** ```json { - "kid": "ed25519-2025-01", "publicJwk": { "kty": "OKP", "crv": "Ed25519", "x": "", - "kid": "ed25519-2025-01" + "kid": "ed25519-2025-01", + "alg": "EdDSA", + "use": "sig" }, "privateJwk": { "kty": "OKP", @@ -713,7 +769,7 @@ regex = '''JWT_(SECRET|PRIVATE_JWK|PUBLIC_JWK|JWKS_URL)\s*=\s*["']?[A-Za-z0-9_\- Before deploying to production: -- [ ] HS512 or EdDSA explicitly enforced (not both in same environment) +- [ ] Single algorithm mode enforced: HS512 **or** asymmetric (EdDSA/ECDSA/RSA) — not both in same environment - [ ] Secrets stored as Cloudflare bindings (`*_NAME` pattern) - [ ] TTL ≤ 15 minutes; leeway ≤ 90 seconds - [ ] `JWT_AUD` is specific per service (no wildcard audiences) — prevents token reuse between services diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 9a08943..d29bd7d 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,4 +1,23 @@ /* Custom styles for Flarelette JWT Kit documentation */ +:root { + --md-primary-fg-color: #0f2b45; + --md-primary-fg-color--light: #1f3f5c; + --md-primary-fg-color--dark: #0b1e30; + --md-accent-fg-color: #ff7a00; + --md-accent-fg-color--transparent: rgba(255, 122, 0, 0.15); +} + +[data-md-color-scheme='slate'] { + --md-primary-fg-color: #0f2b45; + --md-primary-fg-color--light: #1f3f5c; + --md-primary-fg-color--dark: #0b1e30; + --md-accent-fg-color: #ff7a00; + --md-accent-fg-color--transparent: rgba(255, 122, 0, 0.18); + --md-default-bg-color: #0b0f12; + --md-default-fg-color: #f8fafc; + --md-default-fg-color--light: rgba(248, 250, 252, 0.7); + --md-default-fg-color--lighter: rgba(248, 250, 252, 0.5); +} /* Tighten up spacing for code blocks */ .highlight { @@ -11,6 +30,17 @@ border-left-width: 4px; } +/* Success emphasis */ +.admonition.success, +.admonition.tip { + border-left-color: #00c2a8; +} + +.admonition.success .admonition-title, +.admonition.tip .admonition-title { + background-color: rgba(0, 194, 168, 0.12); +} + /* Style the grid cards on homepage */ .grid.cards > ul { display: grid; diff --git a/docs/core-concepts.md b/docs/user-guide/core-concepts.md similarity index 87% rename from docs/core-concepts.md rename to docs/user-guide/core-concepts.md index 450f1d9..9bb7590 100644 --- a/docs/core-concepts.md +++ b/docs/user-guide/core-concepts.md @@ -4,11 +4,11 @@ Understanding how Flarelette JWT Kit makes cryptographic and architectural decis ## Algorithm Selection -The kit supports **two signing algorithms** (HS512, EdDSA) and **three verification profiles** (HS512, EdDSA, RSA). No configuration required — the mode is detected automatically from your environment. +The kit supports **HS512** (symmetric) and **EdDSA** (asymmetric) as its two primary signing algorithms, plus **ES512** (ECDSA P-521) for TypeScript explicit-API signing. Verification supports **EdDSA, ECDSA (ES256/ES384/ES512), and RSA** for external OIDC tokens. Mode is detected automatically from your environment. -**Signing:** HS512 for symmetric trust, EdDSA for asymmetric trust. +**Signing:** HS512 for symmetric trust, EdDSA for asymmetric trust. ES512 available via TypeScript explicit API. -**Verification:** HS512 and EdDSA for internal tokens, RSA for external OIDC providers. +**Verification:** HS512 and EdDSA for internal tokens; ECDSA and RSA for external OIDC providers. ### HS512 (Symmetric) @@ -71,6 +71,8 @@ JWT_JWKS_SERVICE_NAME=GATEWAY_BINDING # Option 3: HTTP JWKS URL for external OIDC providers (TypeScript only) JWT_JWKS_URL=https://tenant.auth0.com/.well-known/jwks.json +# Or with name indirection (useful in multi-env wrangler setups): +JWT_JWKS_URL_NAME=MY_JWKS_URL_VAR ``` ### RSA (External OIDC Verification) @@ -109,7 +111,7 @@ JWT_JWKS_CACHE_TTL_SECONDS=300 # Optional: default 5 minutes **Reduced attack surface:** Fewer algorithms means less code to audit and fewer potential vulnerabilities. -**Simplified key management:** HS512 for simple deployments, EdDSA for complex ones. No need to choose between RSA key sizes, ECDSA curves, or other variants. +**Simplified key management:** HS512 for simple deployments, EdDSA for asymmetric trust. ECDSA (ES256/ES384/ES512) and RSA supported for external OIDC verification and ES512 explicit signing. **Clear trade-offs:** Each algorithm has an obvious use case. No analysis paralysis. @@ -129,7 +131,7 @@ Consumer (verification): Otherwise → HS512 mode ``` -**Note:** EdDSA/RSA mode supports both EdDSA (Ed25519) and RSA (RS256/384/512) verification. The actual algorithm is auto-detected from the JWK structure or token header. +**Note:** Asymmetric mode supports EdDSA (Ed25519), ECDSA (ES256/ES384/ES512), and RSA (RS256/384/512) verification. The actual algorithm is auto-detected from the JWK structure or token header. **Verification in code:** @@ -293,6 +295,7 @@ wrangler secret put MY_JWT_SECRET - `JWT_PRIVATE_JWK_NAME` → `JWT_PRIVATE_JWK` - `JWT_PUBLIC_JWK_NAME` → `JWT_PUBLIC_JWK` - `JWT_JWKS_SERVICE_NAME` → `JWT_JWKS_SERVICE` +- `JWT_JWKS_URL_NAME` → `JWT_JWKS_URL` (public URL — direct form is usually fine; `_NAME` useful in multi-env wrangler setups) **Benefits:** @@ -419,18 +422,20 @@ When you call `verify()` or `checkAuth()`, the kit performs these checks in orde TypeScript and Python implementations are kept in sync: -| Feature | TypeScript | Python | -| ----------------------- | ---------- | --------------------- | -| HS512 signing | ✅ | ✅ | -| HS512 verification | ✅ | ✅ | -| EdDSA signing | ✅ | ❌ (use Node gateway) | -| EdDSA verification | ✅ | ✅ (inline JWK only) | -| RSA verification | ✅ | ❌ | -| JWKS fetch | ✅ | ❌ (inline JWK only) | -| Service bindings | ✅ | ❌ | -| Secret-name indirection | ✅ | ✅ | -| Policy builder | ✅ | ✅ | -| CLI tools | ✅ | ✅ | +| Feature | TypeScript | Python | +| ---------------------------- | ---------- | --------------------- | +| HS512 signing | ✅ | ✅ | +| HS512 verification | ✅ | ✅ | +| EdDSA signing | ✅ | ❌ (use Node gateway) | +| EdDSA verification | ✅ | ✅ (inline JWK only) | +| ES512 signing (explicit API) | ✅ | ❌ | +| ECDSA verification | ✅ | ❌ | +| RSA verification | ✅ | ❌ | +| JWKS fetch | ✅ | ❌ (inline JWK only) | +| Service bindings | ✅ | ❌ | +| Secret-name indirection | ✅ | ✅ | +| Policy builder | ✅ | ✅ | +| CLI tools | ✅ | ✅ | **Why Python limitations?** @@ -510,5 +515,5 @@ TypeScript and Python implementations are kept in sync: - **[Usage Guide](./usage-guide.md)** — Complete API reference - **[Service Delegation](./service-delegation.md)** — RFC 8693 actor claims -- **[Cloudflare Workers](./cloudflare-workers.md)** — Workers deployment guide -- **[Security Guide](./security-guide.md)** — Cryptographic profiles and best practices +- **[Cloudflare Workers](../cloudflare-workers.md)** — Workers deployment guide +- **[Security Guide](../security-guide.md)** — Cryptographic profiles and best practices diff --git a/docs/explicit-config.md b/docs/user-guide/explicit-config.md similarity index 96% rename from docs/explicit-config.md rename to docs/user-guide/explicit-config.md index d4a639b..4929389 100644 --- a/docs/explicit-config.md +++ b/docs/user-guide/explicit-config.md @@ -146,7 +146,7 @@ Sign a JWT token with explicit configuration. **Parameters:** - `payload: JwtPayload` - Claims to include in token -- `config: SignConfig` - HS512 or EdDSA sign configuration +- `config: SignConfig` - HS512, EdDSA, or ES512 sign configuration - `overrides?: Partial<{ iss, aud, ttlSeconds }>` - Per-call overrides **Returns:** `Promise` - Signed JWT token @@ -158,7 +158,7 @@ Verify a JWT token with explicit configuration. **Parameters:** - `token: string` - JWT token to verify -- `config: VerifyConfig` - HS512 or EdDSA verify configuration +- `config: VerifyConfig` - HS512, EdDSA, ECDSA, or JWKS verify configuration - `overrides?: Partial<{ iss, aud, leeway }>` - Per-call overrides **Returns:** `Promise` - Payload if valid, null if invalid @@ -455,7 +455,7 @@ function createJwtConfig(env: 'dev' | 'prod'): HS512Config { ## See Also -- [Getting Started Guide](./getting-started.md) - Basic JWT usage -- [Security Guide](./security-guide.md) - Cryptographic best practices +- [Getting Started Guide](../getting-started.md) - Basic JWT usage +- [Security Guide](../security-guide.md) - Cryptographic best practices - [Service Delegation](./service-delegation.md) - RFC 8693 patterns -- [Cloudflare Workers](./cloudflare-workers.md) - Production deployment +- [Cloudflare Workers](../cloudflare-workers.md) - Production deployment diff --git a/docs/quick-start-demo.md b/docs/user-guide/quick-start-demo.md similarity index 100% rename from docs/quick-start-demo.md rename to docs/user-guide/quick-start-demo.md diff --git a/docs/service-delegation.md b/docs/user-guide/service-delegation.md similarity index 98% rename from docs/service-delegation.md rename to docs/user-guide/service-delegation.md index 67b7c79..3554aa9 100644 --- a/docs/service-delegation.md +++ b/docs/user-guide/service-delegation.md @@ -444,5 +444,5 @@ export default app - **[RFC 8693: OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693.html)** — Actor claim specification - **[Core Concepts](./core-concepts.md)** — Algorithm selection and architecture -- **[Security Guide](./security-guide.md)** — Cryptographic profiles and best practices -- **[Cloudflare Workers](./cloudflare-workers.md)** — Deployment and configuration +- **[Security Guide](../security-guide.md)** — Cryptographic profiles and best practices +- **[Cloudflare Workers](../cloudflare-workers.md)** — Deployment and configuration diff --git a/docs/usage-guide.md b/docs/user-guide/usage-guide.md similarity index 98% rename from docs/usage-guide.md rename to docs/user-guide/usage-guide.md index 1c75157..71f6004 100644 --- a/docs/usage-guide.md +++ b/docs/user-guide/usage-guide.md @@ -4,7 +4,7 @@ Complete API reference for Flarelette JWT Kit with examples in TypeScript and Py ## Overview -This guide covers all exported functions, types, and patterns for both languages. For conceptual understanding, see [Core Concepts](./core-concepts.md). For security best practices, see [Security Guide](./security-guide.md). +This guide covers all exported functions, types, and patterns for both languages. For conceptual understanding, see [Core Concepts](./core-concepts.md). For security best practices, see [Security Guide](../security-guide.md). ## Core Functions @@ -989,8 +989,8 @@ export default app ## Next Topics -- **[Getting Started](./getting-started.md)** — Installation and first token +- **[Getting Started](../getting-started.md)** — Installation and first token - **[Core Concepts](./core-concepts.md)** — Algorithms, modes, and architecture - **[Service Delegation](./service-delegation.md)** — RFC 8693 actor claims for zero-trust -- **[Security Guide](./security-guide.md)** — Cryptographic profiles and best practices -- **[Cloudflare Workers](./cloudflare-workers.md)** — Workers deployment and configuration +- **[Security Guide](../security-guide.md)** — Cryptographic profiles and best practices +- **[Cloudflare Workers](../cloudflare-workers.md)** — Workers deployment and configuration diff --git a/mkdocs.yml b/mkdocs.yml index 7dd71f2..2981a9b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,7 +7,7 @@ repo_name: chrislyons-dev/flarelette-jwt-kit repo_url: https://github.com/chrislyons-dev/flarelette-jwt-kit edit_uri: edit/main/docs/ -copyright: Copyright © 2025 Chris Lyons +copyright: Copyright © 2026 Chris Lyons theme: name: material @@ -15,16 +15,16 @@ theme: # Light mode - media: '(prefers-color-scheme: light)' scheme: default - primary: deep purple - accent: amber + primary: custom + accent: custom toggle: icon: material/brightness-7 name: Switch to dark mode # Dark mode - media: '(prefers-color-scheme: dark)' scheme: slate - primary: deep purple - accent: amber + primary: custom + accent: custom toggle: icon: material/brightness-4 name: Switch to light mode @@ -103,19 +103,18 @@ plugins: lang: en - minify: minify_html: true - -nav: - - Home: index.md - - Getting Started: getting-started.md - - User Guide: - - Core Concepts: core-concepts.md - - Usage Guide: usage-guide.md - - Service Delegation: service-delegation.md - - Deployment: - - Cloudflare Workers: cloudflare-workers.md - - Security: - - Security Guide: security-guide.md - - Architecture: - - Overview: architecture/README.md - - TypeScript Package: architecture/chrislyons_dev_flarelette_jwt.md - - Python Package: architecture/flarelette_jwt.md +# nav: +# - Home: index.md +# - Getting Started: getting-started.md +# - User Guide: +# - Core Concepts: user-guide/core-concepts.md +# - Usage Guide: user-guide/usage-guide.md +# - Service Delegation: user-guide/service-delegation.md +# - Deployment: +# - Cloudflare Workers: cloudflare-workers.md +# - Security: +# - Security Guide: security-guide.md +# - Architecture: +# - Overview: architecture/README.md +# - TypeScript Package: architecture/chrislyons_dev_flarelette_jwt.md +# - Python Package: architecture/flarelette_jwt.md diff --git a/package-lock.json b/package-lock.json index f345097..c14adb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "packages/*" ], "dependencies": { - "@chrislyons-dev/archlette": "^1.2.0" + "@chrislyons-dev/archlette": "^1.3.2" }, "devDependencies": { "@commitlint/cli": "^20.1.0", @@ -38,6 +38,31 @@ "wrangler": "^4.45.1" } }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@astrojs/compiler": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.0.tgz", @@ -48,7 +73,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -63,7 +87,6 @@ "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/@babel/helper-string-parser": { @@ -80,7 +103,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -126,34 +148,82 @@ "node": ">=18" } }, + "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==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", + "license": "Apache-2.0" + }, + "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==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", + "license": "Apache-2.0" + }, "node_modules/@chrislyons-dev/archlette": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@chrislyons-dev/archlette/-/archlette-1.2.0.tgz", - "integrity": "sha512-QQJjDp5w0+M3u/RsKIXYis0MRq86xM0kVMm6h1G00LCWud0ze+5Rkxdmhgs0FeO6Mwj/r++l67LLWoP76AdCrg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@chrislyons-dev/archlette/-/archlette-1.3.2.tgz", + "integrity": "sha512-jUUFfsoiv8tl5kk7F9R5u8HQk57Gu5DvxEAro22sxPWSppXjRGsbT/14lsJmea4IbX7XLDpZOe3Lw46Nsny/cA==", "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.10.3", - "execa": "^9.5.1", - "globby": "^15.0.0", + "@astrojs/compiler": "^2.13.0", + "@mermaid-js/mermaid-cli": "^11.12.0", + "execa": "^9.6.1", + "globby": "^16.0.0", "nunjucks": "^3.2.4", "pino": "^10.1.0", - "pino-pretty": "^13.1.2", - "smol-toml": "^1.4.2", + "pino-pretty": "^13.1.3", + "puppeteer": "^23.11.1", + "sharp": "^0.34.5", + "smol-toml": "^1.5.2", "ts-morph": "^27.0.2", - "yaml": "^2.8.1", - "zod": "^4.1.12" + "yaml": "^2.8.2", + "zod": "^4.1.13" }, "bin": { "archlette": "dist/cli.js" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, "node_modules/@chrislyons-dev/archlette/node_modules/zod": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", - "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -164,38 +234,19 @@ "link": true }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz", - "integrity": "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", + "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", "dev": true, "license": "MIT OR Apache-2.0", - "dependencies": { - "mime": "^3.0.0" - }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@cloudflare/unenv-preset": { - "version": "2.7.8", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.7.8.tgz", - "integrity": "sha512-Ky929MfHh+qPhwCapYrRPwPVHtA2Ioex/DbGZyskGyNRDe9Ru3WThYZivyNVaPy5ergQSgMs9OKrM9Ajtz9F6w==", - "dev": true, - "license": "MIT OR Apache-2.0", - "peerDependencies": { - "unenv": "2.0.0-rc.21", - "workerd": "^1.20250927.0" - }, - "peerDependenciesMeta": { - "workerd": { - "optional": true - } - } - }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20251011.0.tgz", - "integrity": "sha512-0DirVP+Z82RtZLlK2B+VhLOkk+ShBqDYO/jhcRw4oVlp0TOvk3cOVZChrt3+y3NV8Y/PYgTEywzLKFSziK4wCg==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260305.0.tgz", + "integrity": "sha512-chhKOpymo0Eh9J3nymrauMqKGboCc4uz/j0gA1G4gioMnKsN2ZDKJ+qjRZDnCoVGy8u2C4pxlmyIfsXCAfIzhQ==", "cpu": [ "x64" ], @@ -210,9 +261,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20251011.0.tgz", - "integrity": "sha512-1WuFBGwZd15p4xssGN/48OE2oqokIuc51YvHvyNivyV8IYnAs3G9bJNGWth1X7iMDPe4g44pZrKhRnISS2+5dA==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260305.0.tgz", + "integrity": "sha512-K9aG2OQk5bBfOP+fyGPqLcqZ9OR3ra6uwnxJ8f2mveq2A2LsCI7ZeGxQiAj75Ti80ytH/gJffZIx4Np2JtU3aQ==", "cpu": [ "arm64" ], @@ -227,9 +278,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20251011.0.tgz", - "integrity": "sha512-BccMiBzFlWZyFghIw2szanmYJrJGBGHomw2y/GV6pYXChFzMGZkeCEMfmCyJj29xczZXxcZmUVJxNy4eJxO8QA==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260305.0.tgz", + "integrity": "sha512-tt7XUoIw/cYFeGbkPkcZ6XX1aZm26Aju/4ih+DXxOosbBeGshFSrNJDBfAKKOvkjsAZymJ+WWVDBU+hmNaGfwA==", "cpu": [ "x64" ], @@ -244,9 +295,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20251011.0.tgz", - "integrity": "sha512-79o/216lsbAbKEVDZYXR24ivEIE2ysDL9jvo0rDTkViLWju9dAp3CpyetglpJatbSi3uWBPKZBEOqN68zIjVsQ==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260305.0.tgz", + "integrity": "sha512-72QTkY5EzylmvCZ8ZTrnJ9DctmQsfSof1OKyOWqu/pv/B2yACfuPMikq8RpPxvVu7hhS0ztGP6ZvXz72Htq4Zg==", "cpu": [ "arm64" ], @@ -261,9 +312,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20251011.0.tgz", - "integrity": "sha512-RIXUQRchFdqEvaUqn1cXZXSKjpqMaSaVAkI5jNZ8XzAw/bw2bcdOVUtakrflgxDprltjFb0PTNtuss1FKtH9Jg==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260305.0.tgz", + "integrity": "sha512-BA0uaQPOaI2F6mJtBDqplGnQQhpXCzwEMI33p/TnDxtSk9u8CGIfBFuI6uqo8mJ6ijIaPjeBLGOn2CiRMET4qg==", "cpu": [ "x64" ], @@ -570,10 +621,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", - "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", - "dev": true, + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", "license": "MIT", "optional": true, "dependencies": { @@ -1078,9 +1128,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1141,9 +1191,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -1199,9 +1249,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -1248,6 +1298,59 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.4.tgz", + "integrity": "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", + "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.4", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.27.18", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.18.tgz", + "integrity": "sha512-xJWJxvmy3a05j643gQt+pRbht5XnTlGpsEsAPnMi5F5YTOEEJymA90uZKBD8OvIv5XvZ1qi4GcccSlqT3Bq44Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.7", + "@floating-ui/utils": "^0.2.10", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.7.tgz", + "integrity": "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.5" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@google-automations/git-file-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@google-automations/git-file-utils/-/git-file-utils-3.0.0.tgz", @@ -1264,9 +1367,9 @@ } }, "node_modules/@google-automations/git-file-utils/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -1276,6 +1379,53 @@ "node": ">=10" } }, + "node_modules/@headlessui/react": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.9.tgz", + "integrity": "sha512-Mb+Un58gwBn0/yWZfyrCh0TJyurtT+dETj7YHleylHk5od3dv2XqETPGWMyQ5/7sYN7oWdyM1u9MvC0OC8UmzQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.20.2", + "@react-aria/interactions": "^3.25.0", + "@tanstack/react-virtual": "^3.13.9", + "use-sync-external-store": "^1.5.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/@headlessui/react/node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@headlessui/tailwindcss": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@headlessui/tailwindcss/-/tailwindcss-0.2.2.tgz", + "integrity": "sha512-xNe42KjdyA4kfUKLLPGzME9zkH7Q3rOZ5huFihWNWOQFxnItxPB3/67yBI8/qBfY8nwBRx5GHn4VprsoluVMGw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "tailwindcss": "^3.0 || ^4.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1335,14 +1485,39 @@ "dev": true, "license": "ISC" }, + "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==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "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": [ @@ -1355,17 +1530,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" + "@img/sharp-libvips-darwin-arm64": "1.2.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "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": [ @@ -1378,17 +1552,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" + "@img/sharp-libvips-darwin-x64": "1.2.4" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "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": [ @@ -1399,13 +1572,12 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "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": [ @@ -1416,13 +1588,12 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "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, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1433,13 +1604,44 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "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, + "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" + ], + "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" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1450,13 +1652,12 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "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, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1467,13 +1668,12 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "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, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1484,13 +1684,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "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, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1501,13 +1700,12 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "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, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1518,13 +1716,12 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1537,17 +1734,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "@img/sharp-libvips-linux-arm": "1.2.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1560,17 +1756,60 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "@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" + ], + "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" + ], + "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.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1583,17 +1822,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "@img/sharp-libvips-linux-s390x": "1.2.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1606,17 +1844,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" + "@img/sharp-libvips-linux-x64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1629,17 +1866,16 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "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, "license": "Apache-2.0", "optional": true, "os": [ @@ -1652,21 +1888,20 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "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.2.0" + "@emnapi/runtime": "^1.7.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -1675,14 +1910,13 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "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": [ - "ia32" + "arm64" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1695,14 +1929,13 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "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": [ - "x64" + "ia32" ], - "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1715,25 +1948,23 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "license": "MIT", + "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" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, - "engines": { - "node": "20 || >=22" + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@isaacs/cliui": { @@ -1797,11 +2028,20 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "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/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==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1811,14 +2051,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1851,14 +2089,57 @@ "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@mermaid-js/mermaid-cli": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-11.12.0.tgz", + "integrity": "sha512-a0swOS6PByXKi0dZnLQQIhbtUEu7ubc6bojmIqXqvUPq7mIJukCNEvVBTv6IAbuEWqB3Ti8QntupoGdz3ej+kg==", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@mermaid-js/mermaid-zenuml": "^0.2.0", + "chalk": "^5.0.1", + "commander": "^14.0.0", + "import-meta-resolve": "^4.1.0", + "mermaid": "^11.0.2" + }, + "bin": { + "mmdc": "src/cli.js" + }, + "engines": { + "node": "^18.19 || >=20.0" + }, + "peerDependencies": { + "puppeteer": "^23" + } + }, + "node_modules/@mermaid-js/mermaid-zenuml": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-zenuml/-/mermaid-zenuml-0.2.2.tgz", + "integrity": "sha512-sUjwk4NWUpy9uaHypYSIGJDks10ZaZo5CHH9lx9xcmyqv9w7yvd4vecUmlUQxmlHStYO+aqSkYKX5/gFjDfypw==", + "license": "MIT", + "dependencies": { + "@zenuml/core": "^3.35.2" + }, + "peerDependencies": { + "mermaid": "^10 || ^11" + } + }, + "node_modules/@mermaid-js/parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", + "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", + "license": "MIT", + "dependencies": { + "langium": "^4.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { "node": ">= 8" @@ -2210,10 +2491,129 @@ "dev": true, "license": "MIT" }, + "node_modules/@puppeteer/browsers": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz", + "integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-aria/focus": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.4.tgz", + "integrity": "sha512-6gz+j9ip0/vFRTKJMl3R30MHopn4i19HqqLfSQfElxJD+r9hBnYG1Q6Wd/kl/WRR1+CALn2F+rn06jUnf5sT8Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.0", + "@react-aria/utils": "^3.33.0", + "@react-types/shared": "^3.33.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.0.tgz", + "integrity": "sha512-D27pOy+0jIfHK60BB26AgqjjRFOYdvVSkwC31b2LicIzRCSPOSP06V4gMHuGmkhNTF4+YWDi1HHYjxIvMeiSlA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.0", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.33.0.tgz", + "integrity": "sha512-yvz7CMH8d2VjwbSa5nGXqjU031tYhD8ddax95VzJsHSPyqHDEGfxul8RkhGV6oO7bVqZxVs6xY66NIgae+FHjw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.2.tgz", + "integrity": "sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.11.0.tgz", + "integrity": "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.33.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.33.0.tgz", + "integrity": "sha512-xuUpP6MyuPmJtzNOqF5pzFUIHH2YogyOQfUQHag54PRmWB7AbjuGWBUv0l1UDmz6+AbzAYGmDVAzcRDOu2PFpw==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -2225,9 +2625,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -2239,9 +2639,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -2253,9 +2653,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -2267,9 +2667,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -2281,9 +2681,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -2295,9 +2695,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -2309,9 +2709,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -2323,9 +2723,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -2337,9 +2737,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -2351,9 +2751,23 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -2365,9 +2779,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -2379,9 +2807,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -2393,9 +2821,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -2407,9 +2835,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -2421,9 +2849,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -2435,9 +2863,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -2448,10 +2876,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -2463,9 +2905,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -2477,9 +2919,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -2491,9 +2933,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -2505,9 +2947,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -2563,6 +3005,48 @@ "dev": true, "license": "MIT" }, + "node_modules/@swc/helpers": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz", + "integrity": "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.13.19", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.19.tgz", + "integrity": "sha512-KzwmU1IbE0IvCZSm6OXkS+kRdrgW2c2P3Ho3NC+zZXWK6oObv/L+lcV/2VuJ+snVESRlMJ+w/fg4WXI/JzoNGQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.19" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.19", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.19.tgz", + "integrity": "sha512-/BMP7kNhzKOd7wnDeB8NrIRNLwkf5AhCYCvtfZV2GXWbBieFm/el0n6LOAXlTi6ZwHICSNnQcIxRCWHrLzDY+g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@ts-morph/common": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.28.1.tgz", @@ -2574,16 +3058,37 @@ "tinyglobby": "^0.2.14" } }, + "node_modules/@ts-morph/common/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==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2610,6 +3115,259 @@ "@types/node": "*" } }, + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "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==", + "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==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -2624,6 +3382,12 @@ "dev": true, "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==", + "license": "MIT" + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2642,7 +3406,7 @@ "version": "24.9.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.2.tgz", "integrity": "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -2663,6 +3427,13 @@ "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==", + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", @@ -2687,6 +3458,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.46.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.2.tgz", @@ -3076,14 +3857,109 @@ "node": ">=10.0.0" } }, - "node_modules/a-sync-waterfall": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", - "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "license": "MIT" + "node_modules/@zenuml/core": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@zenuml/core/-/core-3.46.0.tgz", + "integrity": "sha512-bjG37doCwXer4DhlBh1d7bHUuJbqAK/1I+kHyL7Evy0eWZnBOTEOfp6LodB5cokw3w2IMxzYuj7qyRzwjqoeiA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.27.16", + "@headlessui/react": "^2.2.9", + "@headlessui/tailwindcss": "^0.2.2", + "antlr4": "~4.11.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "color-string": "^2.1.4", + "dompurify": "^3.3.1", + "highlight.js": "^10.7.3", + "html-to-image": "^1.11.13", + "immer": "^10.2.0", + "jotai": "^2.16.1", + "lodash": "^4.17.21", + "marked": "^4.3.0", + "pako": "^2.1.0", + "pino": "^8.21.0", + "radash": "^12.1.1", + "ramda": "^0.28.0", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "tailwind-merge": "^3.4.0", + "tailwindcss": "^3.4.19" + }, + "engines": { + "node": ">=20" + } }, - "node_modules/abbrev": { - "version": "2.0.0", + "node_modules/@zenuml/core/node_modules/pino": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^6.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^3.7.0", + "thread-stream": "^2.6.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/@zenuml/core/node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "license": "MIT", + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/@zenuml/core/node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "license": "MIT" + }, + "node_modules/@zenuml/core/node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "license": "MIT" + }, + "node_modules/@zenuml/core/node_modules/sonic-boom": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/@zenuml/core/node_modules/thread-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/a-sync-waterfall": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz", + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, @@ -3092,11 +3968,22 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "peer": true, "bin": { @@ -3116,30 +4003,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" } }, "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -3195,11 +4071,44 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/antlr4": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.11.0.tgz", + "integrity": "sha512-GUGlpE2JUjAN+G8G5vY+nOoeyNhHsXoIJwP1XF1oRw89vifA1K46T6SEkwLwr7drihN7I/lf0DIjKc4OZvBX8w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=14" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/array-find-index": { @@ -3245,6 +4154,18 @@ "node": ">=12" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-v8-to-istanbul": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.8.tgz", @@ -3286,6 +4207,20 @@ "node": ">=8.0.0" } }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3293,6 +4228,122 @@ "dev": true, "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.5.tgz", + "integrity": "sha512-XvwYM6VZqKoqDll8BmSww5luA5eflDzY0uEFfBJtFKe4PAAtxBjU3YIxzIBzhyaEQBy1VXEQBto4cpN5RZJw+w==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.7.0.tgz", + "integrity": "sha512-64Rcwj8qlnTZU8Ps6JJEdSmxBEUGgI7g8l+lMtsJLl4IsfTcHMTfJ188u2iGV6P6YPRZrtv72B2kjn+hp+Yv3g==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz", + "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.21.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.3.2.tgz", + "integrity": "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/before-after-hook": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", @@ -3300,6 +4351,18 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/blake3-wasm": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz", @@ -3336,11 +4399,43 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3356,6 +4451,15 @@ "node": ">=6" } }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/camelcase-keys": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", @@ -3388,7 +4492,6 @@ "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -3397,6 +4500,103 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chevrotain": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chromium-bidi": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.11.0.tgz", + "integrity": "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "3.0.1", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/chromium-bidi/node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -3434,7 +4634,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -3449,7 +4648,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3459,7 +4657,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3475,7 +4672,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3485,7 +4681,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3500,7 +4695,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3513,7 +4707,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3527,6 +4720,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "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/code-block-writer": { "version": "13.0.3", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", @@ -3593,16 +4795,6 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/code-suggester/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/code-suggester/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -3688,25 +4880,10 @@ "node": ">=10" } }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -3719,18 +4896,27 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dev": true, + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" } }, "node_modules/colorette": { @@ -3743,7 +4929,6 @@ "version": "14.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -3767,6 +4952,12 @@ "dev": true, "license": "MIT" }, + "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==", + "license": "MIT" + }, "node_modules/conventional-changelog-angular": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", @@ -3904,97 +5095,627 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=18" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "peer": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", + "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "^2.6.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "license": "MIT", + "peer": true, + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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-dsv/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==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "ISC", + "peer": true, + "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==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, - "license": "MIT", - "peer": true, + "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==", + "license": "ISC", "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" + "d3-array": "2 - 3" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=12" } }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.2.0.tgz", - "integrity": "sha512-GEN39v7TgdxgIoNcdkRE3uiAzQt3UXLyHbRHD6YoL048XAeOomyxaP+Hh/+2C6C2wYjxJ2onhJcsQp+L4YEkVQ==", - "dev": true, - "license": "MIT", + "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==", + "license": "ISC", "dependencies": { - "jiti": "^2.6.1" + "d3-time": "1 - 3" }, "engines": { - "node": ">=v18" - }, - "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=9", - "typescript": ">=5" + "node": ">=12" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", + "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==", + "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==", + "license": "ISC", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" }, "engines": { - "node": ">= 8" + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", - "dev": true, - "license": "BSD-2-Clause", + "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==", + "license": "ISC", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "engines": { + "node": ">=12" } }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "node_modules/dagre-d3-es": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", + "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" } }, "node_modules/dargs": { @@ -4010,6 +5731,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -4020,11 +5750,16 @@ "node": "*" } }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "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" @@ -4082,12 +5817,28 @@ "dev": true, "license": "MIT" }, - "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", - "dev": true, - "license": "MIT" + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } }, "node_modules/deprecation": { "version": "2.3.1", @@ -4110,22 +5861,40 @@ "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/devtools-protocol": { + "version": "0.0.1367902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", + "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -4170,6 +5939,18 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", + "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", @@ -4209,7 +5990,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/end-of-stream": { @@ -4238,7 +6018,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4268,7 +6047,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -4337,7 +6115,6 @@ "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" @@ -4356,6 +6133,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/eslint": { "version": "9.38.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.38.0.tgz", @@ -4464,9 +6262,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -4588,9 +6386,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -4686,6 +6484,19 @@ "url": "https://opencollective.com/eslint" } }, + "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==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -4716,7 +6527,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -4736,12 +6546,20 @@ "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/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -4749,10 +6567,28 @@ "dev": true, "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/execa": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", - "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", @@ -4802,19 +6638,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/exit-hook": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", - "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -4825,17 +6648,45 @@ "node": ">=12.0.0" } }, - "node_modules/exsolve": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", - "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", - "dev": true, - "license": "MIT" + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/fast-copy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", + "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -4845,6 +6696,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4887,6 +6744,15 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", @@ -4919,6 +6785,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -5030,7 +6905,6 @@ "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, @@ -5045,7 +6919,6 @@ "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" @@ -5055,7 +6928,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -5090,6 +6962,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/git-raw-commits": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", @@ -5136,7 +7022,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -5145,24 +7030,40 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "node_modules/glob/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": "BSD-2-Clause" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/glob/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5198,17 +7099,17 @@ } }, "node_modules/globby": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-15.0.0.tgz", - "integrity": "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw==", + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.1.1.tgz", + "integrity": "sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==", "license": "MIT", "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "fast-glob": "^3.3.3", "ignore": "^7.0.5", - "path-type": "^6.0.0", + "is-path-inside": "^4.0.0", "slash": "^5.1.0", - "unicorn-magic": "^0.3.0" + "unicorn-magic": "^0.4.0" }, "engines": { "node": ">=20" @@ -5218,12 +7119,12 @@ } }, "node_modules/globby/node_modules/unicorn-magic": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", - "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5244,6 +7145,12 @@ "dev": true, "license": "MIT" }, + "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==", + "license": "MIT" + }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -5290,7 +7197,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5315,10 +7221,19 @@ "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", "license": "MIT" }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/hono": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.10.3.tgz", - "integrity": "sha512-2LOYWUbnhdxdL8MNbNg9XZig6k+cZXm5IjHn2Aviv7honhBMOHb+jxrKIeJRZJRmn+htUCKhaicxwXuUDlchRA==", + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", + "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", "dev": true, "license": "MIT", "engines": { @@ -5345,11 +7260,16 @@ "dev": true, "license": "MIT" }, + "node_modules/html-to-image": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz", + "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==", + "license": "MIT" + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -5363,7 +7283,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5398,6 +7317,38 @@ "url": "https://github.com/sponsors/typicode" } }, + "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==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -5407,11 +7358,20 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -5428,7 +7388,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5438,7 +7397,6 @@ "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", @@ -5475,18 +7433,46 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "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==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, "license": "MIT" }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5554,6 +7540,18 @@ "node": ">=8" } }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -5681,8 +7679,9 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, + "devOptional": true, "license": "MIT", + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -5696,6 +7695,35 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/jotai": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.18.0.tgz", + "integrity": "sha512-XI38kGWAvtxAZ+cwHcTgJsd+kJOJGf3OfL4XYaXWZMZ7IIY8e53abpIHvtVn1eAgJ5dlgwlGFnP4psrZ/vZbtA==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0", + "@babel/template": ">=7.0.0", + "@types/react": ">=17.0.0", + "react": ">=17.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@babel/template": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", @@ -5713,10 +7741,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -5747,7 +7774,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -5817,6 +7843,31 @@ "node": "*" } }, + "node_modules/katex": { + "version": "0.16.33", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.33.tgz", + "integrity": "sha512-q3N5u+1sY9Bu7T4nlXoiRBXWfwSefNGoKeOwekV+gw0cAXQlz2Ww6BLcmBxVDeXBMUDQv6fK5bcNaJLxob3ZQA==", + "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==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -5827,6 +7878,11 @@ "json-buffer": "3.0.1" } }, + "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==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5847,6 +7903,29 @@ "node": ">=6" } }, + "node_modules/langium": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "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==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5921,11 +8000,22 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, "license": "MIT" }, "node_modules/lint-staged": { @@ -5987,6 +8077,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -6145,6 +8247,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/meow": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", @@ -6167,6 +8281,47 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.12.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", + "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.1", + "@mermaid-js/parser": "^1.0.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", + "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.13", + "dayjs": "^1.11.18", + "dompurify": "^3.2.5", + "katex": "^0.16.22", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.2.1", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, + "node_modules/mermaid/node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6180,19 +8335,6 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", @@ -6217,24 +8359,18 @@ } }, "node_modules/miniflare": { - "version": "4.20251011.1", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20251011.1.tgz", - "integrity": "sha512-Qbw1Z8HTYM1adWl6FAtzhrj34/6dPRDPwdYOx21dkae8a/EaxbMzRIPbb4HKVGMVvtqbK1FaRCgDLVLolNzGHg==", + "version": "4.20260305.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260305.0.tgz", + "integrity": "sha512-jVhtKJtiwaZa3rI+WgoLvSJmEazDsoUmAPYRUmEe2VO6VSbvkhbnDRm+dsPbYRatgNIExwrpqG1rv96jHiSb0w==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", - "acorn": "8.14.0", - "acorn-walk": "8.3.2", - "exit-hook": "2.2.1", - "glob-to-regexp": "0.4.1", - "sharp": "^0.33.5", - "stoppable": "1.1.0", - "undici": "7.14.0", - "workerd": "1.20251011.0", + "sharp": "^0.34.5", + "undici": "7.18.2", + "workerd": "1.20260305.0", "ws": "8.18.0", - "youch": "4.1.0-beta.10", - "zod": "3.22.3" + "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" @@ -6243,27 +8379,14 @@ "node": ">=18.0.0" } }, - "node_modules/miniflare/node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6306,6 +8429,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -6319,6 +8448,18 @@ "node": ">=10" } }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -6333,9 +8474,19 @@ "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/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/nano-spawn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", @@ -6353,7 +8504,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -6382,6 +8532,15 @@ "dev": true, "license": "MIT" }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-html-parser": { "version": "6.1.13", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", @@ -6451,6 +8610,15 @@ "node": ">=10" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-install-checks": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", @@ -6593,12 +8761,23 @@ "node": ">= 6" } }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "dev": true, - "license": "MIT" + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } }, "node_modules/on-exit-leak-free": { "version": "2.1.2", @@ -6694,6 +8873,38 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "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", @@ -6701,11 +8912,22 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -6732,7 +8954,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -6765,6 +8986,12 @@ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", "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==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", @@ -6788,7 +9015,6 @@ "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": { @@ -6809,36 +9035,28 @@ } }, "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", - "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" }, "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/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "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": { @@ -6866,6 +9084,15 @@ "node": ">=0.10" } }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/pino": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz", @@ -6898,20 +9125,20 @@ } }, "node_modules/pino-pretty": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.2.tgz", - "integrity": "sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==", + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", "license": "MIT", "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", - "fast-copy": "^3.0.2", + "fast-copy": "^4.0.0", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", + "pino-abstract-transport": "^3.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", @@ -6930,6 +9157,15 @@ "node": "*" } }, + "node_modules/pino-pretty/node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, "node_modules/pino-pretty/node_modules/strip-json-comments": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", @@ -6948,11 +9184,46 @@ "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", "license": "MIT" }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "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==", + "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==", + "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==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6968,6 +9239,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6977,6 +9249,134 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7028,6 +9428,15 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/process-warning": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", @@ -7044,6 +9453,15 @@ ], "license": "MIT" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", @@ -7058,10 +9476,44 @@ "node": ">=10" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -7078,6 +9530,46 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "23.11.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.11.1.tgz", + "integrity": "sha512-53uIX3KR5en8l7Vd8n5DUv90Ae9QDQsyIthaUFVzwV6yU750RjqRznEtNMBT20VthqAdemnJN+hxVdmMHKt7Zw==", + "deprecated": "< 24.15.0 is no longer supported", + "hasInstallScript": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@puppeteer/browsers": "2.6.1", + "chromium-bidi": "0.11.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1367902", + "puppeteer-core": "23.11.1", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "23.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.11.1.tgz", + "integrity": "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.6.1", + "chromium-bidi": "0.11.0", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1367902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7114,6 +9606,57 @@ "node": ">=8" } }, + "node_modules/radash": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/radash/-/radash-12.1.1.tgz", + "integrity": "sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==", + "license": "MIT", + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/ramda": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz", + "integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, "node_modules/read-installed-packages": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/read-installed-packages/-/read-installed-packages-2.0.1.tgz", @@ -7314,6 +9857,58 @@ "node": ">=8" } }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readable-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", @@ -7338,9 +9933,9 @@ } }, "node_modules/release-please": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.1.3.tgz", - "integrity": "sha512-fs4v5318Z3CLqyqw7EueXzjErtL8oXCv6Kc1mMYi72TAyReyBtOuuMB0lwoC2+LtGmvUYoG+RBXnDVU0DsKUIA==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/release-please/-/release-please-17.3.0.tgz", + "integrity": "sha512-dB7HsFUpAvU1Wj9RGCINUz8Zi2qQDZiGbDEEVnJ7baNfJmk5XdYhuUFL6RcuDGjReGhp1gzY8Tc2g7vHlM4zpg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7359,7 +9954,7 @@ "conventional-changelog-writer": "^6.0.0", "conventional-commits-filter": "^3.0.0", "detect-indent": "^6.1.0", - "diff": "^7.0.0", + "diff": "^8.0.3", "figures": "^3.0.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", @@ -7429,6 +10024,16 @@ "node": ">=14" } }, + "node_modules/release-please/node_modules/diff": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/release-please/node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -7447,7 +10052,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7467,7 +10071,6 @@ "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -7558,10 +10161,16 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -7575,31 +10184,46 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, + "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==", + "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-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7623,6 +10247,32 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", @@ -7632,6 +10282,18 @@ "node": ">=10" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/secure-json-parse": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", @@ -7652,7 +10314,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -7662,16 +10323,15 @@ } }, "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", - "dev": true, + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" + "@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" @@ -7680,25 +10340,30 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" + "@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": { @@ -7741,23 +10406,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", - "dev": true, - "license": "MIT" - }, "node_modules/slash": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", @@ -7797,10 +10445,20 @@ "node": "*" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/smol-toml": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.4.2.tgz", - "integrity": "sha512-rInDH6lCNiEyn3+hH8KVGFdbjc099j47+OSgbMrfDYX1CmXLfdKd7qi6IfcWj2wFxvSVkuI46M+wPGYfEOEj6g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", + "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -7809,6 +10467,34 @@ "url": "https://github.com/sponsors/cyyynthia" } }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/sonic-boom": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", @@ -7822,7 +10508,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -7832,7 +10518,6 @@ "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" @@ -7941,15 +10626,24 @@ "dev": true, "license": "MIT" }, - "node_modules/stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", - "dev": true, + "node_modules/streamx": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", "license": "MIT", - "engines": { - "node": ">=4", - "npm": ">=6" + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/string-argv": { @@ -8106,6 +10800,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8123,7 +10854,6 @@ "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" @@ -8132,6 +10862,113 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "license": "MIT" + }, + "node_modules/tailwind-merge": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.5.0.tgz", + "integrity": "sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tar-fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/text-extensions": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", @@ -8145,6 +10982,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/thread-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", @@ -8158,7 +11016,6 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true, "license": "MIT" }, "node_modules/tinybench": { @@ -8172,7 +11029,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { @@ -8276,6 +11132,21 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, "node_modules/ts-morph": { "version": "27.0.2", "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-27.0.2.tgz", @@ -8290,9 +11161,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -8320,11 +11189,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-query-selector": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.1.tgz", + "integrity": "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==", + "license": "MIT" + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peer": true, "bin": { @@ -8360,10 +11235,9 @@ } }, "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "dev": true, + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" }, "node_modules/uglify-js": { @@ -8380,10 +11254,20 @@ "node": ">=0.8.0" } }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "license": "MIT", + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "node_modules/undici": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.14.0.tgz", - "integrity": "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.18.2.tgz", + "integrity": "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==", "dev": true, "license": "MIT", "engines": { @@ -8394,22 +11278,18 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unenv": { - "version": "2.0.0-rc.21", - "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.21.tgz", - "integrity": "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==", + "version": "2.0.0-rc.24", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", + "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "defu": "^6.1.4", - "exsolve": "^1.0.7", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "ufo": "^1.6.1" + "pathe": "^2.0.3" } }, "node_modules/unicorn-magic": { @@ -8484,6 +11364,34 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -8712,6 +11620,55 @@ "dev": true, "license": "MIT" }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8762,9 +11719,9 @@ "license": "MIT" }, "node_modules/workerd": { - "version": "1.20251011.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20251011.0.tgz", - "integrity": "sha512-Dq35TLPEJAw7BuYQMkN3p9rge34zWMU2Gnd4DSJFeVqld4+DAO2aPG7+We2dNIAyM97S8Y9BmHulbQ00E0HC7Q==", + "version": "1.20260305.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260305.0.tgz", + "integrity": "sha512-JkhfCLU+w+KbQmZ9k49IcDYc78GBo7eG8Mir8E2+KVjR7otQAmpcLlsous09YLh8WQ3Bt3Mi6/WMStvMAPukeA==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -8776,41 +11733,41 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20251011.0", - "@cloudflare/workerd-darwin-arm64": "1.20251011.0", - "@cloudflare/workerd-linux-64": "1.20251011.0", - "@cloudflare/workerd-linux-arm64": "1.20251011.0", - "@cloudflare/workerd-windows-64": "1.20251011.0" + "@cloudflare/workerd-darwin-64": "1.20260305.0", + "@cloudflare/workerd-darwin-arm64": "1.20260305.0", + "@cloudflare/workerd-linux-64": "1.20260305.0", + "@cloudflare/workerd-linux-arm64": "1.20260305.0", + "@cloudflare/workerd-windows-64": "1.20260305.0" } }, "node_modules/wrangler": { - "version": "4.45.1", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.45.1.tgz", - "integrity": "sha512-SmmbDl6NUkv6mHT8/Scb09lvxXy0Y2hD98oZHswCysrYbs4JW5LP1eTuroE23Z2jK75D7TEzv2MXmwcDIytxhg==", + "version": "4.69.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.69.0.tgz", + "integrity": "sha512-EmVfIM65I5b4ITHe3Y9R7zQyf4NUBQ1leStakMlWiVR9n6VlDwuEltyQI2l3i0JciDnWyR3uqe+T6C08ivniTQ==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { - "@cloudflare/kv-asset-handler": "0.4.0", - "@cloudflare/unenv-preset": "2.7.8", + "@cloudflare/kv-asset-handler": "0.4.2", + "@cloudflare/unenv-preset": "2.14.0", "blake3-wasm": "2.1.5", - "esbuild": "0.25.4", - "miniflare": "4.20251011.1", + "esbuild": "0.27.3", + "miniflare": "4.20260305.0", "path-to-regexp": "6.3.0", - "unenv": "2.0.0-rc.21", - "workerd": "1.20251011.0" + "unenv": "2.0.0-rc.24", + "workerd": "1.20260305.0" }, "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20251011.0" + "@cloudflare/workers-types": "^4.20260305.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -8818,10 +11775,26 @@ } } }, + "node_modules/wrangler/node_modules/@cloudflare/unenv-preset": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.14.0.tgz", + "integrity": "sha512-XKAkWhi1nBdNsSEoNG9nkcbyvfUrSjSf+VYVPfOto3gLTZVc3F4g6RASCMh6IixBKCG2yDgZKQIHGKtjcnLnKg==", + "dev": true, + "license": "MIT OR Apache-2.0", + "peerDependencies": { + "unenv": "2.0.0-rc.24", + "workerd": "^1.20260218.0" + }, + "peerDependenciesMeta": { + "workerd": { + "optional": true + } + } + }, "node_modules/wrangler/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", - "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ "ppc64" ], @@ -8836,9 +11809,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/android-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", - "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", "cpu": [ "arm" ], @@ -8853,9 +11826,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/android-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", - "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", "cpu": [ "arm64" ], @@ -8870,9 +11843,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/android-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", - "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", "cpu": [ "x64" ], @@ -8887,9 +11860,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", - "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", "cpu": [ "arm64" ], @@ -8904,9 +11877,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/darwin-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", - "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", "cpu": [ "x64" ], @@ -8921,9 +11894,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", - "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", "cpu": [ "arm64" ], @@ -8938,9 +11911,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", - "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", "cpu": [ "x64" ], @@ -8955,9 +11928,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-arm": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", - "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", "cpu": [ "arm" ], @@ -8972,9 +11945,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", - "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ "arm64" ], @@ -8989,9 +11962,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", - "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", "cpu": [ "ia32" ], @@ -9006,9 +11979,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-loong64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", - "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", "cpu": [ "loong64" ], @@ -9023,9 +11996,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", - "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", "cpu": [ "mips64el" ], @@ -9040,9 +12013,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", - "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", "cpu": [ "ppc64" ], @@ -9057,9 +12030,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", - "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", "cpu": [ "riscv64" ], @@ -9074,9 +12047,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-s390x": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", - "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", "cpu": [ "s390x" ], @@ -9091,9 +12064,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/linux-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", - "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", "cpu": [ "x64" ], @@ -9108,9 +12081,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", - "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], @@ -9125,9 +12098,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", - "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], @@ -9142,9 +12115,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", - "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ "arm64" ], @@ -9159,9 +12132,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", - "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ "x64" ], @@ -9175,10 +12148,27 @@ "node": ">=18" } }, + "node_modules/wrangler/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/wrangler/node_modules/@esbuild/sunos-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", - "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], @@ -9193,9 +12183,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/win32-arm64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", - "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ "arm64" ], @@ -9210,9 +12200,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/win32-ia32": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", - "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ "ia32" ], @@ -9227,9 +12217,9 @@ } }, "node_modules/wrangler/node_modules/@esbuild/win32-x64": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", - "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], @@ -9244,9 +12234,9 @@ } }, "node_modules/wrangler/node_modules/esbuild": { - "version": "0.25.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", - "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -9257,31 +12247,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.4", - "@esbuild/android-arm": "0.25.4", - "@esbuild/android-arm64": "0.25.4", - "@esbuild/android-x64": "0.25.4", - "@esbuild/darwin-arm64": "0.25.4", - "@esbuild/darwin-x64": "0.25.4", - "@esbuild/freebsd-arm64": "0.25.4", - "@esbuild/freebsd-x64": "0.25.4", - "@esbuild/linux-arm": "0.25.4", - "@esbuild/linux-arm64": "0.25.4", - "@esbuild/linux-ia32": "0.25.4", - "@esbuild/linux-loong64": "0.25.4", - "@esbuild/linux-mips64el": "0.25.4", - "@esbuild/linux-ppc64": "0.25.4", - "@esbuild/linux-riscv64": "0.25.4", - "@esbuild/linux-s390x": "0.25.4", - "@esbuild/linux-x64": "0.25.4", - "@esbuild/netbsd-arm64": "0.25.4", - "@esbuild/netbsd-x64": "0.25.4", - "@esbuild/openbsd-arm64": "0.25.4", - "@esbuild/openbsd-x64": "0.25.4", - "@esbuild/sunos-x64": "0.25.4", - "@esbuild/win32-arm64": "0.25.4", - "@esbuild/win32-ia32": "0.25.4", - "@esbuild/win32-x64": "0.25.4" + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" } }, "node_modules/wrap-ansi": { @@ -9420,7 +12411,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -9452,7 +12442,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -9466,22 +12455,25 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -9500,7 +12492,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -9510,7 +12501,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9520,7 +12510,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9530,7 +12519,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -9545,7 +12533,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -9554,6 +12541,16 @@ "node": ">=8" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", @@ -9604,19 +12601,9 @@ "error-stack-parser-es": "^1.0.5" } }, - "node_modules/zod": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", - "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "packages/flarelette-jwt-ts": { "name": "@chrislyons-dev/flarelette-jwt", - "version": "1.11.0", + "version": "1.14.0", "license": "MIT", "dependencies": { "jose": "^6.1.3" diff --git a/package.json b/package.json index 575ce49..2fc1553 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,15 @@ "lint:py:fix": "ruff check --fix packages/flarelette-jwt-py", "format": "npm run format:js && npm run format:py", "format:js": "prettier --write .", - "format:py": "black packages/flarelette-jwt-py", + "format:py": "ruff check --fix packages/flarelette-jwt-py && black packages/flarelette-jwt-py", "format:check": "npm run format:js:check && npm run format:py:check", "format:js:check": "prettier --check .", - "format:py:check": "black --check packages/flarelette-jwt-py", + "format:py:check": "ruff check packages/flarelette-jwt-py && black --check packages/flarelette-jwt-py", "typecheck": "npm run typecheck:js && npm run typecheck:py", "typecheck:js": "cd packages/flarelette-jwt-ts && tsc --noEmit & cd ../..", "typecheck:py": "mypy packages/flarelette-jwt-py", "licenses:generate": "node scripts/generate-licenses.mjs", - "check": "npm run lint && npm run licenses:generate && npm run archlette && npm run format && npm run typecheck && npm run test:coverage", + "check": "npm run format && npm run lint && npm run licenses:generate && npm run archlette && npm run typecheck && npm run test:coverage", "pack:test": "npm run pack:test:ts && npm run pack:test:py", "pack:test:ts": "npm run build && cd packages/flarelette-jwt-ts && npm pack --pack-destination ./dist && cd ../.. && node scripts/inspect-pack-ts.js", "pack:test:py": "cd packages/flarelette-jwt-py && py prepare.py && python -m build && cd ../.. && node scripts/inspect-pack-py.js", @@ -77,6 +77,6 @@ "wrangler": "^4.45.1" }, "dependencies": { - "@chrislyons-dev/archlette": "^1.2.0" + "@chrislyons-dev/archlette": "^1.3.2" } } diff --git a/packages/CONTRIBUTING.md b/packages/CONTRIBUTING.md index 458b712..7cde73b 100644 --- a/packages/CONTRIBUTING.md +++ b/packages/CONTRIBUTING.md @@ -288,7 +288,7 @@ The project uses automated releases via [release-please](https://github.com/goog See **[RELEASING.md](RELEASING.md)** for detailed release process and **[RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md)** for setup. -**For maintainers:** Ensure `NPM_TOKEN` and `PYPI_TOKEN` secrets are configured in repository settings. +**For maintainers:** Configure npm and PyPI trusted publishing for this repository/workflow (GitHub OIDC). `NPM_TOKEN` and `PYPI_TOKEN` secrets are not required. ## Questions? diff --git a/packages/flarelette-jwt-py/flarelette_jwt/__init__.py b/packages/flarelette-jwt-py/flarelette_jwt/__init__.py index 851a279..5d6d6da 100644 --- a/packages/flarelette-jwt-py/flarelette_jwt/__init__.py +++ b/packages/flarelette-jwt-py/flarelette_jwt/__init__.py @@ -25,14 +25,18 @@ BaseJwtConfig, EdDSASignConfig, EdDSAVerifyConfig, + ES512VerifyConfig, HS512Config, + JWKSUrlVerifyConfig, SignConfig, VerifyConfig, check_auth_with_config, create_delegated_token_with_config, create_eddsa_sign_config, create_eddsa_verify_config, + create_es512_verify_config, create_hs512_config, + create_jwks_url_verify_config, create_token_with_config, sign_with_config, verify_with_config, @@ -61,6 +65,8 @@ "HS512Config", "EdDSASignConfig", "EdDSAVerifyConfig", + "ES512VerifyConfig", + "JWKSUrlVerifyConfig", "SignConfig", "VerifyConfig", "AuthzOptsWithConfig", @@ -89,4 +95,6 @@ "create_hs512_config", "create_eddsa_sign_config", "create_eddsa_verify_config", + "create_es512_verify_config", + "create_jwks_url_verify_config", ] diff --git a/packages/flarelette-jwt-py/flarelette_jwt/env.py b/packages/flarelette-jwt-py/flarelette_jwt/env.py index 662175d..70546f2 100644 --- a/packages/flarelette-jwt-py/flarelette_jwt/env.py +++ b/packages/flarelette-jwt-py/flarelette_jwt/env.py @@ -41,7 +41,9 @@ class JwtHeader(TypedDict, total=False): EdDSA deployments with multiple active keys. """ - alg: AlgType # Algorithm: HS512 or EdDSA + alg: ( + str # Algorithm as reported in the JWT header (e.g. HS512, EdDSA, ES512, RS256) + ) typ: str # Token type, typically "JWT" kid: str # Key ID for key rotation (optional) @@ -155,13 +157,24 @@ def mode(role: str) -> AlgType: return "EdDSA" # Consumers use public keys or JWKS to verify - if role == "consumer" and ( - os.getenv("JWT_PUBLIC_JWK") - or os.getenv("JWT_PUBLIC_JWK_NAME") - or os.getenv("JWT_JWKS_URL") - or os.getenv("JWT_JWKS_URL_NAME") - ): - return "EdDSA" + if role == "consumer": + has_hs512 = bool(os.getenv("JWT_SECRET") or os.getenv("JWT_SECRET_NAME")) + has_asymmetric = bool( + os.getenv("JWT_PUBLIC_JWK") + or os.getenv("JWT_PUBLIC_JWK_NAME") + or os.getenv("JWT_JWKS_URL") + or os.getenv("JWT_JWKS_URL_NAME") + ) + + if has_hs512 and has_asymmetric: + raise RuntimeError( + "Configuration error: Both HS512 (JWT_SECRET) and asymmetric " + "(JWT_PUBLIC_JWK/JWT_JWKS_*) secrets configured. " + "Choose one to prevent algorithm confusion attacks." + ) + + if has_asymmetric: + return "EdDSA" return "HS512" @@ -218,12 +231,29 @@ def get_hs_secret_bytes() -> bytes: ) try: b = base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) - if len(b) >= 32: + # SECURITY: HS512 uses SHA-512 (512 bits = 64 bytes). Enforce minimum 64-byte secret. + if len(b) >= 64: return b + raise RuntimeError( + f"JWT secret too short: {len(b)} bytes, need >= 64 for HS512 " + "(use 'python -m flarelette_jwt.secret --len=64')" + ) + except RuntimeError: + raise except Exception: pass - return s.encode("utf-8") + b = s.encode("utf-8") + if len(b) < 64: + raise RuntimeError( + f"JWT secret too short: {len(b)} bytes, need >= 64 for HS512 " + "(use 'python -m flarelette_jwt.secret --len=64')" + ) + return b def get_public_jwk_string() -> str | None: return _get_indirect("JWT_PUBLIC_JWK_NAME", "JWT_PUBLIC_JWK") + + +def get_jwks_url() -> str | None: + return _get_indirect("JWT_JWKS_URL_NAME", "JWT_JWKS_URL") diff --git a/packages/flarelette-jwt-py/flarelette_jwt/explicit.py b/packages/flarelette-jwt-py/flarelette_jwt/explicit.py index f093fe6..84d7059 100644 --- a/packages/flarelette-jwt-py/flarelette_jwt/explicit.py +++ b/packages/flarelette-jwt-py/flarelette_jwt/explicit.py @@ -14,12 +14,14 @@ import base64 import json import time -from typing import TYPE_CHECKING, Any, Literal, TypedDict +from typing import TYPE_CHECKING, Any, Literal, TypedDict, TypeGuard +from urllib.parse import urlparse +from urllib.request import urlopen if TYPE_CHECKING: from collections.abc import Callable - from .env import JwtPayload + from .env import JwtHeader, JwtPayload class BaseJwtConfig(TypedDict, total=False): @@ -82,9 +84,34 @@ class EdDSAVerifyConfig(BaseJwtConfig): public_jwk: dict[str, Any] +class ES512VerifyConfig(BaseJwtConfig): + """ES512 (ECDSA P-521) asymmetric configuration for verification.""" + + alg: Literal["ES512"] + public_jwk: dict[str, Any] + + +class JWKSUrlVerifyConfig(BaseJwtConfig): + """Asymmetric verification configuration backed by a remote JWKS URL.""" + + alg: Literal["EdDSA", "ES256", "ES384", "ES512", "RS256", "RS384", "RS512"] + jwks_url: str + cache_ttl: int | None + + # Union types for convenience SignConfig = HS512Config | EdDSASignConfig -VerifyConfig = HS512Config | EdDSAVerifyConfig +VerifyConfig = HS512Config | EdDSAVerifyConfig | ES512VerifyConfig | JWKSUrlVerifyConfig + +ASYMMETRIC_VERIFY_ALGS = { + "EdDSA", + "ES256", + "ES384", + "ES512", + "RS256", + "RS384", + "RS512", +} def _b64url(b: bytes) -> str: @@ -97,6 +124,153 @@ def _b64url_decode(s: str) -> bytes: return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4)) +def _validate_jwks_url(url: str) -> None: + parsed = urlparse(url) + if not parsed.scheme or not parsed.netloc: + raise ValueError("JWT_JWKS_URL must be a valid URL") + if parsed.scheme == "https": + return + if parsed.scheme == "http" and parsed.hostname in {"localhost", "127.0.0.1", "::1"}: + return + raise ValueError("JWT_JWKS_URL must use HTTPS (except localhost for testing)") + + +def _ecdsa_curve_name(alg: str) -> str: + curves = { + "ES256": "P-256", + "ES384": "P-384", + "ES512": "P-521", + } + return curves[alg] + + +def _hash_name(alg: str) -> str: + hashes = { + "RS256": "SHA-256", + "RS384": "SHA-384", + "RS512": "SHA-512", + "ES256": "SHA-256", + "ES384": "SHA-384", + "ES512": "SHA-512", + } + return hashes[alg] + + +async def _fetch_jwks_from_url(url: str) -> list[dict[str, Any]]: + _validate_jwks_url(url) + + text: str + try: + from js import fetch as js_fetch # noqa: PLC0415 + except ImportError: + js_fetch = None + + if js_fetch is not None: + response = await js_fetch(url) + if not response.ok: + raise ValueError( + f"JWKS HTTP fetch returned {response.status}: {response.statusText}" + ) + text = await response.text() + else: + with urlopen(url) as response: # noqa: S310 + status = getattr(response, "status", response.getcode()) + if status < 200 or status >= 300: + raise ValueError(f"JWKS HTTP fetch returned {status}") + text = response.read().decode("utf-8") + + data = json.loads(text) + keys = data.get("keys") + if not isinstance(keys, list): + raise ValueError("Invalid JWKS response: missing keys array") + return keys + + +def _find_jwk_by_kid( + kid: str | None, jwks: list[dict[str, Any]] +) -> dict[str, Any] | None: + if not kid: + return None + for jwk in jwks: + if jwk.get("kid") == kid: + return jwk + return None + + +async def _import_verify_key( + alg: str, jwk: dict[str, Any] +) -> tuple[Any, dict[str, str]]: + from js import crypto # noqa: PLC0415 + + try: + from pyodide.ffi import to_js # noqa: PLC0415 + except ImportError: + + def to_js(value: Any) -> Any: + return value + + if alg == "EdDSA": + x_b64 = jwk.get("x") + if not x_b64: + raise ValueError("EdDSA public JWK must include x") + key = await crypto.subtle.importKey( + "raw", _b64url_decode(x_b64), {"name": "Ed25519"}, False, ["verify"] + ) + return key, {"name": "Ed25519"} + + if alg.startswith("RS"): + key = await crypto.subtle.importKey( + "jwk", + to_js(jwk), + {"name": "RSASSA-PKCS1-v1_5", "hash": _hash_name(alg)}, + False, + ["verify"], + ) + return key, {"name": "RSASSA-PKCS1-v1_5"} + + if alg.startswith("ES"): + key = await crypto.subtle.importKey( + "jwk", + to_js(jwk), + {"name": "ECDSA", "namedCurve": _ecdsa_curve_name(alg)}, + False, + ["verify"], + ) + return key, {"name": "ECDSA", "hash": _hash_name(alg)} + + raise ValueError(f"Unsupported verification algorithm: {alg}") + + +def _has_public_jwk( + config: VerifyConfig, +) -> TypeGuard[EdDSAVerifyConfig | ES512VerifyConfig]: + return "public_jwk" in config + + +def _has_jwks_url(config: VerifyConfig) -> TypeGuard[JWKSUrlVerifyConfig]: + return "jwks_url" in config + + +async def _verify_asymmetric_signature( + header: JwtHeader, + signing_input: bytes, + sig: bytes, + jwk: dict[str, Any], + *, + expected_alg: str | None = None, +) -> bool: + alg = header.get("alg") + if alg not in ASYMMETRIC_VERIFY_ALGS: + return False + if expected_alg is not None and alg != expected_alg: + return False + + from js import crypto # noqa: PLC0415 + + key, verify_algorithm = await _import_verify_key(alg, jwk) + return bool(await crypto.subtle.verify(verify_algorithm, key, sig, signing_input)) + + async def sign_with_config( payload: JwtPayload, config: SignConfig, @@ -139,7 +313,7 @@ async def sign_with_config( Signed JWT token string Raises: - ValueError: If secret is too short (< 32 bytes) + ValueError: If secret is too short (< 64 bytes) RuntimeError: If EdDSA signing is attempted (not supported in Python Workers) """ iss_val = iss or config.get("iss", "") @@ -155,8 +329,11 @@ async def sign_with_config( if config["alg"] == "HS512": secret = config["secret"] - if len(secret) < 32: - raise ValueError(f"JWT secret too short: {len(secret)} bytes, need >= 32") + # SECURITY: HS512 requires 64-byte minimum (SHA-512 digest size) + if len(secret) < 64: + raise ValueError( + f"JWT secret too short: {len(secret)} bytes, need >= 64 for HS512" + ) # Lazy import - only available in Cloudflare Workers/Pyodide runtime from js import crypto # noqa: PLC0415 @@ -235,15 +412,16 @@ async def verify_with_config( except Exception: return None - # Lazy import - only available in Cloudflare Workers/Pyodide runtime - from js import crypto # noqa: PLC0415 - if config["alg"] == "HS512": if header.get("alg") != "HS512": return None + # Lazy import - only available in Cloudflare Workers/Pyodide runtime + from js import crypto # noqa: PLC0415 + secret = config["secret"] - if len(secret) < 32: + # SECURITY: HS512 requires 64-byte minimum (SHA-512 digest size) + if len(secret) < 64: return None key = await crypto.subtle.importKey( @@ -259,23 +437,28 @@ async def verify_with_config( if not ok: return None else: - # EdDSA mode - if header.get("alg") != "EdDSA": - return None - - jwk = config["public_jwk"] - x_b64 = jwk.get("x") - if not x_b64: - return None - - x = _b64url_decode(x_b64) - key = await crypto.subtle.importKey( - "raw", x, {"name": "Ed25519"}, False, ["verify"] - ) - ok = await crypto.subtle.verify( - {"name": "Ed25519"}, key, sig, (h_b64 + "." + p_b64).encode() - ) - if not ok: + signing_input = (h_b64 + "." + p_b64).encode() + + if _has_public_jwk(config): + if not await _verify_asymmetric_signature( + header, + signing_input, + sig, + config["public_jwk"], + expected_alg=config["alg"], + ): + return None + elif _has_jwks_url(config): + jwk = _find_jwk_by_kid( + header.get("kid"), await _fetch_jwks_from_url(config["jwks_url"]) + ) + if not jwk: + return None + if not await _verify_asymmetric_signature( + header, signing_input, sig, jwk, expected_alg=config["alg"] + ): + return None + else: return None # Validate claims @@ -527,7 +710,7 @@ def create_hs512_config( """Helper function to create HS512 config from base64url-encoded secret. Args: - secret: Base64url-encoded secret string or raw bytes (minimum 32 bytes) + secret: Base64url-encoded secret string or raw bytes (minimum 64 bytes) iss: Token issuer aud: Token audience (string or list) ttl_seconds: Token lifetime in seconds (default: 900 = 15 minutes) @@ -537,7 +720,7 @@ def create_hs512_config( HS512Config Raises: - ValueError: If secret is too short (< 32 bytes) + ValueError: If secret is too short (< 64 bytes) """ if isinstance(secret, str): # Decode base64url @@ -545,8 +728,11 @@ def create_hs512_config( else: secret_bytes = secret - if len(secret_bytes) < 32: - raise ValueError(f"JWT secret too short: {len(secret_bytes)} bytes, need >= 32") + # SECURITY: HS512 requires 64-byte minimum (SHA-512 digest size) + if len(secret_bytes) < 64: + raise ValueError( + f"JWT secret too short: {len(secret_bytes)} bytes, need >= 64 for HS512" + ) return { "alg": "HS512", @@ -623,3 +809,48 @@ def create_eddsa_verify_config( "ttl_seconds": ttl_seconds, "leeway": leeway, } + + +def create_es512_verify_config( + public_jwk: dict[str, Any] | str, + *, + iss: str, + aud: str | list[str], + ttl_seconds: int = 900, + leeway: int = 90, +) -> ES512VerifyConfig: + """Helper function to create ES512 verify config from a public JWK.""" + jwk = json.loads(public_jwk) if isinstance(public_jwk, str) else public_jwk + + return { + "alg": "ES512", + "public_jwk": jwk, + "iss": iss, + "aud": aud, + "ttl_seconds": ttl_seconds, + "leeway": leeway, + } + + +def create_jwks_url_verify_config( + jwks_url: str, + *, + iss: str, + aud: str | list[str], + alg: Literal[ + "EdDSA", "ES256", "ES384", "ES512", "RS256", "RS384", "RS512" + ] = "EdDSA", + ttl_seconds: int = 900, + leeway: int = 90, + cache_ttl: int | None = None, +) -> JWKSUrlVerifyConfig: + """Helper function to create JWKS URL verification config.""" + return { + "alg": alg, + "jwks_url": jwks_url, + "cache_ttl": cache_ttl, + "iss": iss, + "aud": aud, + "ttl_seconds": ttl_seconds, + "leeway": leeway, + } diff --git a/packages/flarelette-jwt-py/flarelette_jwt/verify.py b/packages/flarelette-jwt-py/flarelette_jwt/verify.py index e99bb13..741dd1c 100644 --- a/packages/flarelette-jwt-py/flarelette_jwt/verify.py +++ b/packages/flarelette-jwt-py/flarelette_jwt/verify.py @@ -21,9 +21,15 @@ JwtPayload, common, get_hs_secret_bytes, + get_jwks_url, get_public_jwk_string, mode, ) +from .explicit import ( + _fetch_jwks_from_url, + _find_jwk_by_kid, + _verify_asymmetric_signature, +) def _b64url_decode(s: str) -> bytes: @@ -62,12 +68,12 @@ async def verify( except Exception: return None - # Lazy import - only available in Cloudflare Workers/Pyodide runtime - from js import crypto # noqa: PLC0415 - if m == "HS512": if header.get("alg") != "HS512": return None + # Lazy import - only available in Cloudflare Workers/Pyodide runtime + from js import crypto # noqa: PLC0415 + key = await crypto.subtle.importKey( "raw", get_hs_secret_bytes(), @@ -81,23 +87,20 @@ async def verify( if not ok: return None else: - if header.get("alg") != "EdDSA": - return None + signing_input = (h_b64 + "." + p_b64).encode() jwk_str = get_public_jwk_string() - if not jwk_str: - return None - jwk = json.loads(jwk_str) - x_b64 = jwk.get("x") - if not x_b64: + if jwk_str: + jwk = json.loads(jwk_str) + else: + jwks_url = get_jwks_url() + if not jwks_url: + return None + jwk = _find_jwk_by_kid( + header.get("kid"), await _fetch_jwks_from_url(jwks_url) + ) + if not jwk: return None - x = _b64url_decode(x_b64) - key = await crypto.subtle.importKey( - "raw", x, {"name": "Ed25519"}, False, ["verify"] - ) - ok = await crypto.subtle.verify( - {"name": "Ed25519"}, key, sig, (h_b64 + "." + p_b64).encode() - ) - if not ok: + if not await _verify_asymmetric_signature(header, signing_input, sig, jwk): return None now = int(time.time()) diff --git a/packages/flarelette-jwt-py/pyproject.toml b/packages/flarelette-jwt-py/pyproject.toml index 5c121b4..1c0c221 100644 --- a/packages/flarelette-jwt-py/pyproject.toml +++ b/packages/flarelette-jwt-py/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "flarelette-jwt" version = "1.12.0" -description = "Environment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection" +description = "Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers" readme = "README.md" requires-python = ">=3.11" license = { text = "MIT" } diff --git a/packages/flarelette-jwt-py/tests/test_explicit.py b/packages/flarelette-jwt-py/tests/test_explicit.py new file mode 100644 index 0000000..f0c03e2 --- /dev/null +++ b/packages/flarelette-jwt-py/tests/test_explicit.py @@ -0,0 +1,283 @@ +from __future__ import annotations + +import base64 +import json +import os +import sys +import time +import types +from typing import TYPE_CHECKING, Any, cast + +import pytest +from flarelette_jwt.explicit import ( + create_es512_verify_config, + create_jwks_url_verify_config, + verify_with_config, +) +from flarelette_jwt.verify import verify + +if TYPE_CHECKING: + from collections.abc import Iterator + + +def _b64url(data: bytes) -> str: + return base64.urlsafe_b64encode(data).decode("utf-8").rstrip("=") + + +def _make_token(header: dict[str, Any], payload: dict[str, Any]) -> str: + return ".".join( + [ + _b64url(json.dumps(header, separators=(",", ":")).encode("utf-8")), + _b64url(json.dumps(payload, separators=(",", ":")).encode("utf-8")), + _b64url(b"signature"), + ] + ) + + +class _FakeResponse: + def __init__(self, body: str) -> None: + self.ok = True + self.status = 200 + self.statusText = "OK" + self._body = body + + async def text(self) -> str: + return self._body + + +class _FakeSubtle: + def __init__(self) -> None: + self.import_calls: list[tuple[Any, ...]] = [] + self.verify_calls: list[tuple[Any, ...]] = [] + + async def importKey( + self, + format_name: str, + key_data: Any, + algorithm: dict[str, Any], + extractable: bool, + usages: list[str], + ) -> dict[str, Any]: + self.import_calls.append( + (format_name, key_data, algorithm, extractable, usages) + ) + return { + "format_name": format_name, + "key_data": key_data, + "algorithm": algorithm, + "extractable": extractable, + "usages": usages, + } + + async def verify( + self, algorithm: dict[str, Any], key: dict[str, Any], sig: bytes, data: bytes + ) -> bool: + self.verify_calls.append((algorithm, key, sig, data)) + return True + + +class _FakeFetch: + def __init__(self, body: str) -> None: + self.body = body + self.urls: list[str] = [] + + async def __call__(self, url: str) -> _FakeResponse: + self.urls.append(url) + return _FakeResponse(self.body) + + +def _install_runtime( + monkeypatch: pytest.MonkeyPatch, *, jwks_keys: list[dict[str, Any]] | None = None +) -> tuple[_FakeSubtle, _FakeFetch | None]: + subtle = _FakeSubtle() + js_module = cast("Any", types.ModuleType("js")) + js_module.crypto = types.SimpleNamespace(subtle=subtle) + + fetch = None + if jwks_keys is not None: + fetch = _FakeFetch(json.dumps({"keys": jwks_keys})) + js_module.fetch = fetch + + ffi_module = cast("Any", types.ModuleType("pyodide.ffi")) + ffi_module.to_js = lambda value: value + + pyodide_module = cast("Any", types.ModuleType("pyodide")) + pyodide_module.ffi = ffi_module + + monkeypatch.setitem(sys.modules, "js", js_module) + monkeypatch.setitem(sys.modules, "pyodide", pyodide_module) + monkeypatch.setitem(sys.modules, "pyodide.ffi", ffi_module) + + return subtle, fetch + + +@pytest.fixture(autouse=True) +def _clear_env() -> Iterator[None]: + keys = [ + "JWT_SECRET", + "JWT_SECRET_NAME", + "JWT_PUBLIC_JWK", + "JWT_PUBLIC_JWK_NAME", + "JWT_JWKS_URL", + "JWT_JWKS_URL_NAME", + "JWT_ISS", + "JWT_AUD", + "JWT_LEEWAY", + "JWT_TTL_SECONDS", + ] + previous = {key: os.environ.get(key) for key in keys} + for key in keys: + os.environ.pop(key, None) + + yield + + for key, value in previous.items(): + if value is None: + os.environ.pop(key, None) + else: + os.environ[key] = value + + +def test_create_jwks_url_verify_config_supports_explicit_algorithm() -> None: + config = create_jwks_url_verify_config( + "https://tenant.auth0.com/.well-known/jwks.json", + iss="https://tenant.auth0.com/", + aud="my-app-client-id", + alg="RS256", + cache_ttl=600, + ) + + assert config["alg"] == "RS256" + assert config["cache_ttl"] == 600 + + +@pytest.mark.asyncio +async def test_verify_with_config_supports_explicit_es512( + monkeypatch: pytest.MonkeyPatch, +) -> None: + subtle, _ = _install_runtime(monkeypatch) + now = int(time.time()) + token = _make_token( + {"alg": "ES512", "kid": "es-key"}, + { + "sub": "user-es512", + "iss": "issuer", + "aud": "audience", + "iat": now, + "exp": now + 60, + }, + ) + + config = create_es512_verify_config( + {"kty": "EC", "crv": "P-521", "x": "x", "y": "y"}, + iss="issuer", + aud="audience", + ) + + payload = await verify_with_config(token, config) + + assert payload is not None + assert payload["sub"] == "user-es512" + assert subtle.import_calls[0][2]["namedCurve"] == "P-521" + assert subtle.verify_calls[0][0]["hash"] == "SHA-512" + + +@pytest.mark.asyncio +async def test_verify_with_config_supports_jwks_rs256( + monkeypatch: pytest.MonkeyPatch, +) -> None: + subtle, fetch = _install_runtime( + monkeypatch, + jwks_keys=[ + {"kid": "rsa-key", "kty": "RSA", "alg": "RS256", "n": "abc", "e": "AQAB"} + ], + ) + now = int(time.time()) + token = _make_token( + {"alg": "RS256", "kid": "rsa-key"}, + { + "sub": "user-rs256", + "iss": "issuer", + "aud": "audience", + "iat": now, + "exp": now + 60, + }, + ) + + config = create_jwks_url_verify_config( + "https://issuer.example/.well-known/jwks.json", + iss="issuer", + aud="audience", + alg="RS256", + ) + + payload = await verify_with_config(token, config) + + assert payload is not None + assert payload["sub"] == "user-rs256" + assert fetch is not None + assert fetch.urls == ["https://issuer.example/.well-known/jwks.json"] + assert subtle.import_calls[0][2]["hash"] == "SHA-256" + + +@pytest.mark.asyncio +async def test_verify_supports_env_inline_es512( + monkeypatch: pytest.MonkeyPatch, +) -> None: + subtle, _ = _install_runtime(monkeypatch) + os.environ["JWT_PUBLIC_JWK"] = json.dumps( + {"kty": "EC", "crv": "P-521", "x": "x", "y": "y"} + ) + os.environ["JWT_ISS"] = "issuer" + os.environ["JWT_AUD"] = "audience" + + now = int(time.time()) + token = _make_token( + {"alg": "ES512", "kid": "es-key"}, + { + "sub": "env-es512", + "iss": "issuer", + "aud": "audience", + "iat": now, + "exp": now + 60, + }, + ) + + payload = await verify(token) + + assert payload is not None + assert payload["sub"] == "env-es512" + assert subtle.import_calls[0][2]["namedCurve"] == "P-521" + + +@pytest.mark.asyncio +async def test_verify_supports_env_jwks_rs256(monkeypatch: pytest.MonkeyPatch) -> None: + subtle, fetch = _install_runtime( + monkeypatch, + jwks_keys=[ + {"kid": "rsa-key", "kty": "RSA", "alg": "RS256", "n": "abc", "e": "AQAB"} + ], + ) + os.environ["JWT_JWKS_URL"] = "https://issuer.example/.well-known/jwks.json" + os.environ["JWT_ISS"] = "issuer" + os.environ["JWT_AUD"] = "audience" + + now = int(time.time()) + token = _make_token( + {"alg": "RS256", "kid": "rsa-key"}, + { + "sub": "env-rs256", + "iss": "issuer", + "aud": "audience", + "iat": now, + "exp": now + 60, + }, + ) + + payload = await verify(token) + + assert payload is not None + assert payload["sub"] == "env-rs256" + assert fetch is not None + assert fetch.urls == ["https://issuer.example/.well-known/jwks.json"] + assert subtle.import_calls[0][2]["hash"] == "SHA-256" diff --git a/packages/flarelette-jwt-py/tests/test_sign_verify.py b/packages/flarelette-jwt-py/tests/test_sign_verify.py index 4c9c83b..8347d3b 100644 --- a/packages/flarelette-jwt-py/tests/test_sign_verify.py +++ b/packages/flarelette-jwt-py/tests/test_sign_verify.py @@ -83,19 +83,11 @@ def setup_env(self) -> Generator[None, None, None]: def test_mode_defaults_to_hs512(self) -> None: """Should default to HS512 mode when no keys configured.""" - import importlib.util - - spec = importlib.util.spec_from_file_location( - "env", "packages/flarelette-jwt-py/flarelette_jwt/env.py" - ) - if spec and spec.loader: - env_module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(env_module) - - mode = env_module.mode + env = _load_env_module() + mode = env.mode - assert mode("producer") == "HS512" - assert mode("consumer") == "HS512" + assert mode("producer") == "HS512" + assert mode("consumer") == "HS512" def test_mode_detects_eddsa_for_producer_with_private_key(self) -> None: """Should detect EdDSA mode for producer with private key.""" @@ -181,3 +173,63 @@ def test_public_key_name_indirection_detection(self) -> None: os.environ["JWT_PUBLIC_JWK_NAME"] = "MY_PUBLIC_KEY" assert mode("consumer") == "EdDSA" + + def test_jwks_url_name_indirection_detection(self) -> None: + """Should detect EdDSA with JWT_JWKS_URL_NAME.""" + env = _load_env_module() + mode = env.mode + + os.environ["JWT_JWKS_URL_NAME"] = "MY_JWKS_URL" + assert mode("consumer") == "EdDSA" + + def test_mode_conflict_raises_for_consumer(self) -> None: + """Should raise RuntimeError when both HS512 and asymmetric keys configured.""" + import pytest + + env = _load_env_module() + mode = env.mode + + os.environ["JWT_SECRET"] = "some-secret" + os.environ["JWT_PUBLIC_JWK"] = "some-public-key" + + with pytest.raises(RuntimeError, match="algorithm confusion"): + mode("consumer") + + def test_mode_conflict_does_not_raise_for_producer(self) -> None: + """Mode conflict check only applies to consumer role.""" + env = _load_env_module() + mode = env.mode + + # Producer ignores public keys entirely — no conflict error + os.environ["JWT_SECRET"] = "some-secret" + os.environ["JWT_PUBLIC_JWK"] = "some-public-key" + + # Should not raise; producer checks only for private key + assert mode("producer") == "HS512" + + def test_hs512_secret_minimum_64_bytes(self) -> None: + """get_hs_secret_bytes should reject secrets shorter than 64 bytes.""" + import base64 + + import pytest + + env = _load_env_module() + + # 32-byte secret — previously accepted, now rejected + short_secret = base64.urlsafe_b64encode(b"a" * 32).rstrip(b"=").decode() + os.environ["JWT_SECRET"] = short_secret + + with pytest.raises(RuntimeError, match="too short"): + env.get_hs_secret_bytes() + + def test_hs512_secret_accepts_64_bytes(self) -> None: + """get_hs_secret_bytes should accept secrets of exactly 64 bytes.""" + import base64 + + env = _load_env_module() + + valid_secret = base64.urlsafe_b64encode(b"a" * 64).rstrip(b"=").decode() + os.environ["JWT_SECRET"] = valid_secret + + result = env.get_hs_secret_bytes() + assert len(result) == 64 diff --git a/packages/flarelette-jwt-py/tests/test_sign_verify_mocked.py b/packages/flarelette-jwt-py/tests/test_sign_verify_mocked.py index f0d89e7..c25ac4f 100644 --- a/packages/flarelette-jwt-py/tests/test_sign_verify_mocked.py +++ b/packages/flarelette-jwt-py/tests/test_sign_verify_mocked.py @@ -6,6 +6,7 @@ from __future__ import annotations +import base64 import os from typing import TYPE_CHECKING, cast @@ -31,9 +32,9 @@ class TestSignVerifyWithMock: @pytest.fixture(autouse=True) def setup_env(self) -> Generator[None, None, None]: """Setup environment for each test.""" - # Set up HS512 mode with mock secret + # Set up HS512 mode with a valid 64-byte base64url secret os.environ["JWT_SECRET"] = ( - "dGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC1mb3ItaG1hYy1zaGE1MTI" + base64.urlsafe_b64encode(b"a" * 64).rstrip(b"=").decode() ) os.environ["JWT_ISS"] = "test-issuer" os.environ["JWT_AUD"] = "test-audience" diff --git a/packages/flarelette-jwt-ts/package.json b/packages/flarelette-jwt-ts/package.json index 7a63162..c22b457 100644 --- a/packages/flarelette-jwt-ts/package.json +++ b/packages/flarelette-jwt-ts/package.json @@ -1,8 +1,8 @@ { "name": "@chrislyons-dev/flarelette-jwt", - "version": "1.13.0", + "version": "1.14.0", "type": "module", - "description": "Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection", + "description": "TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers", "keywords": [ "jwt", "authentication", diff --git a/packages/flarelette-jwt-ts/src/config.ts b/packages/flarelette-jwt-ts/src/config.ts index 41505f1..0105504 100644 --- a/packages/flarelette-jwt-ts/src/config.ts +++ b/packages/flarelette-jwt-ts/src/config.ts @@ -41,7 +41,8 @@ export function envMode(role: 'producer' | 'consumer'): AlgType { env.JWT_PUBLIC_JWK_NAME || env.JWT_JWKS_SERVICE || env.JWT_JWKS_SERVICE_NAME || - env.JWT_JWKS_URL + env.JWT_JWKS_URL || + env.JWT_JWKS_URL_NAME ) if (hasHS512 && hasAsymmetric) { @@ -142,6 +143,8 @@ export function getJwksServiceName(): string | null { } export function getJwksUrl(): string | null { + const name = envRead('JWT_JWKS_URL_NAME') as string | undefined + if (name && envRead(name)) return envRead(name)! return envRead('JWT_JWKS_URL') || null } diff --git a/packages/flarelette-jwt-ts/src/explicit.ts b/packages/flarelette-jwt-ts/src/explicit.ts index 8f59e8c..abb5ece 100644 --- a/packages/flarelette-jwt-ts/src/explicit.ts +++ b/packages/flarelette-jwt-ts/src/explicit.ts @@ -67,11 +67,33 @@ export interface EdDSAVerifyConfig extends BaseJwtConfig { } /** - * EdDSA/RSA asymmetric configuration for verification via HTTP JWKS + * ES512 (ECDSA P-521) asymmetric configuration for signing + * Uses a private EC key to sign tokens + */ +export interface ES512SignConfig extends BaseJwtConfig { + alg: 'ES512' + /** Private JWK for signing (P-521 EC key) */ + privateJwk: JWK + /** Key ID to include in JWT header */ + kid?: string +} + +/** + * ES512 (ECDSA P-521) asymmetric configuration for verification + * Uses a public EC key to verify tokens + */ +export interface ES512VerifyConfig extends BaseJwtConfig { + alg: 'ES512' + /** Public JWK for verification (P-521 EC key) */ + publicJwk: JWK +} + +/** + * EdDSA/RSA/ECDSA asymmetric configuration for verification via HTTP JWKS * Uses a remote JWKS endpoint to fetch public keys (supports key rotation) */ export interface JWKSUrlVerifyConfig extends BaseJwtConfig { - alg: 'EdDSA' | 'RS256' | 'RS384' | 'RS512' + alg: 'EdDSA' | 'ES256' | 'ES384' | 'ES512' | 'RS256' | 'RS384' | 'RS512' /** HTTP(S) URL to JWKS endpoint */ jwksUrl: string /** Cache TTL in seconds (default: 300) */ @@ -81,12 +103,18 @@ export interface JWKSUrlVerifyConfig extends BaseJwtConfig { /** * Union type for signing configuration */ -export type SignConfig = HS512Config | EdDSASignConfig +export type SignConfig = HS512Config | EdDSASignConfig | ES512SignConfig /** * Union type for verification configuration */ -export type VerifyConfig = HS512Config | EdDSAVerifyConfig | JWKSUrlVerifyConfig +export type VerifyConfig = + | HS512Config + | EdDSAVerifyConfig + | ES512VerifyConfig + | JWKSUrlVerifyConfig + +type JWKSUrlVerifyAlg = JWKSUrlVerifyConfig['alg'] /** * Sign a JWT token with explicit configuration @@ -129,7 +157,11 @@ export async function signWithConfig( const ttlSeconds = overrides?.ttlSeconds ?? config.ttlSeconds ?? 900 const now = Math.floor(Date.now() / 1000) - const jwt = new SignJWT(payload) + // Auto-generate jti if absent — required for JTI revocation and isDuress auto-revocation + const claims: JwtPayload = payload.jti + ? payload + : { ...payload, jti: crypto.randomUUID() } + const jwt = new SignJWT(claims) .setIssuer(iss) .setAudience(aud) .setIssuedAt(now) @@ -143,6 +175,15 @@ export async function signWithConfig( ) } return jwt.setProtectedHeader({ alg: 'HS512', typ: 'JWT' }).sign(config.secret) + } else if (config.alg === 'ES512') { + const key = await importJWK(config.privateJwk, 'ES512') + return jwt + .setProtectedHeader({ + alg: 'ES512', + typ: 'JWT', + kid: (config as ES512SignConfig).kid, + }) + .sign(key) } else { const key = await importJWK(config.privateJwk, 'EdDSA') return jwt @@ -205,9 +246,13 @@ export async function verifyWithConfig( clockTolerance: leeway, }) } else if ('publicJwk' in config) { - // Inline JWK verification - const key = await importJWK(config.publicJwk, 'EdDSA') + // Inline JWK verification — EdDSA needs explicit hint; EC/RSA auto-detected by jose + const key = + (config.publicJwk as JWK).kty === 'OKP' + ? await importJWK(config.publicJwk, 'EdDSA') + : await importJWK(config.publicJwk) result = await jwtVerify(token, key, { + algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'], issuer: iss, audience: aud, clockTolerance: leeway, @@ -219,7 +264,7 @@ export async function verifyWithConfig( const key = await getKeyFromJwks(header.kid, jwks) result = await jwtVerify(token, key, { - algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512'], + algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'], issuer: iss, audience: aud, clockTolerance: leeway, @@ -486,6 +531,49 @@ export function createEdDSAVerifyConfig( } } +/** + * Helper function to create ES512 sign config from a P-521 EC private JWK + * + * @param privateJwk - Private JWK object or JSON string (EC P-521 key) + * @param baseConfig - Base JWT configuration + * @param kid - Optional key ID + * @returns ES512 sign configuration + */ +export function createES512SignConfig( + privateJwk: JWK | string, + baseConfig: Omit & + Partial>, + kid?: string +): ES512SignConfig { + const jwk = typeof privateJwk === 'string' ? JSON.parse(privateJwk) : privateJwk + return { + alg: 'ES512', + privateJwk: jwk, + kid, + ...baseConfig, + } +} + +/** + * Helper function to create ES512 verify config from a P-521 EC public JWK + * + * @param publicJwk - Public JWK object or JSON string (EC P-521 key) + * @param baseConfig - Base JWT configuration + * @returns ES512 verify configuration + */ +export function createES512VerifyConfig( + publicJwk: JWK | string, + baseConfig: Omit & + Partial> +): ES512VerifyConfig { + const jwk = typeof publicJwk === 'string' ? JSON.parse(publicJwk) : publicJwk + return { + alg: 'ES512', + publicJwk: jwk, + ...baseConfig, + } +} + /** * Helper function to create HTTP JWKS URL verification config * @@ -515,9 +603,39 @@ export function createJWKSUrlVerifyConfig( baseConfig: Omit & Partial>, cacheTtl?: number +): JWKSUrlVerifyConfig +export function createJWKSUrlVerifyConfig( + jwksUrl: string, + alg: JWKSUrlVerifyAlg, + baseConfig: Omit & + Partial>, + cacheTtl?: number +): JWKSUrlVerifyConfig +export function createJWKSUrlVerifyConfig( + jwksUrl: string, + algOrBaseConfig: + | JWKSUrlVerifyAlg + | (Omit & + Partial>), + baseConfigOrCacheTtl?: + | (Omit & + Partial>) + | number, + maybeCacheTtl?: number ): JWKSUrlVerifyConfig { + const alg = typeof algOrBaseConfig === 'string' ? algOrBaseConfig : 'EdDSA' + const baseConfig = + typeof algOrBaseConfig === 'string' + ? (baseConfigOrCacheTtl as Omit & + Partial>) + : algOrBaseConfig + const cacheTtl = + typeof algOrBaseConfig === 'string' + ? maybeCacheTtl + : (baseConfigOrCacheTtl as number | undefined) + return { - alg: 'EdDSA', // Default, will support RSA via JWKS + alg, jwksUrl, cacheTtl, ...baseConfig, diff --git a/packages/flarelette-jwt-ts/src/high.ts b/packages/flarelette-jwt-ts/src/high.ts index 0a875f4..5fb1d28 100644 --- a/packages/flarelette-jwt-ts/src/high.ts +++ b/packages/flarelette-jwt-ts/src/high.ts @@ -6,6 +6,7 @@ */ import { sign } from './sign.js' import { verify } from './verify.js' +import { computeRequestHash } from './util.js' import type { Fetcher, JwtPayload } from './types.js' /** @@ -95,6 +96,62 @@ export async function createDelegatedToken( return sign(delegatedClaims, opts) } +/** + * Sign a JWT token bound to a specific HTTP request. + * + * Adds a `req` claim containing base64url(SHA-256(canonical request)) to prevent + * replay of a captured token against a different endpoint within the TTL window. + * + * Canonical form: METHOD + "\n" + pathname + search + "\n" + body bytes + * + * @param payload - Claims to include in the token + * @param request - The HTTP request this token is minted for + * @param opts - Optional overrides for iss, aud, ttlSeconds + * @returns Signed JWT token string with req claim + */ +export async function signWithRequestBinding( + payload: JwtPayload, + request: Request, + opts?: Partial<{ iss: string; aud: string | string[]; ttlSeconds: number }> +): Promise { + const req = await computeRequestHash(request) + return sign({ ...payload, req }, opts) +} + +/** + * Verify a JWT token and validate its request binding. + * + * Re-computes the request hash and compares it with the `req` claim. + * Returns null on any mismatch (fail-silent, same as verify()). + * The `req` claim is stripped from the returned payload — it's an implementation + * detail that has already been validated. + * + * @param token - JWT token string to verify + * @param request - The HTTP request to validate against + * @param opts - Optional overrides for iss, aud, leeway + * @returns Payload (without req claim) if valid and request matches, null otherwise + */ +export async function verifyWithRequestBinding( + token: string, + request: Request, + opts?: Partial<{ + iss: string + aud: string | string[] + leeway: number + jwksService: Fetcher + }> +): Promise { + const payload = await verify(token, opts) + if (!payload) return null + + const expected = await computeRequestHash(request) + if (payload.req !== expected) return null + + // Strip req — it's validated, no need to expose it downstream + const { req: _req, ...rest } = payload + return rest as JwtPayload +} + /** * Authorization options for checkAuth * diff --git a/packages/flarelette-jwt-ts/src/index.ts b/packages/flarelette-jwt-ts/src/index.ts index d64e55c..aecf6e6 100644 --- a/packages/flarelette-jwt-ts/src/index.ts +++ b/packages/flarelette-jwt-ts/src/index.ts @@ -26,10 +26,17 @@ export { sign } from './sign.js' export { verify } from './verify.js' // Utilities -export { parse, isExpiringSoon } from './util.js' +export { parse, isExpiringSoon, computeRequestHash } from './util.js' // High-level API -export { createToken, createDelegatedToken, checkAuth, policy } from './high.js' +export { + createToken, + createDelegatedToken, + checkAuth, + policy, + signWithRequestBinding, + verifyWithRequestBinding, +} from './high.js' export type { AuthzOpts, AuthUser } from './high.js' // Secret generation @@ -63,6 +70,8 @@ export { createHS512Config, createEdDSASignConfig, createEdDSAVerifyConfig, + createES512SignConfig, + createES512VerifyConfig, createJWKSUrlVerifyConfig, } from './explicit.js' @@ -71,6 +80,8 @@ export type { HS512Config, EdDSASignConfig, EdDSAVerifyConfig, + ES512SignConfig, + ES512VerifyConfig, JWKSUrlVerifyConfig, SignConfig, VerifyConfig, diff --git a/packages/flarelette-jwt-ts/src/keygen.ts b/packages/flarelette-jwt-ts/src/keygen.ts index d7d05b8..27ad283 100644 --- a/packages/flarelette-jwt-ts/src/keygen.ts +++ b/packages/flarelette-jwt-ts/src/keygen.ts @@ -1,30 +1,49 @@ #!/usr/bin/env node /** - * Key generation utility for EdDSA keys. + * Key generation utility for EdDSA and ECDSA keys. * - * This script generates EdDSA key pairs and exports them in JWK format. - * It is designed to be executed as a standalone Node.js script. + * Generates asymmetric key pairs and exports them in JWK format. + * Designed to be executed as a standalone Node.js script. * * @module util - * */ import { generateKeyPair, exportJWK } from 'jose' +const SUPPORTED_ALGS = ['EdDSA', 'ES256', 'ES384', 'ES512'] as const + async function main() { + const alg = + (process.argv.find(a => a.startsWith('--alg='))?.split('=')[1] as string) ?? 'EdDSA' const kid = - process.argv.find(a => a.startsWith('--kid='))?.split('=')[1] || - `ed25519-${Date.now()}` - const { publicKey, privateKey } = await generateKeyPair('EdDSA') + process.argv.find(a => a.startsWith('--kid='))?.split('=')[1] ?? + `${alg.toLowerCase()}-${Date.now()}` + const dotenv = process.argv.includes('--dotenv') + + if (!(SUPPORTED_ALGS as readonly string[]).includes(alg)) { + console.error( + `Unsupported algorithm: ${alg}. Use one of: ${SUPPORTED_ALGS.join(', ')}` + ) + process.exit(1) + } + + const { publicKey, privateKey } = await generateKeyPair(alg, { extractable: true }) const pub = await exportJWK(publicKey) const prv = await exportJWK(privateKey) pub.kid = kid prv.kid = kid - pub.alg = 'EdDSA' + pub.alg = alg pub.use = 'sig' - console.log(JSON.stringify({ publicJwk: pub, privateJwk: prv }, null, 2)) + + if (dotenv) { + console.log(`JWT_PUBLIC_JWK='${JSON.stringify(pub)}'`) + console.log(`JWT_PRIVATE_JWK='${JSON.stringify(prv)}'`) + } else { + console.log(JSON.stringify({ publicJwk: pub, privateJwk: prv }, null, 2)) + } } + main().catch(e => { console.error(e) process.exit(1) diff --git a/packages/flarelette-jwt-ts/src/sign.ts b/packages/flarelette-jwt-ts/src/sign.ts index 16e4180..87774d3 100644 --- a/packages/flarelette-jwt-ts/src/sign.ts +++ b/packages/flarelette-jwt-ts/src/sign.ts @@ -26,7 +26,11 @@ export async function sign( const mode: AlgType = envMode('producer') const { iss, aud, ttlSeconds } = { ...getCommon(), ...(opts || {}) } const now = Math.floor(Date.now() / 1000) - const jwt = new SignJWT(payload) + // Auto-generate jti if absent — required for JTI revocation and isDuress auto-revocation + const claims: JwtPayload = payload.jti + ? payload + : { ...payload, jti: crypto.randomUUID() } + const jwt = new SignJWT(claims) .setIssuer(iss) .setAudience(aud) .setIssuedAt(now) diff --git a/packages/flarelette-jwt-ts/src/types.ts b/packages/flarelette-jwt-ts/src/types.ts index 9a93f40..5e5fb7f 100644 --- a/packages/flarelette-jwt-ts/src/types.ts +++ b/packages/flarelette-jwt-ts/src/types.ts @@ -56,8 +56,8 @@ export type ClaimsDict = Record * EdDSA deployments with multiple active keys. */ export interface JwtHeader { - /** Algorithm: HS512 or EdDSA */ - alg: AlgType + /** Algorithm as reported in the JWT header (e.g. HS512, EdDSA, ES512, RS256) */ + alg: string /** Token type, typically "JWT" */ typ?: string /** Key ID for key rotation (optional) */ @@ -142,6 +142,16 @@ export interface JwtPayload { /** Service acting on behalf of subject */ act?: ActorClaim + // Duress credential + /** + * Set server-side when a duress passkey assertion is detected. + * The OIDC Worker sets this based on which credentialId asserted; the Gateway + * copies it into the internal JWT. Downstream Workers must not deny access or + * fail closed when true — a duress session must look like success to the user. + * Never set by clients. + */ + isDuress?: boolean + /** Additional custom claims */ [key: string]: unknown } @@ -241,6 +251,7 @@ export interface WorkerEnv extends Record { // HTTP JWKS (TypeScript only - Python support pending) JWT_JWKS_URL?: string + JWT_JWKS_URL_NAME?: string JWT_JWKS_CACHE_TTL_SECONDS?: string // Thumbprint pinning diff --git a/packages/flarelette-jwt-ts/src/util.ts b/packages/flarelette-jwt-ts/src/util.ts index c44b49a..779795f 100644 --- a/packages/flarelette-jwt-ts/src/util.ts +++ b/packages/flarelette-jwt-ts/src/util.ts @@ -47,3 +47,38 @@ export function isExpiringSoon(payload: JwtPayload, seconds: number): boolean { export function mapScopesToPermissions(scopes: string[]): string[] { return scopes } + +/** + * Compute a deterministic SHA-256 hash that binds a JWT to a specific HTTP request. + * + * Canonical form: UTF-8(METHOD + "\n" + pathname + search + "\n") || body_bytes + * - Method is uppercased + * - Binds to path and query string only (not host/scheme — internal Workers use different hostnames) + * - Body is consumed from a clone to preserve the original stream + * + * @param request - Fetch API Request object + * @returns base64url-encoded SHA-256 hash of the canonical request representation + */ +export async function computeRequestHash(request: Request): Promise { + const url = new URL(request.url) + const prefix = new TextEncoder().encode( + `${request.method.toUpperCase()}\n${url.pathname}${url.search}\n` + ) + + let bodyBytes = new Uint8Array(0) + if (request.body) { + const cloned = request.clone() + bodyBytes = new Uint8Array(await cloned.arrayBuffer()) + } + + const combined = new Uint8Array(prefix.length + bodyBytes.length) + combined.set(prefix, 0) + combined.set(bodyBytes, prefix.length) + + const digest = await crypto.subtle.digest('SHA-256', combined) + // base64url encode without external deps + return btoa(String.fromCharCode(...new Uint8Array(digest))) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, '') +} diff --git a/packages/flarelette-jwt-ts/src/verify.ts b/packages/flarelette-jwt-ts/src/verify.ts index 17f8a3f..466c646 100644 --- a/packages/flarelette-jwt-ts/src/verify.ts +++ b/packages/flarelette-jwt-ts/src/verify.ts @@ -71,8 +71,7 @@ async function resolveVerificationKey( // SECURITY: Detect algorithm from JWK structure. If JWK has explicit alg field, jose will use it. // For EdDSA keys (kty=OKP, crv=Ed25519), explicitly specify 'EdDSA' for compatibility. // Algorithm whitelist in jwtVerify() provides defense-in-depth protection. - const isEdDSA = jwk.kty === 'OKP' && jwk.crv === 'Ed25519' - const key = isEdDSA ? await importJWK(jwk, 'EdDSA') : await importJWK(jwk) + const key = jwk.kty === 'OKP' ? await importJWK(jwk, 'EdDSA') : await importJWK(jwk) // Optional thumbprint pinning const pins = allowedThumbprints() @@ -85,7 +84,7 @@ async function resolveVerificationKey( return { key, - algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512'], + algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'], } } @@ -97,7 +96,7 @@ async function resolveVerificationKey( return { key, - algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512'], + algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'], } } @@ -111,7 +110,7 @@ async function resolveVerificationKey( return { key, - algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512'], + algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512'], } } diff --git a/packages/flarelette-jwt-ts/tests/config.test.ts b/packages/flarelette-jwt-ts/tests/config.test.ts index f4041dc..d499e04 100644 --- a/packages/flarelette-jwt-ts/tests/config.test.ts +++ b/packages/flarelette-jwt-ts/tests/config.test.ts @@ -5,7 +5,7 @@ import { getHSSecret, getJwksUrl, getJwksCacheTtl, -} from '../src/config' +} from '../src/config.js' describe('Config - envMode', () => { beforeEach(() => { @@ -255,6 +255,7 @@ describe('Config - JWT_JWKS_URL Detection', () => { delete process.env.JWT_JWKS_SERVICE delete process.env.JWT_JWKS_SERVICE_NAME delete process.env.JWT_JWKS_URL + delete process.env.JWT_JWKS_URL_NAME delete process.env.JWT_SECRET delete process.env.JWT_SECRET_NAME }) @@ -310,17 +311,43 @@ describe('Config - JWT_JWKS_URL Detection', () => { expect(() => envMode('consumer')).not.toThrow() expect(envMode('consumer')).toBe('HS512') }) + + it('should detect EdDSA mode for consumer with JWT_JWKS_URL_NAME', () => { + process.env.JWT_JWKS_URL_NAME = 'MY_JWKS_URL' + expect(envMode('consumer')).toBe('EdDSA') + }) + + it('should detect EdDSA mode when JWT_JWKS_URL_NAME is set but JWT_JWKS_URL is absent', () => { + process.env.JWT_JWKS_URL_NAME = 'MY_JWKS_URL' + // JWT_JWKS_URL is not set — indirection name alone is enough for mode detection + expect(process.env.JWT_JWKS_URL).toBeUndefined() + expect(envMode('consumer')).toBe('EdDSA') + }) + + it('should throw error if JWT_SECRET and JWT_JWKS_URL_NAME both configured', () => { + process.env.JWT_SECRET = Buffer.from('a'.repeat(64)).toString('base64url') + process.env.JWT_JWKS_URL_NAME = 'MY_JWKS_URL' + + expect(() => envMode('consumer')).toThrow( + 'Configuration error: Both HS512 (JWT_SECRET) and asymmetric (JWT_PUBLIC_JWK/JWT_JWKS_*) secrets configured' + ) + }) }) describe('Config - getJwksUrl', () => { beforeEach(() => { delete process.env.JWT_JWKS_URL + delete process.env.JWT_JWKS_URL_NAME }) afterEach(() => { delete (globalThis as { __FLARELETTE_ENV?: unknown }).__FLARELETTE_ENV }) + it('should return null when neither JWT_JWKS_URL nor JWT_JWKS_URL_NAME is set', () => { + expect(getJwksUrl()).toBeNull() + }) + it('should return null when JWT_JWKS_URL not set', () => { expect(getJwksUrl()).toBeNull() }) @@ -344,6 +371,25 @@ describe('Config - getJwksUrl', () => { } expect(getJwksUrl()).toBe('https://global.example.com/jwks.json') }) + + it('should read URL via JWT_JWKS_URL_NAME indirection', () => { + process.env.JWT_JWKS_URL_NAME = 'MY_JWKS_BINDING' + process.env.MY_JWKS_BINDING = 'https://indirected.example.com/.well-known/jwks.json' + expect(getJwksUrl()).toBe('https://indirected.example.com/.well-known/jwks.json') + }) + + it('should return null when JWT_JWKS_URL_NAME set but binding is unset', () => { + process.env.JWT_JWKS_URL_NAME = 'NONEXISTENT_JWKS_BINDING_12345' + delete process.env.NONEXISTENT_JWKS_BINDING_12345 + // Binding name is set but the binding itself is undefined → falls back to JWT_JWKS_URL (also unset) + expect(getJwksUrl()).toBeNull() + }) + + it('JWT_JWKS_URL takes precedence when JWT_JWKS_URL_NAME is not set', () => { + process.env.JWT_JWKS_URL = 'https://direct.example.com/.well-known/jwks.json' + // JWT_JWKS_URL_NAME not set, so JWT_JWKS_URL is used + expect(getJwksUrl()).toBe('https://direct.example.com/.well-known/jwks.json') + }) }) describe('Config - getJwksCacheTtl', () => { diff --git a/packages/flarelette-jwt-ts/tests/explicit-jwks.test.ts b/packages/flarelette-jwt-ts/tests/explicit-jwks.test.ts index cfecee9..e95cc9e 100644 --- a/packages/flarelette-jwt-ts/tests/explicit-jwks.test.ts +++ b/packages/flarelette-jwt-ts/tests/explicit-jwks.test.ts @@ -41,6 +41,19 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { }) }) + test('should allow explicit RSA algorithm selection', () => { + const config = createJWKSUrlVerifyConfig( + 'https://tenant.auth0.com/.well-known/jwks.json', + 'RS256', + { + iss: 'https://tenant.auth0.com/', + aud: 'my-app-client-id', + } + ) + + expect(config.alg).toBe('RS256') + }) + test('should accept custom cache TTL', () => { const config = createJWKSUrlVerifyConfig( 'https://tenant.auth0.com/.well-known/jwks.json', @@ -351,6 +364,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://auth0.example.com/.well-known/jwks.json', + 'RS256', { iss: 'https://auth0.example.com/', aud: 'api-client-id', @@ -386,6 +400,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://example.com/.well-known/jwks.json', + 'RS384', { iss: 'https://example.com/', aud: 'my-app', @@ -419,6 +434,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://example.com/.well-known/jwks.json', + 'RS512', { iss: 'https://example.com/', aud: 'my-app', @@ -459,6 +475,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://example.com/.well-known/jwks.json', + 'RS256', { iss: 'https://example.com/', aud: 'my-app', @@ -501,6 +518,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://example.com/.well-known/jwks.json', + 'RS256', { iss: 'https://example.com/', aud: 'my-app', @@ -723,6 +741,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://tenant.auth0.com/.well-known/jwks.json', + 'RS256', { iss: 'https://tenant.auth0.com/', aud: 'my-api-client-id', @@ -761,6 +780,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://company.okta.com/oauth2/default/v1/keys', + 'RS256', { iss: 'https://company.okta.com/oauth2/default', aud: 'api://default', @@ -800,6 +820,7 @@ describe('explicit-jwks.test.ts - Explicit Configuration API', () => { const config = createJWKSUrlVerifyConfig( 'https://www.googleapis.com/oauth2/v3/certs', + 'RS256', { iss: 'https://accounts.google.com', aud: '123456-abcdefg.apps.googleusercontent.com', diff --git a/packages/flarelette-jwt-ts/tests/explicit.test.ts b/packages/flarelette-jwt-ts/tests/explicit.test.ts index 4370931..a8c3c15 100644 --- a/packages/flarelette-jwt-ts/tests/explicit.test.ts +++ b/packages/flarelette-jwt-ts/tests/explicit.test.ts @@ -13,6 +13,8 @@ import { createDelegatedTokenWithConfig, checkAuthWithConfig, createHS512Config, + createES512SignConfig, + createES512VerifyConfig, type HS512Config, } from '../src/explicit.js' @@ -402,6 +404,117 @@ describe('Explicit Configuration API', () => { }) }) + describe('ES512 explicit API', () => { + it('createES512SignConfig() returns config with alg: ES512', async () => { + const keyPair = await crypto.subtle.generateKey( + { name: 'ECDSA', namedCurve: 'P-521' }, + true, + ['sign', 'verify'] + ) + const privateJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + + const config = createES512SignConfig(privateJwk, { + iss: 'test-issuer', + aud: 'test-audience', + }) + + expect(config.alg).toBe('ES512') + expect(config.iss).toBe('test-issuer') + expect(config.aud).toBe('test-audience') + }) + + it('sign+verify round-trip using createES512SignConfig + createES512VerifyConfig', async () => { + const keyPair = await crypto.subtle.generateKey( + { name: 'ECDSA', namedCurve: 'P-521' }, + true, + ['sign', 'verify'] + ) + const privateJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + const publicJwk = { + ...(await crypto.subtle.exportKey('jwk', keyPair.publicKey)), + alg: 'ES512', + } + + const signConfig = createES512SignConfig(privateJwk, { + iss: 'test-issuer', + aud: 'test-audience', + }) + const verifyConfig = createES512VerifyConfig(publicJwk, { + iss: 'test-issuer', + aud: 'test-audience', + }) + + const token = await signWithConfig({ sub: 'user-es512' }, signConfig) + const payload = await verifyWithConfig(token, verifyConfig) + + expect(payload).toBeDefined() + expect(payload?.sub).toBe('user-es512') + expect(payload?.iss).toBe('test-issuer') + }) + + it('ES512 token rejected by HS512 config', async () => { + const keyPair = await crypto.subtle.generateKey( + { name: 'ECDSA', namedCurve: 'P-521' }, + true, + ['sign', 'verify'] + ) + const privateJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + + const signConfig = createES512SignConfig(privateJwk, { + iss: 'test-issuer', + aud: 'test-audience', + }) + const hs512Config: HS512Config = { + alg: 'HS512', + secret: new Uint8Array(64).fill(42), + iss: 'test-issuer', + aud: 'test-audience', + } + + const token = await signWithConfig({ sub: 'user-es512' }, signConfig) + const payload = await verifyWithConfig(token, hs512Config) + + expect(payload).toBeNull() + }) + + it('ES512 token accepted by JWKS URL verify config', async () => { + const keyPair = await crypto.subtle.generateKey( + { name: 'ECDSA', namedCurve: 'P-521' }, + true, + ['sign', 'verify'] + ) + const privateJwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + const publicJwk = await crypto.subtle.exportKey('jwk', keyPair.publicKey) + const kidPublicJwk = { ...publicJwk, kid: 'es512-test', alg: 'ES512', use: 'sig' } + + const signConfig = createES512SignConfig( + privateJwk, + { iss: 'test-issuer', aud: 'test-audience' }, + 'es512-test' + ) + + const token = await signWithConfig({ sub: 'user-es512' }, signConfig) + + globalThis.fetch = async () => + ({ + ok: true, + status: 200, + text: async () => JSON.stringify({ keys: [kidPublicJwk] }), + }) as Response + + const { createJWKSUrlVerifyConfig } = await import('../src/explicit.js') + const jwksConfig = createJWKSUrlVerifyConfig( + 'https://example.com/.well-known/jwks.json', + { iss: 'test-issuer', aud: 'test-audience' } + ) + + const payload = await verifyWithConfig(token, jwksConfig) + + expect(payload).toBeDefined() + expect(payload?.sub).toBe('user-es512') + }) + }) + describe('Isolation: No environment pollution', () => { it('should work without any environment variables', async () => { // Explicitly verify no JWT_ environment variables are used diff --git a/packages/flarelette-jwt-ts/tests/request-binding.test.ts b/packages/flarelette-jwt-ts/tests/request-binding.test.ts new file mode 100644 index 0000000..f32cbe3 --- /dev/null +++ b/packages/flarelette-jwt-ts/tests/request-binding.test.ts @@ -0,0 +1,252 @@ +/** + * Tests for request-bound JWT helpers (Issue #39) + * + * Verifies that signWithRequestBinding / verifyWithRequestBinding prevent + * replay of a captured token against a different endpoint. + */ + +import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { + computeRequestHash, + signWithRequestBinding, + verifyWithRequestBinding, +} from '../src/index.js' + +// 64-byte base64url secret for HS512 +const SECRET = Buffer.alloc(64, 0xab).toString('base64url') + +function makeRequest(url: string, method = 'GET', body?: string): Request { + return new Request(url, { + method, + body: body !== undefined ? body : undefined, + }) +} + +describe('computeRequestHash', () => { + it('same request produces the same hash (deterministic)', async () => { + const req1 = makeRequest('https://example.com/api/data?q=1', 'GET') + const req2 = makeRequest('https://example.com/api/data?q=1', 'GET') + const [h1, h2] = await Promise.all([ + computeRequestHash(req1), + computeRequestHash(req2), + ]) + expect(h1).toBe(h2) + }) + + it('different method produces different hash', async () => { + const get = makeRequest('https://example.com/path', 'GET') + const post = makeRequest('https://example.com/path', 'POST') + const [h1, h2] = await Promise.all([ + computeRequestHash(get), + computeRequestHash(post), + ]) + expect(h1).not.toBe(h2) + }) + + it('different path produces different hash', async () => { + const r1 = makeRequest('https://example.com/path/a') + const r2 = makeRequest('https://example.com/path/b') + const [h1, h2] = await Promise.all([computeRequestHash(r1), computeRequestHash(r2)]) + expect(h1).not.toBe(h2) + }) + + it('different query string produces different hash', async () => { + const r1 = makeRequest('https://example.com/path?page=1') + const r2 = makeRequest('https://example.com/path?page=2') + const [h1, h2] = await Promise.all([computeRequestHash(r1), computeRequestHash(r2)]) + expect(h1).not.toBe(h2) + }) + + it('different body produces different hash', async () => { + const r1 = makeRequest('https://example.com/path', 'POST', '{"a":1}') + const r2 = makeRequest('https://example.com/path', 'POST', '{"a":2}') + const [h1, h2] = await Promise.all([computeRequestHash(r1), computeRequestHash(r2)]) + expect(h1).not.toBe(h2) + }) + + it('GET with no body produces a stable hash', async () => { + const r1 = makeRequest('https://example.com/stable') + const r2 = makeRequest('https://example.com/stable') + const [h1, h2] = await Promise.all([computeRequestHash(r1), computeRequestHash(r2)]) + expect(h1).toBe(h2) + expect(h1.length).toBeGreaterThan(0) + }) + + it('hash is a non-empty base64url string', async () => { + const req = makeRequest('https://example.com/api') + const hash = await computeRequestHash(req) + expect(typeof hash).toBe('string') + expect(hash.length).toBeGreaterThan(0) + // base64url characters only + expect(hash).toMatch(/^[A-Za-z0-9_-]+$/) + }) +}) + +describe('signWithRequestBinding', () => { + beforeEach(() => { + process.env.JWT_SECRET = SECRET + process.env.JWT_ISS = 'test-issuer' + process.env.JWT_AUD = 'test-audience' + }) + + afterEach(() => { + delete process.env.JWT_SECRET + delete process.env.JWT_ISS + delete process.env.JWT_AUD + }) + + it('returns a valid 3-part JWT string', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + expect(typeof token).toBe('string') + expect(token.split('.')).toHaveLength(3) + }) + + it('token contains req claim', async () => { + const req = makeRequest('https://example.com/api/resource', 'POST', 'body') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const payloadPart = token.split('.')[1] + const decoded = JSON.parse( + Buffer.from(payloadPart.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString( + 'utf8' + ) + ) + + expect(decoded.req).toBeDefined() + expect(typeof decoded.req).toBe('string') + expect(decoded.req.length).toBeGreaterThan(0) + }) + + it('req claim is a base64url string', async () => { + const req = makeRequest('https://example.com/api/resource') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const payloadPart = token.split('.')[1] + const decoded = JSON.parse( + Buffer.from(payloadPart.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString( + 'utf8' + ) + ) + + expect(decoded.req).toMatch(/^[A-Za-z0-9_-]+$/) + }) +}) + +describe('verifyWithRequestBinding — success', () => { + beforeEach(() => { + process.env.JWT_SECRET = SECRET + process.env.JWT_ISS = 'test-issuer' + process.env.JWT_AUD = 'test-audience' + }) + + afterEach(() => { + delete process.env.JWT_SECRET + delete process.env.JWT_ISS + delete process.env.JWT_AUD + }) + + it('original request returns payload', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + // Re-create same request for verification + const verifyReq = makeRequest('https://example.com/api/resource', 'GET') + const payload = await verifyWithRequestBinding(token, verifyReq) + + expect(payload).not.toBeNull() + expect(payload?.sub).toBe('user123') + }) + + it('req claim is stripped from returned payload', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const verifyReq = makeRequest('https://example.com/api/resource', 'GET') + const payload = await verifyWithRequestBinding(token, verifyReq) + + expect(payload).not.toBeNull() + expect(payload?.req).toBeUndefined() + }) +}) + +describe('verifyWithRequestBinding — replay rejection', () => { + beforeEach(() => { + process.env.JWT_SECRET = SECRET + process.env.JWT_ISS = 'test-issuer' + process.env.JWT_AUD = 'test-audience' + }) + + afterEach(() => { + delete process.env.JWT_SECRET + delete process.env.JWT_ISS + delete process.env.JWT_AUD + }) + + it('different method returns null', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const replayReq = makeRequest('https://example.com/api/resource', 'POST') + const payload = await verifyWithRequestBinding(token, replayReq) + + expect(payload).toBeNull() + }) + + it('different path returns null', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const replayReq = makeRequest('https://example.com/api/other', 'GET') + const payload = await verifyWithRequestBinding(token, replayReq) + + expect(payload).toBeNull() + }) + + it('different body returns null', async () => { + const req = makeRequest( + 'https://example.com/api/resource', + 'POST', + '{"action":"read"}' + ) + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + const replayReq = makeRequest( + 'https://example.com/api/resource', + 'POST', + '{"action":"delete"}' + ) + const payload = await verifyWithRequestBinding(token, replayReq) + + expect(payload).toBeNull() + }) + + it('expired token returns null', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + // ttlSeconds = -200 forces token to be already-expired (beyond 90s default leeway) + const token = await signWithRequestBinding({ sub: 'user123' }, req, { + ttlSeconds: -200, + }) + + const verifyReq = makeRequest('https://example.com/api/resource', 'GET') + const payload = await verifyWithRequestBinding(token, verifyReq) + + expect(payload).toBeNull() + }) + + it('invalid signature returns null', async () => { + const req = makeRequest('https://example.com/api/resource', 'GET') + const token = await signWithRequestBinding({ sub: 'user123' }, req) + + // Tamper with the signature (last segment) + const parts = token.split('.') + parts[2] = parts[2].split('').reverse().join('') + const tampered = parts.join('.') + + const verifyReq = makeRequest('https://example.com/api/resource', 'GET') + const payload = await verifyWithRequestBinding(tampered, verifyReq) + + expect(payload).toBeNull() + }) +})