diff --git a/.github/renovate.json b/.github/renovate.json index 31713cd..7e59ed7 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -6,14 +6,16 @@ "separateMajorMinor": false, "separateMultipleMajor": false, "separateMinorPatch": false, - "packageRules": [ + "customManagers": [ { - "description": "Angular 22 requires TypeScript >=6.0 <6.1; review this range when upgrading Angular.", - "matchManagers": ["npm"], - "matchFileNames": ["client/package.json"], - "matchPackageNames": ["typescript"], - "allowedVersions": ">=6.0 <6.1" - }, + "customType": "regex", + "managerFilePatterns": ["/^test\\/test-pod\\.yaml$/"], + "matchStrings": ["image:\\s*(?ghcr\\.io/mucsi96/mock-oidc-provider):(?[1-9][0-9]*)\\b"], + "datasourceTemplate": "docker", + "versioningTemplate": "loose" + } + ], + "packageRules": [ { "groupName": "all dependencies", "groupSlug": "all", diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 76cbfde..811d48d 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -15,6 +15,22 @@ concurrency: cancel-in-progress: false jobs: + check-server: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@1.99.1 + with: + components: rustfmt, clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: server + - name: Check Rust + working-directory: server + run: | + cargo fmt --all --check + cargo clippy --locked --workspace --all-targets -- -D warnings + build-server-image: runs-on: ubuntu-latest timeout-minutes: 30 @@ -25,14 +41,10 @@ jobs: - uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # The Spring profile is resolved during AOT processing and baked into the - # native executable, so the e2e image is built with the test profile and - # the published image (see publish-server) with the prod profile. - name: Build server image uses: docker/build-push-action@v6 with: context: server - build-args: SPRING_PROFILE=test tags: localhost/skeleton-app-server:test outputs: type=docker,dest=/tmp/server-image.tar cache-from: type=gha,scope=server-test @@ -44,30 +56,33 @@ jobs: path: /tmp/server-image.tar retention-days: 1 - build-client-image: + build-client: runs-on: ubuntu-latest timeout-minutes: 15 concurrency: - group: ${{ github.workflow }}-build-client-image-${{ github.ref }} + group: ${{ github.workflow }}-build-client-${{ github.ref }} cancel-in-progress: true steps: - uses: actions/checkout@v6 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build client image - uses: docker/build-push-action@v6 + - uses: actions/setup-node@v6 with: - context: client - tags: localhost/skeleton-app-client:test - outputs: type=docker,dest=/tmp/client-image.tar - cache-from: type=gha,scope=client - cache-to: type=gha,mode=max,scope=client - - name: Upload client image + node-version: 26 + cache: npm + cache-dependency-path: client/package-lock.json + - name: Check static build preparation + run: node --test scripts/prepare-client.test.mjs + - name: Build client + working-directory: client + run: | + npm ci + npm run lint + npm run build + - name: Upload static client uses: actions/upload-artifact@v4 with: - name: client-image - path: /tmp/client-image.tar - retention-days: 1 + name: client-static + path: client/dist + retention-days: 7 build-mock-anthropic-image: runs-on: ubuntu-latest @@ -100,7 +115,7 @@ jobs: concurrency: group: ${{ github.workflow }}-test-e2e-${{ github.ref }} cancel-in-progress: true - needs: [build-server-image, build-client-image, build-mock-anthropic-image] + needs: [check-server, build-server-image, build-client, build-mock-anthropic-image] steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 @@ -135,18 +150,21 @@ jobs: pattern: "*-image" path: /tmp merge-multiple: true + - name: Download static client + uses: actions/download-artifact@v4 + with: + name: client-static + path: client/dist + - name: Check direct browser asset loading + run: python3 scripts/check_static_assets.py client/dist - name: Load images into Podman run: | podman load -i /tmp/server-image.tar - podman load -i /tmp/client-image.tar podman load -i /tmp/mock-anthropic-image.tar - # The server is a single native executable, so if it cannot even start in - # the runtime image there is nothing to log and the pod just times out two - # minutes later with an empty container log. Fail here instead. - name: Check the server executable runs run: | timeout 60 podman run --rm localhost/skeleton-app-server:test \ - -XX:PrintFlags= > /dev/null + --version - name: Setup test environment and start pod env: SKIP_BUILD: "1" @@ -214,23 +232,17 @@ jobs: with: context: server load: true - build-args: SPRING_PROFILE=prod tags: ghcr.io/${{ github.repository }}-server:${{ steps.get_next_version.outputs.version }} labels: org.opencontainers.image.source=https://github.com/${{ github.repository }} cache-from: type=gha,scope=server-prod cache-to: type=gha,mode=max,scope=server-prod - # The profile is baked in at build time, so this is a different - # executable from the one test-e2e exercised, taking code paths - the Key - # Vault property source above all - that no test covers. This cannot - # catch a missing reflection hint, but it does catch a binary that does - # not start, before the image is published and deploy picks it up. - name: Check the server executable runs if: steps.get_next_version.outputs.hasNextVersion == 'true' env: SERVER_IMAGE: ghcr.io/${{ github.repository }}-server:${{ steps.get_next_version.outputs.version }} run: | - timeout 60 docker run --rm "$SERVER_IMAGE" -XX:PrintFlags= > /dev/null + timeout 60 docker run --rm "$SERVER_IMAGE" --version - name: Push server image if: steps.get_next_version.outputs.hasNextVersion == 'true' @@ -257,7 +269,6 @@ jobs: if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request' permissions: contents: write - packages: write outputs: version: ${{ steps.get_next_version.outputs.version }} steps: @@ -272,31 +283,14 @@ jobs: prefix: 'client' src: client - - name: Set up Docker Buildx - if: steps.get_next_version.outputs.hasNextVersion == 'true' - uses: docker/setup-buildx-action@v3 - - - name: Login to GHCR - if: steps.get_next_version.outputs.hasNextVersion == 'true' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push client image - if: steps.get_next_version.outputs.hasNextVersion == 'true' - uses: docker/build-push-action@v6 + - name: Download tested static client + uses: actions/download-artifact@v4 with: - context: client - push: true - tags: ghcr.io/${{ github.repository }}-client:${{ steps.get_next_version.outputs.version }} - labels: org.opencontainers.image.source=https://github.com/${{ github.repository }} - cache-from: type=gha,scope=client - cache-to: type=gha,mode=max,scope=client + name: client-static + path: /tmp/client-static + - name: Package client release + run: tar -czf /tmp/client-static.tar.gz -C /tmp/client-static . - # Tag the commit this image was built from, not whatever main points at - # by the time the release is created - see publish-server above. - name: Create release if: steps.get_next_version.outputs.hasNextVersion == 'true' uses: softprops/action-gh-release@v2 @@ -304,6 +298,7 @@ jobs: tag_name: ${{ steps.get_next_version.outputs.tag }} target_commitish: ${{ github.sha }} generate_release_notes: true + files: /tmp/client-static.tar.gz deploy: runs-on: ubuntu-latest @@ -318,6 +313,14 @@ jobs: contents: read steps: - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 26 + - name: Download tested static client + uses: actions/download-artifact@v4 + with: + name: client-static + path: client-static - uses: azure/login@v3 with: @@ -325,6 +328,41 @@ jobs: tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + - name: Prepare static client URLs + id: client + env: + AZURE_KEYVAULT_NAME: ${{ secrets.AZURE_KEYVAULT_NAME }} + run: | + config=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --name client-storage-config --query value -o tsv) + account=$(jq -er '.account_name' <<< "$config") + assets_url=$(jq -er '.assets_base_url' <<< "$config") + hostname=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --name hostname --query value -o tsv) + node scripts/prepare-client.mjs client-static client-publish "$assets_url" "https://$hostname" + echo "account=$account" >> "$GITHUB_OUTPUT" + + - name: Publish client assets then document + uses: azure/cli@v2 + env: + STORAGE_ACCOUNT: ${{ steps.client.outputs.account }} + with: + inlineScript: | + set -euo pipefail + az storage blob delete-batch --auth-mode login --account-name "$STORAGE_ACCOUNT" \ + --source '$web' --only-show-errors --output none + az storage blob delete-batch --auth-mode login --account-name "$STORAGE_ACCOUNT" \ + --source assets --only-show-errors --output none + az storage blob upload-batch --auth-mode login --account-name "$STORAGE_ACCOUNT" \ + --destination assets --source client-publish/assets --overwrite true \ + --content-cache-control 'public, max-age=31536000, immutable' --only-show-errors --output none + az storage blob upload --auth-mode login --account-name "$STORAGE_ACCOUNT" \ + --container-name assets --name manifest.webmanifest --file client-publish/assets/manifest.webmanifest \ + --overwrite true --content-type application/manifest+json --content-cache-control 'public, max-age=31536000, immutable' \ + --only-show-errors --output none + az storage blob upload --auth-mode login --account-name "$STORAGE_ACCOUNT" \ + --container-name '$web' --name index.html --file client-publish/documents/index.html \ + --overwrite true --content-type text/html --content-cache-control no-store \ + --only-show-errors --output none + - uses: azure/use-kubelogin@v1 with: kubelogin-version: 'v0.2.7' @@ -334,9 +372,8 @@ jobs: with: service-key: ${{ secrets.TWINGATE_SERVICE_KEY }} - - name: Deploy to Kubernetes + - name: Deploy API and static website env: AZURE_KEYVAULT_NAME: ${{ secrets.AZURE_KEYVAULT_NAME }} SERVER_IMAGE: ghcr.io/${{ github.repository }}-server:${{ needs.publish-server.outputs.version }} - CLIENT_IMAGE: ghcr.io/${{ github.repository }}-client:${{ needs.publish-client.outputs.version }} run: scripts/deploy.sh diff --git a/.github/workflows/update_dependencies.yml b/.github/workflows/update_dependencies.yml index cefb6cc..debe9d7 100644 --- a/.github/workflows/update_dependencies.yml +++ b/.github/workflows/update_dependencies.yml @@ -19,12 +19,7 @@ jobs: statuses: write steps: - uses: actions/checkout@v6 - - uses: actions/setup-java@v5 - with: - java-version: '21' - distribution: 'temurin' - cache: 'maven' - cache-dependency-path: 'server/pom.xml' + - uses: dtolnay/rust-toolchain@1.99.1 - uses: actions/setup-node@v6 with: # Current Renovate releases require Node 24. diff --git a/.gitignore b/.gitignore index 00eaf65..1519578 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .kube/ postgres-data/ .direnv/ +server/config/*.local.yaml diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 162a360..f536914 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,8 @@ { "recommendations": [ - "vmware.vscode-boot-dev-pack", - "vscjava.vscode-java-pack", - "angular.ng-template", + "rust-lang.rust-analyzer", + "vadimcn.vscode-lldb", + "dbaeumer.vscode-eslint", "editorconfig.editorconfig", "esbenp.prettier-vscode", "anweber.vscode-httpyac", diff --git a/.vscode/launch.json b/.vscode/launch.json index df212ce..23e05c3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,14 +16,20 @@ "type": "node" }, { - "type": "java", + "type": "lldb", "name": "Start server", "request": "launch", "cwd": "${workspaceFolder}/server", - "mainClass": "io.github.mucsi96.skeleton.SkeletonApplication", - "args": "--spring.profiles.active=local", + "args": ["start", "--no-banner"], + "cargo": { "args": ["build", "--bin", "skeleton-server", "--manifest-path", "${workspaceFolder}/server/Cargo.toml"] }, "env": { - "AZURE_KEYVAULT_ENDPOINT": "https://p06-hello.vault.azure.net" + "LOCO_ENV": "development", + "PORT": "8053", + "DATABASE_URL": "postgres://postgres:postgres@localhost:5450/skeleton", + "OIDC_ISSUER": "http://localhost:8050/default", + "API_CLIENT_ID": "mock-api-client-id", + "ANTHROPIC_BASE_URL": "http://localhost:3050", + "ANTHROPIC_API_KEY": "mock-anthropic-key" } } ] diff --git a/.vscode/settings.json b/.vscode/settings.json index ef588d0..4739692 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,5 @@ { - "java.compile.nullAnalysis.mode": "disabled", - "java.configuration.updateBuildConfiguration": "interactive", + "rust-analyzer.linkedProjects": ["server/Cargo.toml"], "vs-kubernetes": { "vs-kubernetes.namespace": "skeleton-app", "vs-kubernetes.kubeconfig": "${workspaceFolder}/.kube/config" diff --git a/.vscode/tasks.json b/.vscode/tasks.json index cd5e98f..e279264 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,138 +1,18 @@ { "version": "2.0.0", "tasks": [ - { - "label": "Start DB Connection Proxy", - "type": "shell", - "command": "scripts/start_db_proxy.sh", - "problemMatcher": [], - "isBackground": true, - "options": { - "cwd": "${workspaceFolder}" - } - }, - { - "type": "shell", - "command": "${command:python.interpreterPath} -m ansible.cli.vault encrypt vars/vault.yaml --vault-password-file .ansible/vault_key", - "isBackground": true, - "label": "Encrypt vault", - "problemMatcher": [], - "options": { - "cwd": "${workspaceFolder}" - } - }, - { - "type": "shell", - "command": "${command:python.interpreterPath} -m ansible.cli.vault decrypt vars/vault.yaml --vault-password-file .ansible/vault_key", - "isBackground": true, - "label": "Decrypt vault", - "problemMatcher": [], - "options": { - "cwd": "${workspaceFolder}" - } - }, - { - "type": "shell", - "command": "${command:python.interpreterPath} -m ansible.cli.vault view vars/vault.yaml --vault-password-file .ansible/vault_key", - "isBackground": true, - "label": "View vault", - "problemMatcher": [], - "options": { - "cwd": "${workspaceFolder}" - } - }, - { - "label": "Start client", - "type": "shell", - "command": "npm start", - "options": { - "cwd": "${workspaceFolder}/client" - }, - "isBackground": true, - "problemMatcher": { - "pattern": [ - { - "regexp": "^X \\[(ERROR)\\] ((TS|NG)\\d+): (.*)$", - "severity": 1, - "code": 2, - "message": 4 - }, - { - "regexp": "" - }, - { - "regexp": "^\\s*(.*):(\\d+):(\\d+):$", - "file": 1, - "line": 2, - "column": 3 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "Changes detected\\. Rebuilding\\.\\.\\." - }, - "endsPattern": { - "regexp": "Application bundle generation (complete|failed)" - } - } - } - }, - { - "type": "shell", - "command": "bash", - "label": "Install dependencies", - "args": ["scripts/install_dependencies.sh"], - "options": { - "cwd": "${workspaceFolder}" - }, - "problemMatcher": [] - }, - { - "type": "shell", - "label": "Pod up", - "command": "scripts/pod_up.sh", - "problemMatcher": [] - }, - { - "type": "shell", - "label": "Pod down", - "command": "scripts/pod_down.sh", - "problemMatcher": [] - }, - { - "type": "shell", - "label": "Dev DB up", - "command": "scripts/dev_db_up.sh", - "problemMatcher": [] - }, - { - "type": "shell", - "label": "Dev DB down", - "command": "scripts/dev_db_down.sh", - "problemMatcher": [] - }, - { - "type": "shell", - "command": "scripts/deploy.sh", - "label": "Deploy", - "options": { - "cwd": "${workspaceFolder}" - }, - "problemMatcher": [] - }, - { - "type": "shell", - "label": "Run Playwright Tests", - "command": "npm test", - "options": { - "cwd": "${workspaceFolder}/test" - }, - "problemMatcher": [], - "group": { - "kind": "test", - "isDefault": true - } - } + { "label": "Start DB Connection Proxy", "type": "shell", "command": "scripts/start_db_proxy.sh", "isBackground": true, "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": [] }, + { "label": "Encrypt vault", "type": "shell", "command": "${command:python.interpreterPath} -m ansible.cli.vault encrypt vars/vault.yaml --vault-password-file .ansible/vault_key", "isBackground": true, "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": [] }, + { "label": "Decrypt vault", "type": "shell", "command": "${command:python.interpreterPath} -m ansible.cli.vault decrypt vars/vault.yaml --vault-password-file .ansible/vault_key", "isBackground": true, "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": [] }, + { "label": "View vault", "type": "shell", "command": "${command:python.interpreterPath} -m ansible.cli.vault view vars/vault.yaml --vault-password-file .ansible/vault_key", "isBackground": true, "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": [] }, + { "label": "Start client", "type": "shell", "command": "npm start", "options": { "cwd": "${workspaceFolder}/client" }, "problemMatcher": [] }, + { "label": "Build server", "type": "shell", "command": "cargo build --locked", "options": { "cwd": "${workspaceFolder}/server" }, "problemMatcher": ["$rustc"] }, + { "label": "Install dependencies", "type": "shell", "command": "scripts/install_dependencies.sh", "problemMatcher": [] }, + { "label": "Pod up", "type": "shell", "command": "scripts/pod_up.sh", "problemMatcher": [] }, + { "label": "Pod down", "type": "shell", "command": "scripts/pod_down.sh", "problemMatcher": [] }, + { "label": "Dev DB up", "type": "shell", "command": "scripts/dev_db_up.sh", "problemMatcher": [] }, + { "label": "Dev DB down", "type": "shell", "command": "scripts/dev_db_down.sh", "problemMatcher": [] }, + { "label": "Deploy", "type": "shell", "command": "scripts/deploy.sh", "problemMatcher": [] }, + { "label": "Run Playwright Tests", "type": "shell", "command": "npm test", "options": { "cwd": "${workspaceFolder}/test" }, "problemMatcher": [], "group": { "kind": "test", "isDefault": true } } ] } diff --git a/AGENTS.md b/AGENTS.md index 95a2b73..e62512d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,271 +14,99 @@ This repository is the skeleton-sync source; it does not synchronize from itself ## General Code Style -- Avoid fallbacks, prefer failing fast -- Prefer functional programming patterns -- Prefer immutable data structures - -## Java Style - -- Use Lombok annotations (@Data, @Builder, @RequiredArgsConstructor) -- Constructor injection (via @RequiredArgsConstructor) -- Use Stream API for collections -- Use records for DTOs/responses - -## TypeScript Style - -- Use `const` by default -- Prefer spread operator for object/array operations -- Use functional array methods (map, filter, reduce) -- Use string literals over enums - -## Testing Style - -- Write tests from user perspective -- Use role-based selectors (getByRole) -- Use semantic selectors (getByText, getByLabel) -- E2E tests with Playwright - -## Angular Style - -- Use Angular Material components -- Follow `@mucsi96/angular-material-theme`'s documented button-color API: use `bt-color="primary|success|warn|error"` on `mat-flat-button`, `mat-raised-button`, `mat-fab` (including extended FABs), and `mat-mini-fab`, including anchor buttons. Use `[attr.bt-color]` for dynamic tones; no directive import is needed. -- Solid buttons default to primary. Use `error` for destructive actions, `warn` for caution, and `success` for positive outcomes. Material's legacy `color="warn"` means error/red, not the theme's orange `bt-color="warn"`; migrate solid buttons accordingly. -- For an arbitrary solid-button color, set only `--bt-button-bg` without `bt-color`. Let the theme derive label contrast and hover colors; do not override Material container/label/state-layer color tokens, `--mat-sys-primary`, or button `background`, `color`, and `:hover` separately. Keep the intended button variant; raised buttons support the same API and retain elevation. -- The `bt-color` API does not cover text, outlined, icon, or menu buttons. Use their documented Material APIs instead; do not apply solid-button color workarounds to them. Check the installed theme README when upgrading or changing component styles. -- Use signals and resources (not rxjs where possible) -- Use string literals over enums -- Standalone components - -## Design - -- Material UI dark theme -- Skeleton loaders for loading states - -## Project Overview - -Reference application demonstrating patterns for: -- CI/CD pipeline (GitHub Actions) -- Deployment (Docker images published to registry) -- Client (Angular 21 with Material UI) -- Server (Spring Boot 4 with Java 21) -- Authentication (Entra through platform oauth2-proxy and HttpOnly sessions) -- Configuration (Azure Key Vault, Spring profiles) -- AI integration (Anthropic Claude via Spring AI) -- AI mocking (Express mock server) -- Database (PostgreSQL with JPA) -- Testing (Playwright E2E) +- Avoid fallbacks, prefer failing fast. +- Prefer functional programming patterns and immutable data structures. +- Rust: Loco hooks and controllers, typed Serde payloads/settings, SeaORM queries, Tokio async I/O, + `Result` error propagation, and structured tracing. Never expose internal errors or secrets in API responses. +- TypeScript: strict types, `const`, functional array methods, string literals over enums. +- React: function components, hooks, TanStack Query for server state, Zod validation at API boundaries. +- Use `@mucsi96/react-ui` components and its documented APIs, matching Observatory. +- Colocate component styles in CSS Modules (`*.module.css`). Keep only theme tokens, + typography defaults, and resets in the global stylesheet. +- Dark theme, accessible semantic controls, skeleton loading states, actionable error states. +- Test React and Rust application behavior through the Playwright E2E suite; + do not add React or Rust unit/integration test suites. Use role/text/label selectors. ## Architecture -- **client/** - Angular SPA with client-chart-owned Gateway document/static routing and inline runtime config -- **server/** - Spring Boot 4 REST API with PostgreSQL, Spring AI -- **mock_anthropic_server/** - Express mock for Claude API -- **test/** - Playwright E2E tests -- **scripts/** - Build and deployment scripts -- **.github/workflows/** - CI/CD pipelines - -## Key Technologies - -- Spring Boot 4, Java 21 (built into a GraalVM native image) -- Angular 21.2.0 -- PostgreSQL 17 -- Spring AI 2.0.0-M2 (Anthropic) -- Entra authentication through platform ForwardAuth -- Azure Key Vault for secrets -- Traefik reverse proxy -- Docker multi-stage builds -- Playwright for E2E testing - -## Development Commands - -### Frontend -```bash -cd client && npm start # Start dev server -cd client && npm run build # Production build -``` - -### Backend -```bash -cd server && mvn spring-boot:run -Dspring-boot.run.profiles=local # Start with local profile -``` - -Local development still runs on a plain JVM. The native image is built only by -the container build - see **Native image and the baked-in Spring profile** -below. - -### Podman Development -```bash -scripts/pod_up.sh # Build images and start test pod -scripts/pod_down.sh # Stop and clean up test pod -scripts/dev_db_up.sh # Start development PostgreSQL database -scripts/dev_db_down.sh # Stop development database -``` - -### Testing -```bash -cd test && npm test # Run E2E tests -cd test && npx playwright test --ui # Interactive test runner -``` - -## API Routes - -- `GET /api/greeting` - AI-powered greeting (authenticated) - -## Data Model - -- **greetings** - Stores name and message used for AI greeting generation - -## Configuration Patterns - -### Spring Profiles -- **prod** - Production with Azure Key Vault and AAD -- **local** - Local development with Podman DB -- **test** - Mock OIDC/AI services with backend JWT validation enabled - -## Native image and the baked-in Spring profile - -The server is compiled ahead of time into a GraalVM native executable linked -against musl, so there is no JRE in the runtime image and startup is in the tens -of milliseconds rather than seconds. +- **client/** — React 19 + Vite static SPA, shared React UI, build-time Faro configuration. +- **server/** — Loco, Rust 2024, SeaORM/PostgreSQL, Anthropic Messages API. +- **mock_anthropic_server/** — Express mock for Claude API. +- **test/** — Playwright E2E, gateway identity fixtures, Podman test pod. +- **scripts/** — Build and deployment scripts. +- **.github/workflows/** — CI/CD pipelines. -Ahead-of-time processing resolves bean definitions at build time, which means -the active Spring profile is decided by the build, not by the environment: -Spring AOT emits an `EnvironmentPostProcessor` that activates the profile the -image was built with. `SPRING_PROFILES_ACTIVE` is no longer read at runtime, and -`test/test-pod.yaml` no longer sets it. Build one image per profile with the -`SPRING_PROFILE` build argument - `test` for the e2e pod, `prod` for the image -published to GHCR: +Toolchain versions are pinned in `server/rust-toolchain.toml` and lockfiles. -```bash -podman build --build-arg SPRING_PROFILE=test \ - -t localhost/skeleton-app-server:test server -``` - -Build-time details that live in `server/pom.xml` and are easy to trip over: - -- AOT processing refreshes the application context, so every placeholder an - auto-configuration condition reads has to resolve during the build. The - `process-aot` execution supplies build-time stand-ins for them and turns the - Key Vault property source off, so the build never reaches out to Azure. The - stand-ins are not baked into the image; they only have to make the same - conditions match as the real values do at runtime. A new required environment - placeholder read by a condition means adding it there too. Placeholders that - are only read while creating beans (`${db-url}`, `${claude-api-key}`) are - resolved at runtime as before and need nothing. -- Spring AOT generates bean-definition classes into the packages of the - configuration classes it processes, including the signed Spring Cloud Azure - jars. Mixing generated (unsigned) and signed classes in one package makes the - native-image builder throw `SecurityException: ... signer information does not - match`, so the builder is pointed at `server/native-image.security`, which - disables jar signature verification. -- Jars can ship a `META-INF/native-image/.../native-image.properties` that forces - classes to build-time initialization. When such a class holds on to objects of - types that are still initialized at run time, the builder fails with - `UnsupportedFeatureException: An object of type ... was found in the image - heap`. `--initialize-at-build-time` in the `native-maven-plugin` config covers - the Jackson core classes `azure-core` leaves behind that way. Note that a build - cannot undo such a directive: `exclude-config` does not apply to - `native-image.properties`, and `initialize-at-run-time` for the same class is - rejected outright. That is why `azure-core` is pinned ahead of the version the - Azure BOM selects - the BOM's 1.58.0 forces SLF4J and logback to build-time - initialization, which is irreconcilable with Spring Boot setting logging up at - run time. Check this again when the Azure BOM moves. -- The Azure SDK's `ExpandableStringEnum` constants are built by instantiating the - subclass reflectively, and `fromString` returns `null` rather than failing when - it cannot. Missing reflection metadata therefore surfaces as every constant of - a class being `null` and a `NullPointerException` far from the cause. - `AzureNativeHints` registers the subclasses azure-identity does not ship - metadata for. -- azure-core decides how to read a response body by asking the model class - whether it declares the `fromXml` / `fromJson` pair azure-xml and azure-json - generate, and it asks with `Class.getDeclaredMethods()`. In a native image that - returns nothing for a class with no reachability metadata, so the answer is - silently "no" and azure-core falls back to Jackson - for XML that means an - `XmlMapper`, and jackson-dataformat-xml is not on the classpath, so the call - dies with a `NoClassDefFoundError`. The SDK ships metadata for most of its - models but not all. `AzureNativeHints` scans `com.azure` and registers every - `XmlSerializable`, `JsonSerializable` and `HttpResponseException` instead of - naming the ones missing today, so an SDK upgrade cannot reintroduce this. -- The Key Vault property source is configured by an `EnvironmentPostProcessor` - that runs before there is an application context and reads its own settings - with a plain `Binder` over `AzureKeyVaultSecretProperties`. Nothing in the - framework infers that, and the auto-configuration that would otherwise - contribute the binding metadata for that type never matches here - it is - conditional on `spring.cloud.azure.keyvault[.secret].endpoint`, while this - application configures the endpoint under `...secret.property-sources[0]`. With - no members in the image the binder binds nothing, and an absent binding is - indistinguishable from an empty configuration, so the post-processor quietly - concludes there is no property source to add. Nothing fails at that point: the - image starts and then dies much later on the first secret-backed placeholder. - `KeyVaultPropertySourceNativeHints` supplies the metadata. Only the prod - profile reads secrets from Key Vault, so no test covers this - after changing - anything about the Key Vault configuration, check that the generated - `target/spring-aot/main/resources/META-INF/native-image/**/reachability-metadata.json` - still carries `AzureKeyVaultSecretProperties` and - `AzureKeyVaultPropertySourceProperties` with their accessors. - -Spring Cloud Azure needs one workaround in application code: -`AzureGlobalPropertiesConfiguration` re-declares the `AzureGlobalProperties` -bean. Spring Cloud Azure registers it from an `ImportBeanDefinitionRegistrar` -using a lambda instance supplier, which AOT cannot turn into generated code, so -it drops the bean and the image fails to start with "required a bean of type -AzureGlobalProperties that could not be found". See the class comment for why it -uses its own bean name. That workaround turns on Spring Cloud Azure's -registration order, which is not a public contract, so smoke-test the image -whenever `spring-cloud-azure-dependencies` moves - a change there could drop the -bean again with no compile-time signal. - -The image is deliberately not built with `--static`. A fully static binary links -but then segfaults the moment it starts in the container - before GraalVM -installs its own segfault handler, so with no output whatsoever, which looks -exactly like a container that silently never starts. - -### Reproducing AOT problems without a native build - -Most AOT problems reproduce without waiting for a native compile (which takes -several minutes). Run the AOT-processed application on a normal JVM: +## Development and checks ```bash -cd server -mvn -Pnative package -DskipTests -Dapp.profile=test -java -Dspring.aot.enabled=true -jar target/skeleton-0.0.1-SNAPSHOT.jar +scripts/install_dependencies.sh +scripts/pod_up.sh +cd test && npm test +cd client && npm run lint && npm run build +cd server && cargo fmt --all --check && cargo clippy --locked --workspace --all-targets -- -D warnings +node --test scripts/prepare-client.test.mjs +python3 scripts/check_static_assets.py client/dist ``` -That exercises the generated context - missing bean definitions, profile and -condition mismatches - in seconds. Only class-initialization and reflection -problems need the real `mvn -Pnative native:compile`. - -Types that are only ever bound reflectively need explicit hints. Controller -request/response types, JPA entities and Spring Data repositories are covered by -the framework's own AOT processing and need nothing. Types read with a plain -`ObjectMapper` want `@RegisterReflectionForBinding`; types bound by a `Binder` -rather than Jackson want `BindableRuntimeHintsRegistrar`, which registers exactly -what `JavaBeanBinder` looks for over the whole class hierarchy - see -`KeyVaultPropertySourceNativeHints`. - -### Release and image publishing - -`publish-server` and `publish-client` publish numbered GHCR images only when -`get_next_version.outputs.hasNextVersion == 'true'`, tagging them with -`get_next_version.outputs.version`. Authentication uses `GITHUB_TOKEN` with -job-scoped `packages: write`. Release tags use `target_commitish: ${{ github.sha }}`. -The action always returns `version` and `tag`, including the current reachable -release when unchanged; `hasNextVersion` alone controls publication. Forward its -version output directly to deployment without a consumer-side tag lookup. -The workflow serializes publication and rollout; require numbered GHCR tags or -digests. -The production Dockerfiles carry GHCR source labels, triggering both initial -publications through normal component version detection. -Both packages must be public for anonymous Kubernetes pulls. - -### Runtime Configuration and Document Authentication -- The client chart owns SPA routes, document auth, index rewriting and config injection. API charts own API auth/header policies. The platform supplies only the proxy, login configuration and credentials. -- Keep `` before Angular. The client chart replaces the quoted marker with public JSON. -- Angular validates `clientLogUrl`/`clientAppName` and bootstraps directly. There is no environment endpoint or config fetch. -- Deploy reads the proxy reference from `forward-auth-config.auth` and passes it to each chart's `auth` value. Public config is separate `client-runtime-config`. Do not pass generated policy lists. Keep the client HTTPRoute and `/index.html` probes. -- Faro uses the exact same-origin logging route with credential stripping and collector origin/rate-limit controls. -- No frontend auth service/interceptor/guard or sign-in/out UI. Userinfo is read-only profile data. -- Use Spring Security SPA CSRF and Angular's built-in XSRF support. Keep CSRF checks - active for proxy-injected bearer requests; do not add a custom Origin filter. -- App E2E fixtures mock gateway identity and profile data; do not run oauth2-proxy/Redis or duplicate platform session-flow tests. +`npm start` in client starts Vite on 4250. `cargo run --locked -- start` in server runs the +API; see README for required environment variables. `scripts/dev_db_up.sh` starts +the standalone development database. Podman is a distro-level prerequisite; the +Nix shell supplies Rust/Node and deployment tools. + +## Data and configuration + +- `GET /api/greeting` returns `{name,message,aiGreeting}` and requires a valid JWT, + `api-access` scope, and `readGreetings` role. +- Preserve `hello.greetings` and its existing sequence. SeaORM migrations adopt the + Liquibase-created table and leave legacy changelog tables intact. Seed only new + databases; never overwrite or reseed existing user data. +- `LOCO_ENV=production` loads existing `db-url`, `db-username`, `db-password`, `tenant-id`, + `api-client-id`, and `claude-api-key` secrets from `AZURE_KEYVAULT_ENDPOINT` using + Azure workload identity. JDBC PostgreSQL URLs remain accepted. +- `LOCO_ENV=development|test` requires explicit DATABASE_URL/OIDC/Anthropic environment values. +- One native Rust image supports all environments at runtime. No build profiles, + JVM, AOT processing, reflection hints, or secrets in the image. +- `/healthz` reports readiness after migration/discovery and checks database access. + +## Authentication and static hosting + +- The platform owns oauth2-proxy, login configuration, and HttpOnly sessions. The + client chart owns authenticated SPA documents and index URL rewriting; the API + chart owns API auth/header policies. +- Validate JWT signature, issuer, audience, expiry/not-before, scope, and role in + the API even when requests arrive through ForwardAuth. +- Keep CSRF checks active on all unsafe requests, including proxy-injected bearer + requests. Use Secure, host-only `__Host-XSRF-TOKEN` at `/` and require its matching + `X-XSRF-TOKEN` header. The same-origin fetch helper sends CSRF proof on mutations. +- No frontend OAuth service, auth interceptor, guard, or sign-in/out UI. Userinfo + is read-only profile data. E2E fixtures mock gateway identity; do not duplicate + platform oauth2-proxy/Redis session-flow tests. +- Compile Faro's public app name and `/_telemetry/collect` path into the bundle; + resolve against the browser's application origin, not the Blob asset origin. +- Bootstrap directly without global config, HTML markers, an environment endpoint, + or config fetch. Omit chart `runtimeConfig` and retain `--reset-values`. +- Faro's same-origin logging route has credential stripping and collector + origin/rate-limit controls. +- Build with Node/npm. Upload the tested `client/dist` artifact to Azure Storage + with official `azure/login` / `azure/cli` actions; index is uploaded last. +- `prepare-client.mjs` rewrites HTML asset URLs only. Vite uses relative imports + so modules, lazy chunks, CSS, fonts, icons, and manifests load directly from Blob + storage with anonymous CORS. Document base remains `/`. +- Deploy reads `forward-auth-config.auth` for both charts. Pass the hostname in + `client-storage-config` to `static-client-app.staticOrigin`. Production has no + client Deployment or probes. Do not pass generated policy lists. +- E2E mounts `client/dist` into stock nginx behind Traefik. See docs/static-hosting.md. + +## Release and image publishing + +`publish-server` publishes numbered GHCR images only when +`get_next_version.outputs.hasNextVersion == 'true'`, using its `version` output. +Use job-scoped `packages: write` and `GITHUB_TOKEN`. Release tags target +`${{ github.sha }}`. Forward the action's version output directly to deployment; +do not add a consumer-side tag lookup. The workflow serializes publication/rollout. +Require numbered GHCR tags or digests, the GHCR source label, and a public server +package for anonymous pulls. Use `rust-app` for the API while preserving the +`hello-server` release, workload identity, `/api` route and existing database. +`publish-client` attaches the tested static archive to numbered client releases. diff --git a/README.md b/README.md index 5fdba69..00a6c9c 100644 --- a/README.md +++ b/README.md @@ -1,150 +1,144 @@ # Skeleton App -Reference application for all future projects. Based on patterns from [learn-language](https://github.com/mucsi96/learn-language). - -## Patterns Covered - -- **CI/CD Pipeline** - GitHub Actions with E2E testing and image publishing -- **Deployment** - Docker multi-stage builds with Traefik reverse proxy -- **Client** - Angular 21 with Material UI dark theme -- **Server** - Spring Boot 4 with Java 21, compiled ahead of time into a GraalVM native image -- **Authentication** - Entra through stock oauth2-proxy ForwardAuth and HttpOnly sessions -- **Configuration** - Azure Key Vault + Spring profiles (prod/local/test) -- **AI Integration** - Anthropic Claude via Spring AI -- **AI Mocking** - Express mock server for testing -- **Database** - PostgreSQL with Spring Data JPA -- **Testing** - Playwright E2E tests -- **UI Components** - Material UI with custom dark theme -- **Fetching** - Angular resource API with HttpClient - -## Authentication and deployment - -The client Helm chart owns SPA document/static routing and inline runtime -configuration. Its Gateway document rule uses its own authentication middleware -before rewriting deep links to `/index.html`. Index HTML is authenticated before -Angular scripts are served; ordinary bundles remain public. nginx serves files -only and missing assets return 404. There is no `/api/environment` endpoint or -configuration fetch before bootstrap. -There is no frontend auth service, auth interceptor, route guard or login/logout -UI. A read-only `/oauth2/userinfo` resource supplies the header profile menu. - -The API keeps JWT audience/scope/role validation and uses Spring Security's built-in -SPA CSRF protection for unsafe requests, including proxy-injected bearer requests. -The initial API GET sets a Secure, host-only `__Host-XSRF-TOKEN` cookie at -`/`; Angular's built-in XSRF support sends its value as `X-XSRF-TOKEN` on same-origin -mutations. This is a CSRF token, not an OAuth credential. There is no custom filter -or auth interceptor, and no backend `BROWSER_ORIGIN` setting is needed. - -Platform Terraform owns `hello-oauth2-proxy` and its Secrets. Publish the shared -app chart changes and provision the proxy reference/deploy permissions before -deploying this app. New app-owned middleware can use the existing chart-5 proxy; -upgrade the proxy chart only after live routes stop referencing its old middleware. -`scripts/deploy.sh` fails early if the auth release or middleware-capable -charts are missing. It reads `.auth` from `forward-auth-config` in app Azure Key -Vault: the proxy Service, port and mode. It passes that object to -both charts' `auth` value; each chart creates its own middleware and policies. -Both upgrades reset Helm values and supply the intended configuration, removing -obsolete policy-list settings. New charts do not accept manual filter lists. -No generated filter lists are read or assembled. Separate `client-runtime-config` -supplies the public -`clientLogUrl` and `clientAppName` map to the client chart's `runtimeConfig` value. -The deploy identity has read access scoped to those deployment secrets. Backend -session/login URL variables are no longer consumed. The client chart keeps its -own route and `/index.html` health probes. The proxy owns OAuth and session renewal; an -unrenewable session re-enters login on the next page load. -All apps use the host-only `__Host-session` cookie; separate hostnames keep browser -sessions separate. Hello is always hosted at `/`, including all nested UI routes. - -The app tests use mock authentication. Playwright injects a mock-issued bearer -token into browser API requests, supplies profile data and injects public runtime -config into documents. Backend JWT -validation and Spring CSRF checks stay enabled. Test pods run the app, database, mock OIDC/AI services -and routing, without oauth2-proxy or Redis. Playwright targets `http://localhost:8150`. - -The built HTML contains `` -before Angular. The client-owned body middleware replaces the quoted marker with -HTML-escaped JSON; startup rejects a missing configuration. Enable the pinned -Traefik rewritebody v0.3.1 plugin through the ingress module before deployment. -Keep index HTML uncompressed at the origin; the client route sets no-store and -strips validators/conditional/range headers before injection. - -Faro uses the absolute same-origin URL `https://hello./_telemetry/collect`. -The logging module owns that exact collector route, rewriting to `/collect` and -stripping app cookies/bearer/CSRF headers. Browser collection needs no cross-origin -preflight; the receiver keeps its explicit origin allowlist and rate limits. -Full Gateway/proxy/plugin integration lives in the shared chart regression. - -## One image per Spring profile - -The server is shipped as a GraalVM native executable. Bean definitions are -resolved during ahead-of-time processing at build time, so the active Spring -profile is baked into the executable and cannot be chosen at startup any more. -The server image is therefore built once per profile, via the `SPRING_PROFILE` -build argument: +A full-stack React and Loco application with authenticated greetings and AI integration. -```bash -podman build --build-arg SPRING_PROFILE=test -t skeleton-app-server:test server # e2e pod -podman build --build-arg SPRING_PROFILE=prod -t skeleton-app-server:prod server # published image -``` - -`SPRING_PROFILES_ACTIVE` is not read at runtime; the pipeline builds the test -image for the e2e job and the prod image when publishing to GHCR. Running -the server on a JVM for local development is unaffected - `mvn spring-boot:run --Dspring-boot.run.profiles=local` still selects the profile the usual way. +## Stack -## AI Pattern Sync +- **API:** Loco, Rust 2024, SeaORM/PostgreSQL, Tokio, typed Serde settings. +- **Client:** React 19, Vite, TypeScript, CSS Modules, TanStack Query, Zod, `@mucsi96/react-ui`. +- **AI:** Anthropic Messages API (`claude-sonnet-4-6`), Express mock for E2E. +- **Authentication:** platform oauth2-proxy/Entra, HttpOnly sessions, backend JWT validation. +- **Configuration:** Azure Key Vault via workload identity in production. +- **Delivery:** GitHub Actions, native Rust container, Azure Blob static assets, + chart-owned authenticated Gateway documents and API routes. +- **Testing:** Playwright end-to-end tests against the containerized application. -This repository publishes a diff of the last 2 weeks of changes to GitHub Pages. AI agents on other projects can fetch this diff to stay in sync with the latest patterns from skeleton-app. +## Quick start -- **Commits**: `https://mucsi96.github.io/skeleton-app/commits.txt` -- **Diff**: `https://mucsi96.github.io/skeleton-app/diff.patch` (or `https://mucsi96.github.io/skeleton-app/diff.txt` to view inline in browser) +Install Podman separately (on WSL enable systemd). The Nix dev shell supplies +Rustup, Node and deployment tools; Rust is pinned in `server/rust-toolchain.toml`. -The pages build runs on every push to main, weekly on Monday, and on manual dispatch. +```bash +nix develop +scripts/install_dependencies.sh +scripts/pod_up.sh +cd test && npm test +``` -## Port Mapping +The pod includes PostgreSQL, the Rust API, mock OIDC/Anthropic services, nginx and +Traefik. Playwright supplies gateway identity/profile fixtures; the API still +verifies real mock-issued JWTs. Visit `http://localhost:8150` through those fixtures +for authenticated data. No local oauth2-proxy/Redis stack is required. -All host-exposed ports use the **xx50–xx59** range for their last two digits to avoid clashes with other local projects. +For a local Rust process, start the test pod for mock services, then: -| Port | Service | Context | -|------|----------------------|-------------------------------------| -| 3050 | Mock Anthropic API | Test pod | -| 4250 | Angular dev server | Local dev | -| 5450 | PostgreSQL | Dev database | -| 5451 | PostgreSQL | Test pod | -| 8050 | Mock OAuth2 provider | Test pod | -| 8053 | Spring Boot server | Local dev (VSCode) | -| 8054 | Spring Boot server | Test pod (internal, behind Traefik) | -| 8150 | Traefik (web) | Test pod | -| 8151 | Traefik (admin) | Test pod | -| 8152 | Spring Actuator | Local dev & test | +```bash +scripts/dev_db_up.sh +cd server +LOCO_ENV=development PORT=8053 \ +DATABASE_URL=postgres://postgres:postgres@localhost:5450/skeleton \ +OIDC_ISSUER=http://localhost:8050/default API_CLIENT_ID=mock-api-client-id \ +ANTHROPIC_API_KEY=mock-anthropic-key ANTHROPIC_BASE_URL=http://localhost:3050 \ +cargo run --locked -- start +``` -## Development Environment +`cd client && npm start` runs Vite on 4250 with `/api` proxied to 8053. A direct +development browser still needs gateway identity; it does not bypass backend auth. +VS Code includes a Rust debug launch with the same local configuration. -System tooling (JDK 21, Maven, Node, jq, kubectl, helm, azure-cli) is provided by -a Nix flake dev shell: +## Checks ```bash -nix develop # enter the dev shell manually -# or, with direnv installed, `direnv allow` once and it loads automatically +cd client && npm run lint && npm run build +cd server && cargo fmt --all --check && cargo clippy --locked --workspace --all-targets -- -D warnings +cd test && npm test +node --test scripts/prepare-client.test.mjs +python3 scripts/check_static_assets.py client/dist ``` -Then install the per-project dependencies: +Run each command from the repository root. Start the test pod with +`scripts/pod_up.sh` before running Playwright. Application behavior is tested +end-to-end in Playwright rather than React or Rust unit tests. -```bash -scripts/install_dependencies.sh -``` +## API, data and security -**Podman** is a distro-level prerequisite and is not managed by the flake -(rootless Podman needs setuid `newuidmap`/`newgidmap` helpers the Nix store -cannot provide). On WSL, enable `systemd=true` in `/etc/wsl.conf` and install it -via your distro, e.g. `apt install podman`. +`GET /api/greeting` reads the first row (by ID) of `hello.greetings`, requests a +short greeting from Anthropic and returns `{name,message,aiGreeting}`. JWT validation +requires RS256, the configured issuer/audience, valid time claims, `api-access` +scope and `readGreetings` role. `/healthz` checks database access after startup +migrations and OIDC discovery have succeeded. -## Quick Start +The initial API GET sets a readable Secure, host-only `__Host-XSRF-TOKEN` cookie +at `/`, with SameSite=Lax. All unsafe API requests require matching `X-XSRF-TOKEN` +proof, including requests with proxy-injected bearer credentials. The client fetch +helper adds that proof only to same-origin mutations. OAuth tokens remain at the +gateway; there is no sign-in/out UI or frontend token storage. `/oauth2/userinfo` +only supplies the read-only profile menu. -```bash -# Start test stack -scripts/pod_up.sh +SeaORM migrations preserve the existing `hello.greetings` table, IDs, sequence and +Liquibase changelog. Only a new database is seeded. No export/reset is required. -# Run E2E tests -cd test && npm test +## Runtime configuration and deployment + +One native Rust image supports all environments; no build-time profile is needed: + +```bash +podman build -t localhost/skeleton-app-server:test server +podman run --rm localhost/skeleton-app-server:test --version ``` + +`LOCO_ENV` selects `config/development.yaml`, `test.yaml` or `production.yaml`. +Development/test require the environment +variables shown above. Production uses `AZURE_KEYVAULT_ENDPOINT` and Azure workload +identity (injected tenant/client/token-file variables) to read the existing secrets: +`db-url`, `db-username`, `db-password`, `tenant-id`, `api-client-id`, `claude-api-key`. +JDBC PostgreSQL URLs remain accepted. Secrets are loaded at startup. Production +listens on `0.0.0.0:8080`; `PORT` overrides the port. Logging is configured in YAML. + +## Application structure + +- `client/src/`: function components with colocated CSS Modules; TanStack Query + owns server state and Zod validates API responses. +- `server/src/app.rs`: Loco application hooks, routes and infrastructure setup. +- `server/src/controllers/`: HTTP handlers; `models/`: SeaORM entities; + `services/`: typed external API clients; `middleware/`: JWT and CSRF enforcement. +- `server/config/`: Loco environment configuration and typed application settings. +- `server/migration/`: versioned SeaORM schema migrations, applied at startup. + +Run Loco commands from `server/`, for example `cargo run -- routes` or +`cargo run -- db migrate`. Local overrides use `config/development.local.yaml`. + +The `hello-server` release uses `rust-app` 7.0.0 with workload identity, +JWT configuration and `/api` routing. The server uses +a non-root distroless image and handles SIGTERM gracefully. Production Key Vault +access requires the existing workload identity federation and secret-read grants. + +See [static client deployment](docs/static-hosting.md). The tested Vite artifact +is uploaded to Azure Storage; the `static-client-app` chart authenticates documents +before rewriting deep links to index. Public modules/styles/fonts/icons load from +Blob storage with anonymous CORS. API/profile/Faro requests stay on the application +origin. Faro settings are compiled into the bundle; there is no runtime config +marker, bootstrap fetch, or production client container. The logging route strips +credentials and enforces collector origin/rate-limit controls. + +## Ports + +| Port | Service | +|------|---------| +| 3050 | Mock Anthropic | +| 4250 | Vite dev server | +| 5450 | Development PostgreSQL | +| 5451 | Test PostgreSQL | +| 8050 | Mock OIDC | +| 8053 | Local Rust API | +| 8054 | Test Rust API (pod-internal) | +| 8150 | Test Traefik web | +| 8151 | Test Traefik admin | + +## AI pattern sync + +This repository publishes the last two weeks of changes to GitHub Pages on main +pushes, weekly, and on manual dispatch: + +- [Commits](https://mucsi96.github.io/skeleton-app/commits.txt) +- [Diff](https://mucsi96.github.io/skeleton-app/diff.patch) diff --git a/client/.gitignore b/client/.gitignore index cc7b141..04c6cd5 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,42 +1,7 @@ -# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. - -# Compiled output -/dist -/tmp -/out-tsc -/bazel-out - -# Node -/node_modules +/dist/ +/node_modules/ +# Legacy local build cache from before the React migration. +/.angular/ +*.tsbuildinfo npm-debug.log -yarn-error.log - -# IDEs and editors -.idea/ -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Visual Studio Code -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history/* - -# Miscellaneous -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -testem.log -/typings - -# System files .DS_Store -Thumbs.db diff --git a/client/Dockerfile b/client/Dockerfile deleted file mode 100644 index 18c9bec..0000000 --- a/client/Dockerfile +++ /dev/null @@ -1,19 +0,0 @@ -FROM docker.io/library/node:26 AS build - -WORKDIR /workspace - -COPY package*.json ./ -RUN npm install -COPY . . -RUN npm run build - - -FROM docker.io/library/nginx:1.31.6 -LABEL org.opencontainers.image.source="https://github.com/mucsi96/skeleton-app" - -RUN apt-get update && apt-get install -y --no-install-recommends wget && rm -rf /var/lib/apt/lists/* - -COPY nginx.conf /etc/nginx/conf.d/default.conf -COPY --from=build /workspace/dist /usr/share/nginx/html - -CMD ["nginx", "-g", "daemon off;"] diff --git a/client/angular.json b/client/angular.json deleted file mode 100644 index 829d6c5..0000000 --- a/client/angular.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "client": { - "projectType": "application", - "schematics": {}, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular/build:application", - "options": { - "outputPath": { - "base": "dist", - "browser": "" - }, - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": [ - { - "glob": "**/*", - "input": "public" - } - ], - "styles": [ - "src/styles.scss" - ], - "scripts": [], - "allowedCommonJsDependencies": [ - "ua-parser-js" - ] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "2MB", - "maximumError": "5MB" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "6kb", - "maximumError": "8kb" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular/build:dev-server", - "configurations": { - "production": { - "buildTarget": "client:build:production" - }, - "development": { - "buildTarget": "client:build:development", - "proxyConfig": "proxy.conf.json" - } - }, - "defaultConfiguration": "development" - }, - "extract-i18n": { - "builder": "@angular/build:extract-i18n" - } - } - } - }, - "cli": { - "analytics": false - }, - "schematics": { - "@schematics/angular:component": { - "type": "component" - }, - "@schematics/angular:directive": { - "type": "directive" - }, - "@schematics/angular:service": { - "type": "service" - }, - "@schematics/angular:guard": { - "typeSeparator": "." - }, - "@schematics/angular:interceptor": { - "typeSeparator": "." - }, - "@schematics/angular:module": { - "typeSeparator": "." - }, - "@schematics/angular:pipe": { - "typeSeparator": "." - }, - "@schematics/angular:resolver": { - "typeSeparator": "." - } - } -} diff --git a/client/eslint.config.js b/client/eslint.config.js new file mode 100644 index 0000000..a3be242 --- /dev/null +++ b/client/eslint.config.js @@ -0,0 +1,19 @@ +import js from '@eslint/js'; +import { defineConfig, globalIgnores } from 'eslint/config'; +import globals from 'globals'; +import hooks from 'eslint-plugin-react-hooks'; +import refresh from 'eslint-plugin-react-refresh'; +import tseslint from 'typescript-eslint'; + +export default defineConfig([ + globalIgnores(['dist', 'node_modules']), + { + files: ['**/*.{ts,tsx}'], + extends: [js.configs.recommended, tseslint.configs.recommended], + languageOptions: { globals: { ...globals.browser, ...globals.node } }, + }, + { + files: ['src/**/*.{ts,tsx}'], + extends: [hooks.configs.flat.recommended, refresh.configs.vite], + }, +]); diff --git a/client/src/index.html b/client/index.html similarity index 50% rename from client/src/index.html rename to client/index.html index ba66291..57a286d 100644 --- a/client/src/index.html +++ b/client/index.html @@ -1,7 +1,6 @@ - Hello @@ -11,19 +10,12 @@ - - - - - + + + - - + +
+ diff --git a/client/nginx.conf b/client/nginx.conf index 8a2fc09..9ea4adb 100644 --- a/client/nginx.conf +++ b/client/nginx.conf @@ -40,6 +40,11 @@ server { expires -1; } + # Direct Kubernetes probes use / without going through the Gateway. + location = / { + rewrite ^ /index.html last; + } + # The client chart's Gateway route owns SPA document selection. location / { try_files $uri =404; diff --git a/client/package-lock.json b/client/package-lock.json index 5287e09..c6c3f6b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,790 +1,695 @@ { "name": "skeleton-client", - "version": "0.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "skeleton-client", - "version": "0.0.0", + "version": "0.1.0", "dependencies": { - "@angular/cdk": "22.2.2", - "@angular/common": "22.2.2", - "@angular/compiler": "22.2.2", - "@angular/core": "22.2.2", - "@angular/forms": "22.2.2", - "@angular/material": "22.2.2", - "@angular/platform-browser": "22.2.2", - "@angular/router": "22.2.2", - "@grafana/faro-web-sdk": "^2.7.0", - "@mucsi96/angular-material-theme": "^1.12.0", - "rxjs": "7.8.2", - "tslib": "2.8.1", - "zone.js": "0.16.3" + "@fontsource/roboto": "5.3.0", + "@grafana/faro-web-sdk": "^2.13.0", + "@mucsi96/react-ui": "^0.2.0", + "@tanstack/react-query": "^5.104.1", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "zod": "^4.6.5" }, "devDependencies": { - "@angular/build": "22.2.2", - "@angular/cli": "22.2.2", - "@angular/compiler-cli": "22.2.2", - "typescript": "6.0.3" + "@eslint/js": "^10.0.1", + "@types/node": "^26.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^6.1.2", + "eslint": "^10.12.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.7", + "globals": "^17.0.0", + "typescript": "~6.0.3", + "typescript-eslint": "^8.71.1", + "vite": "^8.3.4" + }, + "engines": { + "node": ">=24" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@angular-devkit/architect": { - "version": "0.2202.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2202.2.tgz", - "integrity": "sha512-7ScBo47haHyRGG5M5ZEpbhwHgO2LEDbCLwNCjpjwhtRFDIEmAFbULM1OQjIybN3x+wOyY1kWRK7KvihCbs371g==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "22.2.2", - "rxjs": "7.8.2" - }, - "bin": { - "architect": "bin/cli.js" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=6.9.0" } }, - "node_modules/@angular-devkit/core": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.2.2.tgz", - "integrity": "sha512-iQexb5xUON9AkTzvBiMftrHWLguIlYv6M/BOH/sj7U5L8eOPMu8N269WF74xPo4n/X5tusFLqniGI0zolT2Sjg==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/generator": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.12.tgz", + "integrity": "sha512-2W76mhjrpQFO1lK5e8IvGYB2D0YZ7S2R1Z2BjO2ZUYuW+amcpK/z60U6ZZmzskwoa7sJ6XohP/Wg8H5KxXI/IA==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.20.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.7", - "rxjs": "7.8.2", - "source-map": "0.8.0" + "@babel/parser": "^7.29.12", + "@babel/types": "^7.29.11", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "node": ">=6.9.0" } }, - "node_modules/@angular-devkit/schematics": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.2.2.tgz", - "integrity": "sha512-uCpFZbQgFUrOjKHLeYSCaYCJdufauYom8yFGggm67yetMAGKPbmRvUEko8i8auNFoBQ+1w1CivjSTwtmXQzZkA==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.2.2", - "jsonc-parser": "3.3.1", - "magic-string": "1.4.1", - "ora": "9.4.1", - "rxjs": "7.8.2" - }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=6.9.0" } }, - "node_modules/@angular/build": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-22.2.2.tgz", - "integrity": "sha512-QHJWkZdEWTqqb3+HiSp8lnuS4iQJCa7yTK9gg5TaMIjCoZzP9mD9L417stiVDZGj2J3Y9mrml044nEVvSbW0ig==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-string-parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.11.tgz", + "integrity": "sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==", "dev": true, "license": "MIT", - "dependencies": { - "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2202.2", - "@babel/core": "8.0.5", - "@inquirer/confirm": "6.3.2", - "@parcel/watcher": "2.6.0", - "@vitejs/plugin-basic-ssl": "2.3.0", - "beasties": "0.5.4", - "browserslist": "^4.26.0", - "chokidar": "5.0.0", - "esbuild": "0.28.2", - "https-proxy-agent": "9.1.0", - "jsonc-parser": "3.3.1", - "listr2": "11.1.0", - "magic-string": "1.4.1", - "mrmime": "2.0.1", - "oxc-parser": "0.150.0", - "parse5-html-rewriting-stream": "8.0.1", - "picomatch": "4.0.7", - "piscina": "5.3.2", - "rolldown": "1.2.8", - "sass": "1.104.1", - "sass-embedded": "1.104.1", - "semver": "7.8.5", - "source-map-support": "0.5.21", - "tinyglobby": "0.2.17", - "vite": "8.3.0", - "xxhash-wasm": "1.1.0" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "optionalDependencies": { - "lmdb": "3.5.6" - }, - "peerDependencies": { - "@angular/compiler": "^22.0.0", - "@angular/compiler-cli": "^22.0.0", - "@angular/core": "^22.0.0", - "@angular/localize": "^22.0.0", - "@angular/platform-browser": "^22.0.0", - "@angular/platform-server": "^22.0.0", - "@angular/service-worker": "^22.0.0", - "@angular/ssr": "^22.2.2", - "istanbul-lib-instrument": "^6.0.0", - "karma": "^6.4.0", - "less": "^4.2.0", - "ng-packagr": "^22.0.0", - "postcss": "^8.4.0", - "rollup": "^4.0.0", - "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", - "tslib": "^2.3.0", - "typescript": ">=6.0 <6.1", - "vitest": "^4.0.8 || ^5.0.0" - }, - "peerDependenciesMeta": { - "@angular/core": { - "optional": true - }, - "@angular/localize": { - "optional": true - }, - "@angular/platform-browser": { - "optional": true - }, - "@angular/platform-server": { - "optional": true - }, - "@angular/service-worker": { - "optional": true - }, - "@angular/ssr": { - "optional": true - }, - "istanbul-lib-instrument": { - "optional": true - }, - "karma": { - "optional": true - }, - "less": { - "optional": true - }, - "ng-packagr": { - "optional": true - }, - "postcss": { - "optional": true - }, - "rollup": { - "optional": true - }, - "tailwindcss": { - "optional": true - }, - "vitest": { - "optional": true - } + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@angular/cdk": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.2.2.tgz", - "integrity": "sha512-d5PWfIargIEV0rlwZea2pYDGb8FhF9df6a6XFRLThla6NKiJRs8utqW+7pyY9wCPFR3SSCGHC05xFh7qv91hdw==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, "license": "MIT", - "dependencies": { - "parse5": "^8.0.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^22.0.0 || ^23.0.0", - "@angular/core": "^22.0.0 || ^23.0.0", - "@angular/forms": "^22.0.0 || ^23.0.0", - "@angular/platform-browser": "^22.0.0 || ^23.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@angular/cli": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.2.2.tgz", - "integrity": "sha512-AALIN+zai0CiA7HgSCGVPHyZyiw3yFWliCfbaS4ueHDJHVZ8QhVjRUrnfGZc3EJnigcyQ0w2DKeTxjwqpDjKew==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/parser": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.12.tgz", + "integrity": "sha512-WJ7JBp/Q4+z/ImydtI7jS6NVco5++632ExBemSX+Ysb+G1lCwQ5BVo3SY+jGGOcZXI4ZccbZSUSJLNBW6eEpJg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2202.2", - "@angular-devkit/core": "22.2.2", - "@angular-devkit/schematics": "22.2.2", - "@inquirer/prompts": "8.7.2", - "@listr2/prompt-adapter-inquirer": "4.2.7", - "@modelcontextprotocol/server": "2.3.1", - "@schematics/angular": "22.2.2", - "jsonc-parser": "3.3.1", - "listr2": "11.1.0", - "npm-package-arg": "14.0.0", - "parse5-html-rewriting-stream": "8.0.1", - "semver": "7.8.5", - "yargs": "18.1.0", - "zod": "4.6.5" + "@babel/types": "^7.29.11" }, "bin": { - "ng": "bin/ng.js" + "parser": "bin/babel-parser.js" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=6.0.0" } }, - "node_modules/@angular/common": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.2.2.tgz", - "integrity": "sha512-d+mbF1UQLpsoJiC7h4pl58G7XeLHKU8DdLbq9u7TuOK0AnC1t2rrphi8M8WqUrZ+bfmFKCU4i1i4+vOF1N5GtA==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "@angular/core": "22.2.2", - "rxjs": "^6.5.3 || ^7.4.0" + "node": ">=6.9.0" } }, - "node_modules/@angular/compiler": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-22.2.2.tgz", - "integrity": "sha512-hg8Kvhq29w97vs3O5KsSeqA+oobrAKpr/GvsWBIqjRzfrxxeFdjRRoEv1/MVgMSJK36VLigNCjB1qPF3MB17uA==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/traverse": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.12.tgz", + "integrity": "sha512-MscXe/NAZcOkYEsRajHZFt3ynsb22PUi6CTrp5U7+RYycR9By84mn9mFN54YgfITiqK4hFx3Ju3tZSyzfpS5ew==", + "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.12", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.12", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.11", + "debug": "^4.3.1" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + "node": ">=6.9.0" } }, - "node_modules/@angular/compiler-cli": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-22.2.2.tgz", - "integrity": "sha512-7PCIBTVIzG4oyAkDeBRPJpGcgSDLBCKn+2Pp9+gXnXOEETdWhV34so1fpWZ2GWBZsxXav7Ry0K93vFwF93yWoQ==", + "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.11.tgz", + "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "8.0.1", - "@jridgewell/sourcemap-codec": "^1.4.14", - "chokidar": "^5.0.0", - "convert-source-map": "^1.5.1", - "reflect-metadata": "^0.2.0", - "semver": "^7.0.0", - "tslib": "^2.3.0", - "yargs": "^18.0.0" - }, - "bin": { - "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js" + "@babel/helper-string-parser": "^7.29.11", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "@angular/compiler": "22.2.2", - "typescript": ">=6.0 <6.1" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=6.9.0" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.1.tgz", - "integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==", + "node_modules/@babel/helper-module-imports/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/generator": "^8.0.0", - "@babel/helper-compilation-targets": "^8.0.0", - "@babel/helpers": "^8.0.0", - "@babel/parser": "^8.0.0", - "@babel/template": "^8.0.0", - "@babel/traverse": "^8.0.0", - "@babel/types": "^8.0.0", - "@types/gensync": "^1.0.5", - "convert-source-map": "^2.0.0", - "empathic": "^2.0.1", - "gensync": "^1.0.0-beta.2", - "import-meta-resolve": "^4.2.0", - "json5": "^2.2.3", - "obug": "^2.1.1", - "semver": "^7.7.3" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", "dev": true, - "license": "MIT" - }, - "node_modules/@angular/core": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-22.2.2.tgz", - "integrity": "sha512-mFiSoAs7Gp/7VlbdSxDyV2I/FEyYeNZRaHH7QrMWSB9t+k7wm37uCaYOt9fy6fgXU/UbCgBESp09fV9bUTQcmA==", "license": "MIT", "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "@angular/compiler": "22.2.2", - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.15.0 || ~0.16.0" - }, - "peerDependenciesMeta": { - "@angular/compiler": { - "optional": true - }, - "zone.js": { - "optional": true - } + "hashery": "^1.5.1", + "keyv": "^5.6.0" } }, - "node_modules/@angular/forms": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-22.2.2.tgz", - "integrity": "sha512-Fgh+EnDoULSFzuDy44da/5Chi+4Sd2Qc4SLjFj23bktvMJ1yfuBPWkvpR9xgWg9Auq+9x84wJVK6WyNwIjXYWA==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, "license": "MIT", "dependencies": { - "@standard-schema/spec": "^1.0.0", - "tslib": "^2.3.0", - "zod": "^4.0.10" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "@angular/common": "22.2.2", - "@angular/core": "22.2.2", - "@angular/platform-browser": "22.2.2", - "rxjs": "^6.5.3 || ^7.4.0" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@angular/material": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-22.2.2.tgz", - "integrity": "sha512-G8nnt6yO7z64yZZbeF0l0fSztgZYv1TBFdGlexweyPfBlRn7N2X14Uv/TWht46vrXvExGuZOiR3c05XELd80fw==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@angular/cdk": "22.2.2", - "@angular/common": "^22.0.0 || ^23.0.0", - "@angular/core": "^22.0.0 || ^23.0.0", - "@angular/forms": "^22.0.0 || ^23.0.0", - "@angular/platform-browser": "^22.0.0 || ^23.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@angular/platform-browser": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.2.2.tgz", - "integrity": "sha512-DnAyZTLty5bVNeDhcSPNQABqb9SmNvYfYhvgU3dKoGEpONrrECfYo/X4MN0g7Z9Dn/DkgBCNRoC9AZWxbO9HDQ==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "@angular/animations": "22.2.2", - "@angular/common": "22.2.2", - "@angular/core": "22.2.2" - }, - "peerDependenciesMeta": { - "@angular/animations": { - "optional": true - } + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@angular/router": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-22.2.2.tgz", - "integrity": "sha512-45HP/henqbPRTCBHzwF4ZV8JU75u2TmBMR4BtwcXcKF5SWragKWE0rMz4NpHnCQIy3bIy5SVTvawpf7EJ/kRyw==", - "license": "MIT", + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.3.0" + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" }, "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "@angular/common": "22.2.2", - "@angular/core": "22.2.2", - "@angular/platform-browser": "22.2.2", - "rxjs": "^6.5.3 || ^7.4.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/code-frame": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.6.tgz", - "integrity": "sha512-uMHhvmDmwFiLuiozaoRYTZHqMFuu3fem/X9JY78lohAuLoh8LSGGC8JqUzo2cVuBsBxkjMZNk56CE7ock8Xxkw==", + "node_modules/@eslint/config-helpers": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-validator-identifier": "^8.0.6", - "js-tokens": "^10.0.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/compat-data": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.5.tgz", - "integrity": "sha512-YLsYoQMvL8l8WrGpN3Zj7O1wK5LEBN+cQtux7BcuHyxIXve724XG+zuJ1n3U1cUweRtTzQOA4IHbuQw3N34SZw==", + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/core": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.5.tgz", - "integrity": "sha512-2/oWkgTbBYoqioCWAE4XJobOrzwxTDa5/XjDP3tJ1BhDr/owcd9qnXBp4xc3/2G5X4bvXM04nrxbRJxFcXAxFQ==", + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/generator": "^8.0.5", - "@babel/helper-compilation-targets": "^8.0.5", - "@babel/helpers": "^8.0.5", - "@babel/parser": "^8.0.5", - "@babel/template": "^8.0.0", - "@babel/traverse": "^8.0.5", - "@babel/types": "^8.0.5", - "@types/gensync": "^1.0.5", - "convert-source-map": "^2.0.0", - "empathic": "^2.0.1", - "gensync": "^1.0.0-beta.2", - "import-meta-resolve": "^4.2.0", - "json5": "^2.2.3", - "obug": "^2.1.1", - "verkit": "^0.3.2" - }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } } }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } }, - "node_modules/@babel/generator": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.6.tgz", - "integrity": "sha512-/pcanjdRsonCexCuxgGD8fKnBLLzk2i9uM4kmcmGyyev2R5YDs+rafMYZ89RvaGY1mW8T7C5au0TyYaEeHBGng==", + "node_modules/@eslint/plugin-kit": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@babel/parser": "^8.0.6", - "@babel/types": "^8.0.6", - "@jridgewell/gen-mapping": "0.4.0-beta.0", - "@jridgewell/trace-mapping": "^0.3.31", - "@types/jsesc": "^2.5.0", - "jsesc": "^3.0.2" + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.4.0-beta.0", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.4.0-beta.0.tgz", - "integrity": "sha512-JdGNkbE4GlNPYQhM0L95fBQr7ctLZJ276QXQLTad4t1oSdnnCI3fDq9DW3BqYAWv8Wc3+HS+4Gsii1oPMCfz1w==", - "dev": true, - "license": "MIT", + "node_modules/@fontsource/roboto": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.3.0.tgz", + "integrity": "sha512-BapRJOWYP+LZ21zp+wBQjfpPYKRoxc4LspJ/RLuI+HSMBD5u/X4O+ESDrSvEqDSy0rAl7GwBJ+09mdc16cVQ1Q==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@grafana/faro-core": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-core/-/faro-core-2.13.0.tgz", + "integrity": "sha512-Zfmroynd3y/NRghfIYXGCAinIb7mIx8EhGBpC3WUYoJT/4nO/jWvbKBEpELP29Z7g1Ul2TlJwbmNa1yh3x3+uw==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.6.0-beta.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/otlp-transformer": "^0.223.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.7.tgz", - "integrity": "sha512-ilAZCdOOlOVA7dQbaFNw2f/59p6GW33NxTopc3DvEE3efp3ZXTrGX/yZScaKw8/vd9bq31Ag0EcXiLw32bAgJg==", - "dev": true, - "license": "MIT", + "node_modules/@grafana/faro-web-sdk": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@grafana/faro-web-sdk/-/faro-web-sdk-2.13.0.tgz", + "integrity": "sha512-k/vZL73Ii4PR6IyhyZZU/wWAlLL8HyPQ1re9CFyyIN2bXuX5b0dTYTLBHlEAK3oGqi7Nj/jGwKXoM27BNLPLuQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/compat-data": "^8.0.5", - "@babel/helper-validator-option": "^8.0.0", - "browserslist": "^4.24.0", - "flru": "1.0.2", - "verkit": "^0.5.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" + "@grafana/faro-core": "^2.13.0", + "ua-parser-js": "1.0.41", + "web-vitals": "^6.0.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/verkit": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz", - "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12.0" + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@babel/helper-globals": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.6.tgz", - "integrity": "sha512-OdnA/N52LhzFpeUuVz5YGuSWjc7TPHiFmVYZbPlSgExocO2GwbxVpSni9MVs5wwW+wZ4kPuwBEBN9pIPDYz1mA==", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": ">=18.18.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.6.tgz", - "integrity": "sha512-+6HYEBnsDRZHJtUTAEfMQd0zMDqdFHS7C+5vAsEZqBUr3vEMWOWlHJ0Jz1gS8jJIlCvLsuA6ivmeoqzH936YcA==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": ">=18.18.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.6.tgz", - "integrity": "sha512-HYx0YmuchRxRSpnjvcNffnPS8DCauKNmnumIuHG3jnQAVewRA7kfJGwF13ayEpSZs7s4R/oBH4eppuXcAQd5JQ==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/helper-validator-option": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz", - "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@babel/helpers": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.7.tgz", - "integrity": "sha512-5dMj5kFwS2AY7Dt4PZp4px3c5ThMbbEa7tZfuHTncCGSFYq8uoA1ufDE1IS/lYpQedE+3+GQ3cPZUiplIu195w==", - "dev": true, - "license": "MIT", + "node_modules/@internationalized/date": { + "version": "3.12.4", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.4.tgz", + "integrity": "sha512-M1dEn4c1U1HsSlaVR8upZtSqvXrTkHDfv18H01uCSJyjVLDxnBR38v/fMxecmlwXKR4i9HeZcmgQAPE6A+aGJQ==", + "license": "Apache-2.0", "dependencies": { - "@babel/template": "^8.0.0", - "@babel/types": "^8.0.6" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" + "@swc/helpers": "^0.5.0" } }, - "node_modules/@babel/parser": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.7.tgz", - "integrity": "sha512-UkDwEbPO1px2JQSrdh4qIgaH1JgG7GO/pFeJkpxhDxIETkT/QvGpnigXIw75ViHYPtIgKITmVUJqLjiO+JuWjA==", - "dev": true, - "license": "MIT", + "node_modules/@internationalized/number": { + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.9.tgz", + "integrity": "sha512-GgWy2caO/+hV9sT/oCTWGHvbjmJMPT9kkXzoKRLnkEq7adghhR7UprhvY9sXrKfrp3NcDfhF6QQHXR1KfQbB8g==", + "license": "Apache-2.0", "dependencies": { - "@babel/types": "^8.0.6" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" + "@swc/helpers": "^0.5.0" } }, - "node_modules/@babel/template": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz", - "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==", - "dev": true, - "license": "MIT", + "node_modules/@internationalized/string": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.10.tgz", + "integrity": "sha512-PDx6//vHSpRnHfxqMqto11zQvhsaU74O3mKv2F/0eicGZcl9NLjQmGlbHz/LsJh5tLKp4A4L7ZVTzN1/MmMTvA==", + "license": "Apache-2.0", "dependencies": { - "@babel/code-frame": "^8.0.0", - "@babel/parser": "^8.0.0", - "@babel/types": "^8.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" + "@swc/helpers": "^0.5.0" } }, - "node_modules/@babel/traverse": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.7.tgz", - "integrity": "sha512-bVV0brinsTWgc6ptSIoQo3GbITtl0VZAqEUJbHHcyfDPEu+q/fEvlYEa+6H85HoK8IdksKBFtKJbJFZ6Kff+zg==", + "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==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^8.0.6", - "@babel/generator": "^8.0.6", - "@babel/helper-globals": "^8.0.6", - "@babel/parser": "^8.0.7", - "@babel/template": "^8.0.0", - "@babel/types": "^8.0.6", - "obug": "^3.0.0" - }, - "engines": { - "node": "^22.18.0 || >=24.11.0" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@babel/traverse/node_modules/obug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz", - "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], "license": "MIT", - "engines": { - "node": ">=12.20.0" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@babel/types": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.6.tgz", - "integrity": "sha512-c+xgSWboV2pdwXP67BUWDVRHi2BO5Q3KwxyFVs7taVTY+fsK47/L51ZXQoV9rozHJDNHvJ4v4WEsI/IlxV2l2A==", + "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", - "dependencies": { - "@babel/helper-string-parser": "^8.0.6", - "@babel/helper-validator-identifier": "^8.0.6" - }, "engines": { - "node": "^22.18.0 || >=24.11.0" + "node": ">=6.0.0" } }, - "node_modules/@bufbuild/protobuf": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.16.0.tgz", - "integrity": "sha512-FWa0sPlqYGJgpTs6OxBRcL/AW4JT0OIO+W1ajerluoTVh8CV0B7XM1qsNCRgnkSCkRCgOICKHRQlY17jrsm0+Q==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "dev": true, - "license": "(Apache-2.0 AND BSD-3-Clause)" + "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", - "cpu": [ - "ppc64" - ], + "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", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", - "cpu": [ - "arm" - ], + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, "engines": { - "node": ">=18" + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", - "cpu": [ - "arm64" - ], + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", "dev": true, + "license": "MIT" + }, + "node_modules/@mucsi96/react-ui": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mucsi96/react-ui/-/react-ui-0.2.0.tgz", + "integrity": "sha512-LqKFVYVOxpLQBZBy41i6JpQ+nHFo/Hn03AzIFIPZDCkXCJakHacLaCONnHC0qOySsbjeSe46ZaohogBCgaoC4Q==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "react-aria-components": "1.22.1" + }, + "peerDependencies": { + "react": "^19.3.0", + "react-dom": "^19.3.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.223.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.223.0.tgz", + "integrity": "sha512-Oepm6etVPFCn0VWB1t833iOTgz1eYBDUPxcrOR/XvwzD1+Ag9VzSPSrrKAFNJ/haatj+8CXbG47pZXvdNQKDJw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.12.0.tgz", + "integrity": "sha512-1HsSAuvT4/my0QrXWsyXFdWjKaPeCHsismKZgEEIb8NK13LP6DrMRlsUbvD/0F9mDWK3xDom9AMv3IscxgOnOQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.223.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.223.0.tgz", + "integrity": "sha512-oxmmPL5/MbSsO8K588V9n/XLIe7FZTK30Fo+/U/lAnt0ZIK/hoPM03n2WpSTZVbUBGTUE7aLyxnAzh7nE2PD4Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.223.0", + "@opentelemetry/core": "2.12.0", + "@opentelemetry/resources": "2.12.0", + "@opentelemetry/sdk-logs": "0.223.0", + "@opentelemetry/sdk-metrics": "2.12.0", + "@opentelemetry/sdk-trace": "2.12.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.12.0.tgz", + "integrity": "sha512-+rSRoOdln6NhXTVcBdHSlZxJDNzwxadeweK2ltZO3tVtfp6aklABc06xclDk6ovRR+EiGgIcSbh/6NgjFhnb3A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.12.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.223.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.223.0.tgz", + "integrity": "sha512-ApiAfUiUh6fmJt1GbsBuoeDn8D8IL42UvGyPUr8o1Z89ZeIiOCE1rZ78KkIUjEX3OV8Oorl9ez5Qjo43ZynDyw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.223.0", + "@opentelemetry/core": "2.12.0", + "@opentelemetry/resources": "2.12.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.12.0.tgz", + "integrity": "sha512-mVMaEHwCUJuY3S4Esn+nT0yQA3qCEGh+SOPJsXygU0Gl453WcsDNjtEa8EfdewMwoLyr1tlofB4fXytVpiXuow==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.12.0", + "@opentelemetry/resources": "2.12.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.12.0.tgz", + "integrity": "sha512-ImVuRQ6faOsTi1Wna88s2avgrrf/iDgXPigIeynkUhjstMuoQUDOJXgkez2j1mlU4btjXcXBGa+q7qKFYR3GsA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.12.0", + "@opentelemetry/resources": "2.12.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@react-types/shared": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.37.0.tgz", + "integrity": "sha512-VNlZuifu4tHdxWPfHvoMfKsHA9kVTCGkduv5vKVTdinm8wHFJNhyVB5RzIMiRFj0q3RKoCbP68u2zaoBSiFueg==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz", + "integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==", "cpu": [ - "x64" + "arm" ], "dev": true, "license": "MIT", @@ -793,13 +698,13 @@ "android" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz", + "integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==", "cpu": [ "arm64" ], @@ -807,18 +712,18 @@ "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz", + "integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", @@ -827,30 +732,30 @@ "darwin" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz", + "integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "freebsd" + "darwin" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz", + "integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==", "cpu": [ "x64" ], @@ -861,13 +766,13 @@ "freebsd" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz", + "integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==", "cpu": [ "arm" ], @@ -878,149 +783,133 @@ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz", + "integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", - "cpu": [ - "ia32" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz", + "integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==", "cpu": [ - "loong64" + "arm64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", - "cpu": [ - "mips64el" + "libc": [ + "musl" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz", + "integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz", + "integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==", "cpu": [ - "riscv64" + "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz", + "integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==", "cpu": [ - "s390x" + "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz", + "integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz", + "integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==", "cpu": [ "arm64" ], @@ -1028,4567 +917,2064 @@ "license": "MIT", "optional": true, "os": [ - "netbsd" + "openharmony" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz", + "integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "netbsd" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz", + "integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "openbsd" + "win32" ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", - "cpu": [ - "x64" - ], + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tanstack/query-core": { + "version": "5.105.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.105.3.tgz", + "integrity": "sha512-v1rbNy7MB/4Akth7CQH+CerV13K7Ok9hAusEsfz4sCjDdu3/kOSJPoWfoB+YjdEX1eBFBWKNAGE5nqZCgdlHDw==", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@tanstack/react-query": { + "version": "5.105.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.105.3.tgz", + "integrity": "sha512-dj5hGWZmwoc9NG4enoXuYbiYwb5FxgJYPVv06eUgicMTfEMTRXn08Xv9D/r1V8TfjAv+BpxdvZFzJ1h3hSWZcQ==", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@tanstack/query-core": "5.105.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", - "cpu": [ - "x64" - ], + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", - "cpu": [ - "arm64" - ], + "node_modules/@types/estree": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz", + "integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", - "cpu": [ - "ia32" - ], + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", - "cpu": [ - "x64" - ], + "node_modules/@types/node": { + "version": "26.6.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz", + "integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@grafana/faro-core": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/@grafana/faro-core/-/faro-core-2.12.1.tgz", - "integrity": "sha512-Pg0vjgsR1BxdmLzzX9r8YcZ8rI4aXLlDGtreppZev++BbnH2utKBwCI16Vx+IzfQqHKRT+7WGc63HOue8/9J6Q==", - "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/otlp-transformer": "^0.222.0" + "undici-types": "~8.9.0" } }, - "node_modules/@grafana/faro-web-sdk": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/@grafana/faro-web-sdk/-/faro-web-sdk-2.12.1.tgz", - "integrity": "sha512-JnpZy/ztfkP3UZ3AW0DzUxVgMRTBvYz+m0oZuVi+KRpGTYz0GGF0umi0S0pAemnaUbQBo6umGdCm5CL6n8BAWQ==", - "license": "Apache-2.0", + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "devOptional": true, + "license": "MIT", "dependencies": { - "@grafana/faro-core": "^2.12.1", - "ua-parser-js": "1.0.41", - "web-vitals": "^6.0.0" + "csstype": "^3.2.2" } }, - "node_modules/@harperfast/extended-iterable": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", - "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, - "node_modules/@inquirer/ansi": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz", - "integrity": "sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==", + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "peerDependencies": { + "@types/react": "^19.3.0" } }, - "node_modules/@inquirer/checkbox": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.5.tgz", - "integrity": "sha512-bRt8J8m+Fot9CXv+zNQGXUq2ET0MggR1fPz7v6edN6MFYmsbfGnMmkmWZJEegMKqrAC8ej/o1sqisHZXZJMAfQ==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.72.1.tgz", + "integrity": "sha512-5CokTWXpmbylfFabsbvHC0CAw3XLaGnoa+nFJX5FR592h/LoZsENUE6p/rg5xvkKrFEXz6pYmgI29AgXc2N3BQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.8", - "@inquirer/core": "^12.0.3", - "@inquirer/figures": "^2.0.9", - "@inquirer/type": "4.1.1" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/type-utils": "8.72.1", + "@typescript-eslint/utils": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "@typescript-eslint/parser": "^8.72.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/confirm": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.2.tgz", - "integrity": "sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.14.tgz", + "integrity": "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" - }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 4" } }, - "node_modules/@inquirer/core": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.3.tgz", - "integrity": "sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==", + "node_modules/@typescript-eslint/parser": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.72.1.tgz", + "integrity": "sha512-ZGwZP4OCfyA0AQTpEAMWz+rtX01DRhQWW5hB0ucKDEIX5U7jdmPSaMx94rQfaPAQzIYz2BimOgKOJtjfpRFQ9g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.8", - "@inquirer/figures": "^2.0.9", - "@inquirer/type": "4.1.1", - "cli-width": "^4.1.0", - "fast-wrap-ansi": "^0.2.0", - "mute-stream": "^3.0.0", - "signal-exit": "^4.1.0" + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "debug": "^4.4.3" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/editor": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.3.tgz", - "integrity": "sha512-YsKkS2q63IiLtaDK/9nqzdComN97SDQrmKiyNggN+ceP4ty+Z6VwyTz3FpjeUWeW1Efss2xHFKCC9sx7hnrsxg==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.72.1.tgz", + "integrity": "sha512-fAuVMkwdO/huI8nyo/WKnNKf6Gag93S56Rh3Ts5mGcavwSdaN8tRg1gCeIGX8PF+nzp1BjGfO4gHhGzW1J6jTg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/external-editor": "^3.0.5", - "@inquirer/type": "4.1.1" + "@typescript-eslint/tsconfig-utils": "^8.72.1", + "@typescript-eslint/types": "^8.72.1", + "debug": "^4.4.3" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/expand": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.5.tgz", - "integrity": "sha512-uHuXLmXW+TtIfT/9vSBotypAkqn1n34Ul+CLGPos/xANyO4Ff5xZzkYhbKR4NEcfVK4a9mHQOpwVZzluSHFRGw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.72.1.tgz", + "integrity": "sha512-lC/t6eMCZZQAAKZEYGL6RDVSuFehpdmMT6h+nJIjIa6oylN/PwDgDVtEIbB7O9xFfZYtZAYLoLlDNWKJhtF+uQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@inquirer/external-editor": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.5.tgz", - "integrity": "sha512-f3QQJRIX5ZEneBHNUIuPjmbdzHnmRFJA8r2dkcb8q+OM5Uv5KtnuAttQumnrjcBVBM3mcTX1CkmtAkU58VRZxg==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.72.1.tgz", + "integrity": "sha512-e4D5R5vpeAEPBxT2BAzsFQL3sbwyeeeo5+aczgNSRK1V734jE7pTqaGFU+fXapWEQwnZbpFaTn32+Z8DwS6OTg==", "dev": true, "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.2" - }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/figures": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.9.tgz", - "integrity": "sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/input": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.6.tgz", - "integrity": "sha512-HtcJhB2QFVXbLuJ5S3syhNbTUVxYvwqV4VRBDkQceBloC9bmTViUoRFP5PbSaDZb3HzfPmpuU/gG4ybVBz4FHA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.72.1.tgz", + "integrity": "sha512-iY2wlmyrXJmx4yxUGP3aYCFF3cA/6ShddOKmLU2dx7LnEykbAM8WThlxZEfd1NddqceF6eJmZUayxx9oKIYNlg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/utils": "8.72.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/number": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.3.tgz", - "integrity": "sha512-6Yuwh1NGSbu1Lo4N1EWjXs1jKRntLg/ZCwhmeorEHde90v1XxAozdbd4Iu30eOQLW+6h1hp2O9ujNfLSbTPJnA==", + "node_modules/@typescript-eslint/types": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.72.1.tgz", + "integrity": "sha512-LmE5IhQet1BWOWEXqBrVtBPsMAOQ6Nzk35d+WLh3mk4EUF33sqlfxjio1MdYeSvKSG5skactKKuixBIKXhL4Rw==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" - }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@inquirer/password": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.2.tgz", - "integrity": "sha512-W9zYdyzogK+6110mqwaSJWCBu2yA5Q/OfnGSjjZB1bNpHlmUozXxTl0+QOZBNeVd6Qo81/qT75gW05gLAtITxw==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.72.1.tgz", + "integrity": "sha512-DAlUoUV93hIvrtIQLwCbmZQYVZwOMhiHJrOVUUIWicFZaIYjTRqlY3I/NZevfkLmSqkNHRu2qYDcq9lrn16oOQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.8", - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" + "@typescript-eslint/project-service": "8.72.1", + "@typescript-eslint/tsconfig-utils": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/visitor-keys": "8.72.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/prompts": { - "version": "8.7.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.7.2.tgz", - "integrity": "sha512-QoRB4wFIjgH5iOhSjoIKMkTvSHDuV+O3OITlIqAYO0oK5x364GJILXiMBvlPiE+klg7Xx9tq5XVqQHcGUDYYPA==", + "node_modules/@typescript-eslint/utils": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.72.1.tgz", + "integrity": "sha512-5v5liypurJBFHCBNqh/RjsymAD+VWcE0djuGY/BUqp5fC3Qn+luWDEksjuTtWjPn6i5zQlUtkZCRG/CYG0yCkA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^5.2.5", - "@inquirer/confirm": "^6.3.2", - "@inquirer/editor": "^5.3.3", - "@inquirer/expand": "^5.1.5", - "@inquirer/input": "^5.1.6", - "@inquirer/number": "^4.2.3", - "@inquirer/password": "^5.2.2", - "@inquirer/rawlist": "^5.3.5", - "@inquirer/search": "^4.3.3", - "@inquirer/select": "^5.2.5" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.72.1", + "@typescript-eslint/types": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@inquirer/rawlist": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.5.tgz", - "integrity": "sha512-1oHky1ONfCOwNrnkQGDE1oaSij/3fI6HFMSf2H/WsGO2lEyDX9My82iggITSy9ddSZ8yk8j9v41OI0fVoSIoaA==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.72.1.tgz", + "integrity": "sha512-SB8xqipSzZHUePCCLNeYxqnxq83X61/qzNhjQGbTfjxGZIeOEP7tBgWYX05Tcd6CgE02WdTJnh5b8kMZJ/+bnQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/type": "4.1.1" + "@typescript-eslint/types": "8.72.1", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@inquirer/search": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.3.tgz", - "integrity": "sha512-fyuIU1Nbpvwlikjg3gXwJFDI11+EFjqQ7P+iByfmivIKQ1vmaykNrD/vy5unHuUqUpsOsnvJ25//tPF7E/RBRA==", + "node_modules/@vitejs/plugin-react": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.2.1.tgz", + "integrity": "sha512-9KyWCij3r0+qLG3Q62vBmv0VyevmYibAtxaCIVK9o0k6CXgaajZRIe8tpfchQcdZArJ5b/7OrIz4W3b2uxVRDA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^12.0.3", - "@inquirer/figures": "^2.0.9", - "@inquirer/type": "4.1.1" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "@types/node": ">=18" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0 || ^0.3.0", + "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": ">=0.152.0 <0.157.0", + "vite": "^8.0.0" }, "peerDependenciesMeta": { - "@types/node": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "oxc-transform-react": { "optional": true } } }, - "node_modules/@inquirer/select": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.5.tgz", - "integrity": "sha512-9kc15hr8r/kI+3DO/xLog5nOzTz1jqsHXa6JBFzmQKhkoJ8Slda1I1L/uD8ZSZ9tF1yp79wwXe7mclvX1rqR2Q==", + "node_modules/acorn": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz", + "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==", "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.8", - "@inquirer/core": "^12.0.3", - "@inquirer/figures": "^2.0.9", - "@inquirer/type": "4.1.1" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=0.4.0" } }, - "node_modules/@inquirer/type": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz", - "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "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==", - "dev": true, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "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==", + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "18 || 20 || >=22" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "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==", + "node_modules/baseline-browser-mapping": { + "version": "2.11.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.27.tgz", + "integrity": "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-4.2.7.tgz", - "integrity": "sha512-k180vxSv2KqmnDxoato6pCqEJsov4U5C0EVmldZkAdNeVBxY48A/LM6TCNPGIzDK/iZSfsZP0Mw+gbWc5hXLyA==", + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^4.0.7" + "balanced-match": "^4.0.2" }, "engines": { - "node": ">=22.13.0" - }, - "peerDependencies": { - "@inquirer/prompts": ">= 3 < 9", - "listr2": "11.1.0" + "node": "20 || >=22" } }, - "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.6.tgz", - "integrity": "sha512-mY5FG4TjPAkY4P0w+OhHaUka5mDh2TX2WKYIwuKzJ1zeW3VvRgxdam/lGJTquI+bthTx5CSHDW+BAQCnNAzkEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.6.tgz", - "integrity": "sha512-foa+pwitysO8k+xhs7psBFfTKnVgR69NlZRRTHaFVDqphh7AdGpLeyRzKw/ofatr/sN6TiHRRW6mmop0ZrrppQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.6.tgz", - "integrity": "sha512-QR4YRyR5h5Z8eGXrNQjiyo2NNDfqi3tCc9dQG5Is1blCt+qWw1ZoBWhlWAr5d+jshkifMIJjVHzHGKbkKzF8Tw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.6.tgz", - "integrity": "sha512-HmiyFFdJa38s1heCMSooSPaBSFTHJ3C+ERPp28xAPlDX1YiALJVOgbry065nXd8Y7KISWjnw05zpG1RX8IfftA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.6.tgz", - "integrity": "sha512-ADzCuCF2cTNiX9kDScqcz1fjnAkxPpQNneV3KFTdV3wWtVlI2sTGzySoMTgDpinkMMFj1NTJlxA6XR8fwc4hlA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.6.tgz", - "integrity": "sha512-J7A9aEQsQiv0TYtBGL7NDIPp2lOS8nnl+zm4sWZm1xlsTTaQ4PgD096Adzdrk27rw3UxCkDXdCUa4ax41oztBQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.6.tgz", - "integrity": "sha512-1g7G0knRX2iV/voDu54yxrGqw5Dk0w2oIYb7dgJq8IkOi+m7wbD8Q3QpPFjh0C01G58S88dqGn03len6UPCXsg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@modelcontextprotocol/core": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.3.1.tgz", - "integrity": "sha512-laVmIhPGpWi7rG9q+0UigblRN0Hws/Yjlb6qLFtVqryXVLkc4h+yN8z731POD2LnAGQlFe7/tXhUm7Bi0YB91g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "zod": "^4.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@modelcontextprotocol/server": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.3.1.tgz", - "integrity": "sha512-e59MfWuSssj6DoQ96JCTqdW1AXT5/XtnTl0WWd6MU1Ka434fFUGGosCLJbGNySDhHGvxQWoRWK137FXYFkYNWw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@modelcontextprotocol/core": "2.3.1", - "zod": "^4.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", - "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", - "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", - "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", - "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", - "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", - "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@mucsi96/angular-material-theme": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@mucsi96/angular-material-theme/-/angular-material-theme-1.12.0.tgz", - "integrity": "sha512-alMkFnsIIfrK9JRKE76+16EwcTW7DvlqoPXyJTVzC7XDKz5vz/PO8sLqE4U/8YskGUp+5OAZT9fsPbAV8LFT8Q==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/cdk": ">=21.0.0", - "@angular/common": ">=21.0.0", - "@angular/core": ">=21.0.0", - "@angular/material": ">=21.0.0" - } - }, - "node_modules/@napi-rs/nice": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", - "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/nice-android-arm-eabi": "1.1.1", - "@napi-rs/nice-android-arm64": "1.1.1", - "@napi-rs/nice-darwin-arm64": "1.1.1", - "@napi-rs/nice-darwin-x64": "1.1.1", - "@napi-rs/nice-freebsd-x64": "1.1.1", - "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", - "@napi-rs/nice-linux-arm64-gnu": "1.1.1", - "@napi-rs/nice-linux-arm64-musl": "1.1.1", - "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", - "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", - "@napi-rs/nice-linux-s390x-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-musl": "1.1.1", - "@napi-rs/nice-openharmony-arm64": "1.1.1", - "@napi-rs/nice-win32-arm64-msvc": "1.1.1", - "@napi-rs/nice-win32-ia32-msvc": "1.1.1", - "@napi-rs/nice-win32-x64-msvc": "1.1.1" - } - }, - "node_modules/@napi-rs/nice-android-arm-eabi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", - "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-android-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", - "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-darwin-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", - "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-darwin-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", - "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-freebsd-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", - "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", - "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-ppc64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", - "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-riscv64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", - "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-s390x-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", - "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-x64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", - "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-linux-x64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", - "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-openharmony-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", - "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-arm64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", - "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-ia32-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", - "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-win32-x64-msvc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", - "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.222.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.222.0.tgz", - "integrity": "sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.11.0.tgz", - "integrity": "sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.222.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.222.0.tgz", - "integrity": "sha512-/F3BZ89+CJQnZkMh2tCrtcdB+XT2Dxhj4FFE+WPQ//413hmFL0/RfEX6vgOIWGhiSzrkHWTK3+6SiT7K5/g/jQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.222.0", - "@opentelemetry/core": "2.11.0", - "@opentelemetry/resources": "2.11.0", - "@opentelemetry/sdk-logs": "0.222.0", - "@opentelemetry/sdk-metrics": "2.11.0", - "@opentelemetry/sdk-trace": "2.11.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.11.0.tgz", - "integrity": "sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.11.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.222.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.222.0.tgz", - "integrity": "sha512-+19YHODIjaUCArxleaJtuufFZVpz/xvvK+VllQqE+W8hHolxdoRwHfK/s667zezwh1hkx6FFF+oYzetYgqK+Bg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.222.0", - "@opentelemetry/core": "2.11.0", - "@opentelemetry/resources": "2.11.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.11.0.tgz", - "integrity": "sha512-7GXXcObyHyDUUSG+L+kJoquty01bzm7ivE7+SSgXXJcHuPzGviptxwARmI2c+bnnxjexGQbJnyNlN8HxBP/Y7A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.11.0", - "@opentelemetry/resources": "2.11.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace/-/sdk-trace-2.11.0.tgz", - "integrity": "sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.11.0", - "@opentelemetry/resources": "2.11.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@oxc-parser/binding-android-arm-eabi": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.150.0.tgz", - "integrity": "sha512-oQef2Zu4Prz1KLKznz3HqZzU9uVoA5PMoDZuuLmqms7hKmKSAPzlaMnLllJq3t+rgKmfJJ2siPrpZfFrW06btw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-android-arm64": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.150.0.tgz", - "integrity": "sha512-B6ofpoFiAUwIZ0MJ2IgHPvZK8FAtL4qzSZRwOkAKIfxEobE1mQC8nDdiFZj7pUaJiVUVCsfkMsBJKedzO8rZvA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-darwin-arm64": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.150.0.tgz", - "integrity": "sha512-J+9IHKzx/bSz1JetOfD4zKXSK9sOm4/a7+0qomJODcTL6JsRXGeV/ZdkAPSIDydfFmWzYCraMlQEosSZEyBYkQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-darwin-x64": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.150.0.tgz", - "integrity": "sha512-v6IPfcAcSYrBWXV5Tce1DmxDMXLhEYpIIWiRFPJopgCVscZdLaV4MRQOUxvL3usQlw+yrwYOjBFB9IwBx+jUiQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-freebsd-x64": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.150.0.tgz", - "integrity": "sha512-AoR/4jD02HET0KO0yNT4nbTE+XJUxiO9jB1X/ycEjUE3WrIJ3IjV/Vf+gskhWLcqqeXfvNnkDtBR7epllAm88A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.150.0.tgz", - "integrity": "sha512-A/hycCFjLUrCmLoL5O/vBp40ohlaXO1Ta3v5hqYZxicYFs129wZmgZJggcW4mYGYbZebQLhup+N8JjeQl8qwyw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.150.0.tgz", - "integrity": "sha512-pbqahg1Pkz7J4RKmXm30s/iQu99hv64ayXCu8P4p75HcEH5azOdR4eGqiB6lFGkFR3mMpzaYsSKLkS8oJbjmeQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-arm64-gnu": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.150.0.tgz", - "integrity": "sha512-HV11aRbBQGwqv8bEo+K/6qr88uB4fEe1mhXncMhlVCrj+WpBSraxrUzHaPVmeQRU6x6x8v/3DuCbbo93rpp+fw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-arm64-musl": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.150.0.tgz", - "integrity": "sha512-k6pVkJqALwtEuP4zukVhGRhdIy4+ofChUIUUsAHHyqDZlNsknmel3JjbggrJiWGaes6h/dIcWmEXsKW4SmK9oQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-ppc64-gnu": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.150.0.tgz", - "integrity": "sha512-tEFg39mw/rHO5n8GK2DR4ZMFfsPQZtnQIPbsIpjoQRomJc/2tRfsCSmCT6gNit+NZGoeJG5aH9ATDH5bf0WnoQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.150.0.tgz", - "integrity": "sha512-0JO7IFkoek6HqV589Menx3hJySNXi6quRhO4tq2P7kpEHKEXoDATnoPVUpn5B7gDH2KLkdo751N0uIrGJFCTCw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-riscv64-musl": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.150.0.tgz", - "integrity": "sha512-7XPzREnyAS5wHU9aB+49Uaqgoo1gVCklHc3DRlc3fJy2tXD/eAJFN1QFz/crj+Ulup5P1+axNREF+/RGaB/IRA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-s390x-gnu": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.150.0.tgz", - "integrity": "sha512-7n7ZxcbRWDFaTdyj8M8p0O9OfzoMKm8O6syBAIgcSutbOALq0Bb9G52Me+XH0anMLZV+NgXc726gqgG2q39vcQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-x64-gnu": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.150.0.tgz", - "integrity": "sha512-Vx0GSA9ZCRTUiczoEQnIIyXkMvtEY8uc6IiwLQtMe5ci2sXPqjrry0Ek5fsPP1k2kCzkML3ow9UOOEgnEDi7Bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-linux-x64-musl": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.150.0.tgz", - "integrity": "sha512-ii4/9m3viDLssMnfXU7/Pni/3nYplApuGayceX4qsVGaqqQJCx3tHIH9M/HWIeSty5i8LjS21zPYT6lVIkwLxw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-openharmony-arm64": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.150.0.tgz", - "integrity": "sha512-ZtoxX5rez36ZWkwtiEhjkCPnlTPoQ2I7lIL0IYZ1yjxMYohbvoOjBmUIZzrf9W/HouONq0omIfTeCWEY+R380w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-win32-arm64-msvc": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.150.0.tgz", - "integrity": "sha512-VqeRb5JX/bKYBrff7TUDvJyKY0914UzuCkuXIGxJS4FUmvMNfqkCbc7Sq90iMz9DlmAtlggwaBYQ9eg3h3ltiw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-win32-ia32-msvc": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.150.0.tgz", - "integrity": "sha512-EPqJfeZ4Pgg2BJSsCV8GozxV0FDltRzpVtGVa1r2noJu1iu+opOw3gtBWXwIo9odCT/MdFfyHxdy0/CRqs3OqA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-parser/binding-win32-x64-msvc": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.150.0.tgz", - "integrity": "sha512-n5YMzbqwPQqozbkrexi0lNZrUz5cnPHalYpFWe6Dau7AmKIWNo+y24IwzDuZEQtEdUHuKhXmMMih/MPjOI+CMw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.150.0.tgz", - "integrity": "sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/oxc-project" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", - "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.6.0", - "@parcel/watcher-darwin-arm64": "2.6.0", - "@parcel/watcher-darwin-x64": "2.6.0", - "@parcel/watcher-freebsd-x64": "2.6.0", - "@parcel/watcher-linux-arm-glibc": "2.6.0", - "@parcel/watcher-linux-arm-musl": "2.6.0", - "@parcel/watcher-linux-arm64-glibc": "2.6.0", - "@parcel/watcher-linux-arm64-musl": "2.6.0", - "@parcel/watcher-linux-x64-glibc": "2.6.0", - "@parcel/watcher-linux-x64-musl": "2.6.0", - "@parcel/watcher-win32-arm64": "2.6.0", - "@parcel/watcher-win32-x64": "2.6.0" - } - }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", - "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", - "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", - "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", - "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", - "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", - "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", - "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", - "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", - "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", - "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", - "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", - "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher/node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.8.tgz", - "integrity": "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.8.tgz", - "integrity": "sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.8.tgz", - "integrity": "sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.8.tgz", - "integrity": "sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.8.tgz", - "integrity": "sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.8.tgz", - "integrity": "sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.8.tgz", - "integrity": "sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.8.tgz", - "integrity": "sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.8.tgz", - "integrity": "sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.8.tgz", - "integrity": "sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.8.tgz", - "integrity": "sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.8.tgz", - "integrity": "sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.8.tgz", - "integrity": "sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.8.tgz", - "integrity": "sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.8.tgz", - "integrity": "sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@schematics/angular": { - "version": "22.2.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-22.2.2.tgz", - "integrity": "sha512-JxpXKpxdmQcRsJbriWJOhB7HeVTzz9CEsPNw6fQ0LOuPFnvtyUIXLxyFbKv/LfoFUz8wFADCtNU5sjowME5Mvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.2.2", - "@angular-devkit/schematics": "22.2.2", - "jsonc-parser": "3.3.1", - "oxc-parser": "0.150.0", - "typescript": "6.0.3" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@types/gensync": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.5.tgz", - "integrity": "sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsesc": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz", - "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz", - "integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "peerDependencies": { - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.27", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.27.tgz", - "integrity": "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/beasties": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.5.4.tgz", - "integrity": "sha512-8/lOOjT+PElYCnaUbmhgd3Uad5R1VTQ4Wg0k4rK8bX04m5WEqHNmnlLy3Q/lJ7dk25XA+72gayzc/skTfKKpcA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "css-select": "^7.0.0", - "css-what": "^8.0.0", - "dom-serializer": "^3.0.0", - "domhandler": "^6.0.0", - "htmlparser2": "^12.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.49", - "postcss-media-query-parser": "^0.2.3", - "postcss-safe-parser": "^7.0.1" - }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/boolbase": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-2.0.0.tgz", - "integrity": "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/browserslist": { - "version": "4.29.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", - "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.11.26", - "caniuse-lite": "^1.0.30001813", - "electron-to-chromium": "^1.5.439", - "node-releases": "^2.0.57", - "update-browserslist-db": "^1.3.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001814", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001814.tgz", - "integrity": "sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "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" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chardet": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", - "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", - "dev": true, - "license": "MIT" - }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", - "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-6.1.1.tgz", - "integrity": "sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^9.0.0", - "string-width": "^8.2.0" - }, - "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/colorjs.io": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.7.1.tgz", - "integrity": "sha512-LY7OHnJZxHwT5UlzNa9bbhHHDbzB6yE5+3MIPwJEQKRvSCt/T4G7epsj+9j2BExUIIfXFIJGsIXUKdfrK9Q5tA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/color" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/css-select": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-7.0.0.tgz", - "integrity": "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^2.0.0", - "css-what": "^8.0.0", - "domhandler": "^6.0.1", - "domutils": "^4.0.2", - "nth-check": "^3.0.1" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-8.0.0.tgz", - "integrity": "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-serializer": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz", - "integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0", - "entities": "^8.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-3.0.0.tgz", - "integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/domhandler": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-6.0.1.tgz", - "integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^3.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-4.0.2.tgz", - "integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^3.0.0", - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0" - }, - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.444", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.444.tgz", - "integrity": "sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/empathic": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.1.0.tgz", - "integrity": "sha512-AnfC1ATldl49/cvZdLPDjBfrRNwbDO05aibiOtzQu3qtlbJtomNLhF30HEtn/7iBz50dlMECqATo3fG0LrdEgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/entities": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", - "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20.19.0" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-string-truncated-width": "^3.0.2" - } - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", - "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-string-width": "^3.0.2" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/flru": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flru/-/flru-1.0.2.tgz", - "integrity": "sha512-kWyh8ADvHBFz6ua5xYOPnUroZTT/bwWfrCeL0Wj1dzG4/YOmOcfJ99W8dOVyyynJN35rZ9aCOtHChqQovV7yog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "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.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hosted-git-info": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz", - "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^11.1.0" - }, - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } - }, - "node_modules/htmlparser2": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz", - "integrity": "sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==", + "node_modules/browserslist": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", + "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", "dev": true, "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, { "type": "github", - "url": "https://github.com/sponsors/fb55" + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "domelementtype": "^3.0.0", - "domhandler": "^6.0.0", - "domutils": "^4.0.2", - "entities": "^8.0.0" + "baseline-browser-mapping": "^2.11.26", + "caniuse-lite": "^1.0.30001813", + "electron-to-chromium": "^1.5.439", + "node-releases": "^2.0.57", + "update-browserslist-db": "^1.3.3" }, - "engines": { - "node": ">=20.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz", - "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "proxy-agent-negotiate": "1.1.0" + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">= 20" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" } }, - "node_modules/immutable": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", - "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "node_modules/caniuse-lite": { + "version": "1.0.30001814", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001814.tgz", + "integrity": "sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" }, - "node_modules/is-extglob": { + "node_modules/clsx": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, "license": "MIT" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "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", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, - "license": "MPL-2.0", "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" + "ms": "^2.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 12.0.0" + "node": ">=6.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } + "license": "MIT" }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=8" } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], + "node_modules/electron-to-chromium": { + "version": "1.5.444", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.444.tgz", + "integrity": "sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=6" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/eslint": { + "version": "10.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.14.0.tgz", + "integrity": "sha512-T0pNsxkb9IKmtQjhpK3d7nWOpFv+YHuMbTJnSVMoQblF0onvXfErrtp4V1jHtsQPan7dKaGVD0q1WCXnzMF31A==", + "dev": true, + "license": "MIT", + "workspaces": [ + "packages/*" + ], + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.3", + "@humanfs/node": "^0.16.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "11.1.5 || >11.1.6 <12", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.6", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, "engines": { - "node": ">= 12.0.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=6.9.0" } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=6.9.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://opencollective.com/babel" } }, - "node_modules/listr2": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-11.1.0.tgz", - "integrity": "sha512-xsuczF6mWkEo/E80QHaEokQzKmTy7m80KcLRnkUt9wrcePres2w7dbQi5zOsWtDUg8Dac4gPFyu4EJ/IvKwTOg==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/generator": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.12.tgz", + "integrity": "sha512-2W76mhjrpQFO1lK5e8IvGYB2D0YZ7S2R1Z2BjO2ZUYuW+amcpK/z60U6ZZmzskwoa7sJ6XohP/Wg8H5KxXI/IA==", "dev": true, "license": "MIT", "dependencies": { - "cli-truncate": "^6.1.1", - "log-update": "^8.0.0", - "wrap-ansi": "^10.0.1" + "@babel/parser": "^7.29.12", + "@babel/types": "^7.29.11", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=22.13.0" + "node": ">=6.9.0" } }, - "node_modules/lmdb": { - "version": "3.5.6", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.6.tgz", - "integrity": "sha512-j3uE8ReKNyUWDjhfEFSJqE/1DLtfTR5Z8yFzVHvBjAk37wNg7HdScjcv8ttPHRvrdgPQMPWxFFI0SsdBzI5lBw==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, "dependencies": { - "@harperfast/extended-iterable": "^1.0.3", - "msgpackr": "^1.11.2", - "node-addon-api": "^6.1.0", - "node-gyp-build-optional-packages": "5.2.2", - "ordered-binary": "^1.5.3", - "weak-lru-cache": "^1.2.2" - }, - "bin": { - "download-lmdb-prebuilds": "bin/download-prebuilds.js" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, - "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.5.6", - "@lmdb/lmdb-darwin-x64": "3.5.6", - "@lmdb/lmdb-linux-arm": "3.5.6", - "@lmdb/lmdb-linux-arm64": "3.5.6", - "@lmdb/lmdb-linux-x64": "3.5.6", - "@lmdb/lmdb-win32-arm64": "3.5.6", - "@lmdb/lmdb-win32-x64": "3.5.6" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/log-symbols": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", - "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", - "dependencies": { - "is-unicode-supported": "^2.0.0", - "yoctocolors": "^2.1.1" - }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "node_modules/log-update": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-8.0.0.tgz", - "integrity": "sha512-lddSgOt3bPASrylL54ZSpy8nBHns+vBVSoILlVOx+dei300pnLRN958rj/EdlVLKuWlSESU3qdnDZdAI7FXYGg==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^7.3.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^9.0.0", - "string-width": "^8.2.0", - "strip-ansi": "^7.2.0", - "wrap-ansi": "^10.0.0" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { - "node": ">=22" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/lru-cache": { - "version": "11.5.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", - "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-string-parser": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.11.tgz", + "integrity": "sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": ">=6.9.0" } }, - "node_modules/magic-string": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.1.tgz", - "integrity": "sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.6.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/parser": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.12.tgz", + "integrity": "sha512-WJ7JBp/Q4+z/ImydtI7jS6NVco5++632ExBemSX+Ysb+G1lCwQ5BVo3SY+jGGOcZXI4ZccbZSUSJLNBW6eEpJg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.11" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/msgpackr": { - "version": "1.11.8", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz", - "integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", - "optional": true, - "optionalDependencies": { - "msgpackr-extract": "^3.0.2" + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/msgpackr-extract": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", - "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/traverse": { + "version": "7.29.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.12.tgz", + "integrity": "sha512-MscXe/NAZcOkYEsRajHZFt3ynsb22PUi6CTrp5U7+RYycR9By84mn9mFN54YgfITiqK4hFx3Ju3tZSyzfpS5ew==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, "dependencies": { - "node-gyp-build-optional-packages": "5.2.2" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.12", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.12", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.11", + "debug": "^4.3.1" }, - "bin": { - "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eslint-plugin-react-hooks/node_modules/@babel/types": { + "version": "7.29.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.11.tgz", + "integrity": "sha512-WCsemW40Cpc6gouC1SrY6PBaZ+oLRlEVY9XBvZBI7il/HyUrb2nJ505wE1MHEFyDZNnrWDEuy4jL50WVHfTTSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.11", + "@babel/helper-validator-identifier": "^7.29.7" }, - "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "node_modules/eslint-plugin-react-hooks/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react-hooks/node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-react-hooks/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/nanoid": { - "version": "3.3.19", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", - "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "node_modules/eslint-plugin-react-hooks/node_modules/semver": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.2.tgz", + "integrity": "sha512-GYrCADwpu6yV5OAvchkQ27Z5wwMxWAEMg5NNWjyHh/5DboFFqbdbvYNIvZouQpxXyeMPoTOh0vdPYKlf0ZswdQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "license": "ISC", "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "semver": "bin/semver.js" } }, - "node_modules/node-addon-api": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", - "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.7.tgz", + "integrity": "sha512-XhJSzLljuYD4UjNuFGJu2v7aD3sqNVK12w5/DCUfrNfHWegZo2+TsavNx8MuxMwEquuFAzNbNfXKU0WoZ+YUIg==", "dev": true, "license": "MIT", - "optional": true + "peerDependencies": { + "eslint": "^9 || ^10" + } }, - "node_modules/node-gyp-build-optional-packages": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", - "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, - "license": "MIT", - "optional": true, + "license": "BSD-2-Clause", "dependencies": { - "detect-libc": "^2.0.1" + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, - "bin": { - "node-gyp-build-optional-packages": "bin.js", - "node-gyp-build-optional-packages-optional": "optional.js", - "node-gyp-build-optional-packages-test": "build-test.js" + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/node-releases": { - "version": "2.0.57", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.57.tgz", - "integrity": "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==", + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/npm-package-arg": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz", - "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "hosted-git-info": "^10.1.0", - "proc-log": "^7.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^8.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/nth-check": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-3.0.1.tgz", - "integrity": "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "boolbase": "^2.0.0" + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" }, "engines": { - "node": ">=20.19.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "type": "github", - "url": "https://github.com/fb55/nth-check?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/obug": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", - "integrity": "sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==", + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=12.20.0" + "node": ">=0.10" } }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "mimic-function": "^5.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/ora": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.1.tgz", - "integrity": "sha512-6VlU9MLXbjVQD04AZCMX28hVtA5bUoadvUqO76MUCVA0ilwJbMiHsITRPfyVm6p/BC0Av/BXMujx39WCe1LEqw==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.6.2", - "cli-cursor": "^5.0.0", - "cli-spinners": "^3.2.0", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.1.0", - "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.2", - "string-width": "^8.1.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/ordered-binary": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", - "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "license": "MIT", - "optional": true + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" }, - "node_modules/oxc-parser": { - "version": "0.150.0", - "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.150.0.tgz", - "integrity": "sha512-zwajKw1GUa57IOdafIS7/yOObGF2NihwIfZfs5yJTRprMSkiwhWOc/k+n8bwnUPbHr2/XsjfBO8KyTPaW3VpWg==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "license": "MIT", - "dependencies": { - "@oxc-project/types": "^0.150.0" - }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/oxc-project" + "node": ">=12.0.0" }, - "optionalDependencies": { - "@oxc-parser/binding-android-arm-eabi": "0.150.0", - "@oxc-parser/binding-android-arm64": "0.150.0", - "@oxc-parser/binding-darwin-arm64": "0.150.0", - "@oxc-parser/binding-darwin-x64": "0.150.0", - "@oxc-parser/binding-freebsd-x64": "0.150.0", - "@oxc-parser/binding-linux-arm-gnueabihf": "0.150.0", - "@oxc-parser/binding-linux-arm-musleabihf": "0.150.0", - "@oxc-parser/binding-linux-arm64-gnu": "0.150.0", - "@oxc-parser/binding-linux-arm64-musl": "0.150.0", - "@oxc-parser/binding-linux-ppc64-gnu": "0.150.0", - "@oxc-parser/binding-linux-riscv64-gnu": "0.150.0", - "@oxc-parser/binding-linux-riscv64-musl": "0.150.0", - "@oxc-parser/binding-linux-s390x-gnu": "0.150.0", - "@oxc-parser/binding-linux-x64-gnu": "0.150.0", - "@oxc-parser/binding-linux-x64-musl": "0.150.0", - "@oxc-parser/binding-openharmony-arm64": "0.150.0", - "@oxc-parser/binding-win32-arm64-msvc": "0.150.0", - "@oxc-parser/binding-win32-ia32-msvc": "0.150.0", - "@oxc-parser/binding-win32-x64-msvc": "0.150.0" - } - }, - "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/parse5-html-rewriting-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.1.tgz", - "integrity": "sha512-NaRku2aMpUN1Sh1Gyk1KWUh2A7EJx2c6qYzvwsPtqhoHoaURshdrceYK3LunVCm3WHhm6FS7Vcczbvdh3/UIVw==", + "node_modules/file-entry-cache": { + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^8.0.0", - "parse5": "^8.0.0", - "parse5-sax-parser": "^8.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "flat-cache": "^6.1.23" } }, - "node_modules/parse5-sax-parser": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", - "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "parse5": "^8.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=10" }, "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "node_modules/flat-cache": { + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=10.13.0" } }, - "node_modules/piscina": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.3.2.tgz", - "integrity": "sha512-vv7l/mM7B9WgrhDaudIqv1x6v4LOBRYYmpWGdWushhpbCmVHp11sUB2v4hj1CAeTGXVxuZFz6xOU1RalAiPKfQ==", + "node_modules/globals": { + "version": "17.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.14.0.tgz", + "integrity": "sha512-UtdkTVyAJePQv0J2M9Xe4L0ruNSDV314XiIJsADI2Zf40bcdAonE/D/OhAU8AT99oij9mhLByb+NvA3QWZYgCg==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.x" + "node": ">=18" }, - "optionalDependencies": { - "@napi-rs/nice": "^1.0.4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss": { - "version": "8.5.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", - "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.18", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "hookified": "^1.15.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=20" } }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", "dev": true, "license": "MIT" }, - "node_modules/postcss-safe-parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" + "dependencies": { + "hermes-estree": "0.25.1" } }, - "node_modules/proc-log": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz", - "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==", + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", "dev": true, - "license": "ISC", - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - } + "license": "MIT" }, - "node_modules/proxy-agent-negotiate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz", - "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "kerberos": "^2.0.0" - }, - "peerDependenciesMeta": { - "kerberos": { - "optional": true - } + "node": ">= 4" } }, - "node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "node": ">=0.8.19" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/rolldown": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.8.tgz", - "integrity": "sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.149.0", - "@rolldown/pluginutils": "^1.0.0" + "bin": { + "jsesc": "bin/jsesc" }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", "bin": { - "rolldown": "bin/cli.mjs" + "json5": "lib/cli.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.8", - "@rolldown/binding-android-arm64": "1.2.8", - "@rolldown/binding-darwin-arm64": "1.2.8", - "@rolldown/binding-darwin-x64": "1.2.8", - "@rolldown/binding-freebsd-x64": "1.2.8", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.8", - "@rolldown/binding-linux-arm64-gnu": "1.2.8", - "@rolldown/binding-linux-arm64-musl": "1.2.8", - "@rolldown/binding-linux-ppc64-gnu": "1.2.8", - "@rolldown/binding-linux-s390x-gnu": "1.2.8", - "@rolldown/binding-linux-x64-gnu": "1.2.8", - "@rolldown/binding-linux-x64-musl": "1.2.8", - "@rolldown/binding-openharmony-arm64": "1.2.8", - "@rolldown/binding-win32-arm64-msvc": "1.2.8", - "@rolldown/binding-win32-x64-msvc": "1.2.8" + "node": ">=6" } }, - "node_modules/rolldown/node_modules/@oxc-project/types": { - "version": "0.149.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.149.0.tgz", - "integrity": "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==", + "node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/oxc-project" - } - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "license": "Apache-2.0", "dependencies": { - "tslib": "^2.1.0" + "@keyv/serialize": "^1.1.1" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/sass": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.104.1.tgz", - "integrity": "sha512-yDA+1aIG3EHgN4V/BvuhCvu61FF6hEd4e+9DxikUm9U0CAGuvdIZ/UYy7qbOxjhbbWQraoyLlMuzdRGOSV5Bmw==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^5.0.0", - "immutable": "^5.1.5", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">=20.19.0" - }, - "optionalDependencies": { - "@parcel/watcher": "^2.4.1" + "node": ">= 0.8.0" } }, - "node_modules/sass-embedded": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.104.1.tgz", - "integrity": "sha512-7LxbtPJ1MWKVbhzOnGx1sHTkHTcHVJ9hbgVsU29p/8gY1VeXt19fcJFr5xsx2f6zfrrR3FeOcYMt0uYDLAxpgw==", + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", "dependencies": { - "@bufbuild/protobuf": "^2.5.0", - "colorjs.io": "^0.7.0", - "immutable": "^5.1.5", - "rxjs": "^7.4.0", - "supports-color": "^8.1.1", - "sync-child-process": "^1.0.2", - "varint": "^6.0.0" - }, - "bin": { - "sass": "dist/bin/sass.js" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=20.19.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "sass-embedded-all-unknown": "1.104.1", - "sass-embedded-android-arm": "1.104.1", - "sass-embedded-android-arm64": "1.104.1", - "sass-embedded-android-riscv64": "1.104.1", - "sass-embedded-android-x64": "1.104.1", - "sass-embedded-darwin-arm64": "1.104.1", - "sass-embedded-darwin-x64": "1.104.1", - "sass-embedded-linux-arm": "1.104.1", - "sass-embedded-linux-arm64": "1.104.1", - "sass-embedded-linux-musl-arm": "1.104.1", - "sass-embedded-linux-musl-arm64": "1.104.1", - "sass-embedded-linux-musl-riscv64": "1.104.1", - "sass-embedded-linux-musl-x64": "1.104.1", - "sass-embedded-linux-riscv64": "1.104.1", - "sass-embedded-linux-x64": "1.104.1", - "sass-embedded-unknown-all": "1.104.1", - "sass-embedded-win32-arm64": "1.104.1", - "sass-embedded-win32-x64": "1.104.1" - } - }, - "node_modules/sass-embedded-all-unknown": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.104.1.tgz", - "integrity": "sha512-toyMCyUKkT6DsYlHuKZGjd8T6WltaW4TGX07F7HnF4tNJM5m/8VaVsd74zrq3QSPqGE9JjxIDK4NrNc/QY9pkA==", - "cpu": [ - "!arm", - "!arm64", - "!riscv64", - "!x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "sass": "1.104.1" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, - "node_modules/sass-embedded-android-arm": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.104.1.tgz", - "integrity": "sha512-g/XPAJYAzSSQZFP4xCdGD0HLKB4mf24cJ/+5Nls8rMool3jNkBv9+AFO4EV0b+RxN8rLcEsMccH1CR64yIFYcQ==", + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ - "arm" + "arm64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "android" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-android-arm64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.104.1.tgz", - "integrity": "sha512-yW3BVW4YFpN2vu2cVQ+Pz5JrRTvoIz36aCdo+J/Mo1A9gEN8eVPV/AL7aeZ803YdKgIitd3qw3pY4wpmT6TXNg==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "android" + "darwin" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-android-riscv64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.104.1.tgz", - "integrity": "sha512-ZYY8oMKQS7Q/6FBoC8w3T16O3MucDe3xv8iKym41Nht5uvLCGGpm4fC4OF5nlv7wQkJv8oactYddGG3Wd0Rqkg==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ - "riscv64" + "x64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "android" + "darwin" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-android-x64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.104.1.tgz", - "integrity": "sha512-5WZKC4lSfjMIjzZdQUlYQUAV+UiatBhD8w28U7cYLLj4/dMgEPOBd4g3VMv0BwpgH2JOaycMS42dXq29W2bcDg==", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "android" + "freebsd" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-darwin-arm64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.104.1.tgz", - "integrity": "sha512-oatuHzn0NsEg0d9Dcze6CuWUPvuETtMxRK4cv0eRAg7p6R0vHnv5GZRyWG6gEy3nc/ha/L+GtTasWVU82f4jrQ==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ - "arm64" + "arm" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-darwin-x64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.104.1.tgz", - "integrity": "sha512-gql/5sHGzUTVwuHfM3QLCDeb6NYwen+LLj22gz81C2NKHF/4nUtDyh4N+fURWdT7J0/EhtMOd0+FLML3sGNP7g==", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-arm": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.104.1.tgz", - "integrity": "sha512-WfmshPJOp9vUKxgp8wZ2ncaKBbyrlW9J51M2aUQHWECjMNxTULnGOHWSmD7FViXv4zwn1Co5FIFQUipW7RCxtA==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ - "arm" + "arm64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-arm64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.104.1.tgz", - "integrity": "sha512-sVWUKXNTu8sP3X95Df0xo/t49Ce5IseTIMqXHxhFBKVmx7gf7kBWNLK0wH5ym+4khc+B5nNJPgq4IxpelG8tMQ==", + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.104.1.tgz", - "integrity": "sha512-k0cQ/CxBzFVYiQEObg6CpF6CUglkdEhi/DZgZXQbwC27kbGGY+fatmIs/cFPJL2z1ulACwoAr86RQUFzYvw5eg==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ - "arm" + "x64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.104.1.tgz", - "integrity": "sha512-H7b+LzZ/w8pwNExInM8HDHraqvxCMdUc5ZRGU/aSJJhZ9HjeRKBjF3GxaisVHnx7o18j1l4VQ5cLBL9tTmNzZw==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.104.1.tgz", - "integrity": "sha512-9DYdn4wfrkidjxJVtEd2iCx8HKdZe+uF82GDmrYEZhgu4NjVE6a4fQyW7OLwzn3erZMHKBaObBOH1d37DnXI1A==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ - "riscv64" + "x64" ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">=14.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.104.1.tgz", - "integrity": "sha512-5xz+nAr01b6yaRdrGVgE7lNvm1lGFjwNdUvnz+teidvHCbD5oTcbhrRVrnDoLHHvq5n3Jve9TzWaaHhezaEfHA==", - "cpu": [ - "x64" - ], + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "p-locate": "^5.0.0" + }, "engines": { - "node": ">=14.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sass-embedded-linux-riscv64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.104.1.tgz", - "integrity": "sha512-oWryPJWTXK5adtlz/FD7wd2kS4I0CEgp6mWLUVb4oMFURMLz9bA9fO87D7lc4SV++lds7T51PU1kykCbOvNHMg==", - "cpu": [ - "riscv64" - ], + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.57", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.57.tgz", + "integrity": "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/sass-embedded-linux-x64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.104.1.tgz", - "integrity": "sha512-j/sX/yKTx/wJKepC5/ISlR6kPeSuHKThf76D2za5i2VnbHg0MN19jQq3WMorowR3kRghqt6azs3awogG+e7IRA==", - "cpu": [ - "x64" - ], + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, "engines": { - "node": ">=14.0.0" + "node": ">= 0.8.0" } }, - "node_modules/sass-embedded-unknown-all": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.104.1.tgz", - "integrity": "sha512-RaMsYZB5mRioL4qhoI7T5mmNb2OunakbPTJW2cuu3MeIULnGoxo7Wd5QKFxeQvF7sSQL57RuaQ+q9pH+/pQ9Fg==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "!android", - "!darwin", - "!linux", - "!win32" - ], "dependencies": { - "sass": "1.104.1" + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sass-embedded-win32-arm64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.104.1.tgz", - "integrity": "sha512-fS6DL7lcnTPclqGLF4xRt8egZlFY9cU23d57ufbWqaUbCFu9JTu0+8qB4jMxfx1la6byi3GoSTfbnNOLfWv8sw==", - "cpu": [ - "arm64" - ], + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "p-limit": "^3.0.2" + }, "engines": { - "node": ">=14.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sass-embedded-win32-x64": { - "version": "1.104.1", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.104.1.tgz", - "integrity": "sha512-/c4N2A93Ckms6DuRFVftKYISuI1tyC8gmlVJ8WaWFzgCBN/Swq2rARJIBUNeuxlmxjmYXfd3+2f/u887K63wbA==", - "cpu": [ - "x64" - ], + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=14.0.0" + "node": ">=8" } }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "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", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/slice-ansi": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-9.0.1.tgz", - "integrity": "sha512-aBY19bn/XA+hKOKX0qL7Z0UfdBsbQvc9hn993U8ALUjzxCvDcuZqLoRXjGJrUARWAlwMnsRVD9sw2AFNOYvalA==", + "node_modules/postcss": { + "version": "8.5.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.32.tgz", + "integrity": "sha512-LJlKCCAUFKOuZxipUdYw1NzIITEsPcgyOG9LkvRJvuKj/bRzbuRY0ARXvL0pWGpsZvn8jku+LMep2eU0seHp8g==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.3", - "is-fullwidth-code-point": "^5.1.0" + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" }, "engines": { - "node": ">=22" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "node": "^10 || ^12 || >=14" } }, - "node_modules/source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0.tgz", - "integrity": "sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">= 0.8.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", "dev": true, "license": "MIT", "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" } }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "node_modules/react": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/stdin-discarder": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", - "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "node_modules/react-aria": { + "version": "3.53.1", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.53.1.tgz", + "integrity": "sha512-dikisyOjJd3D2fFrIDWmVWzqiLz5B86GzZv1zxs7xI4dVc0JIz/1Wa52I20gYvVL2WXeFXlygYsle/QcOMhtcg==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.4", + "@internationalized/number": "^3.6.9", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.37.0", + "@swc/helpers": "^0.5.0", + "aria-hidden": "^1.2.3", + "clsx": "^2.0.0", + "react-stately": "3.51.0", + "use-sync-external-store": "^1.6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "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/string-width": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz", - "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==", - "dev": true, + "node_modules/react-aria-components": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.22.1.tgz", + "integrity": "sha512-UTHaYHOaM71bOCjGPF50DcLywlrwAodE63IP64LB4kO+OizatQEL8TesVEOM8+TkBeSgHoflJ45388IlJfa7aw==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.4", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.37.0", + "@swc/helpers": "^0.5.0", + "client-only": "^0.0.1", + "react-aria": "3.53.1", + "react-stately": "3.51.0", + "use-sync-external-store": "^1.6.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-dom": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.1.tgz", + "integrity": "sha512-Y0bARz53lhEC1NMCASs0/j+faB/zqt3R8hpvg1e8+61ZVJ4UL0UdC4cBbXfZMcIuhrfgeILTLe+ZeBCavQPtKQ==", "license": "MIT", "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" + "scheduler": "^0.28.0" }, - "engines": { - "node": ">=20" + "peerDependencies": { + "react": "^19.3.1" + } + }, + "node_modules/react-stately": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.51.0.tgz", + "integrity": "sha512-YJcmkAXu2XOQP97hO/qz/cC3qv9kni3oVhwBlxWr358BHePJUpY15XwL3YSRMKxYt4EkslPqAz11JRirMfANGw==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.4", + "@internationalized/number": "^3.6.9", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.37.0", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/rolldown": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz", + "integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "@oxc-project/types": "=0.155.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.15", + "@rolldown/binding-android-arm64": "1.2.15", + "@rolldown/binding-darwin-arm64": "1.2.15", + "@rolldown/binding-darwin-x64": "1.2.15", + "@rolldown/binding-freebsd-x64": "1.2.15", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.15", + "@rolldown/binding-linux-arm64-gnu": "1.2.15", + "@rolldown/binding-linux-arm64-musl": "1.2.15", + "@rolldown/binding-linux-ppc64-gnu": "1.2.15", + "@rolldown/binding-linux-s390x-gnu": "1.2.15", + "@rolldown/binding-linux-x64-gnu": "1.2.15", + "@rolldown/binding-linux-x64-musl": "1.2.15", + "@rolldown/binding-openharmony-arm64": "1.2.15", + "@rolldown/binding-win32-arm64-msvc": "1.2.15", + "@rolldown/binding-win32-x64-msvc": "1.2.15" } }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.155.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz", + "integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/sync-child-process": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", - "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { - "sync-message-port": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=8" } }, - "node_modules/sync-message-port": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", - "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, "node_modules/tinyglobby": { @@ -5608,12 +2994,38 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.9.1.tgz", + "integrity": "sha512-a4Ux9VKuIMHsOS7ENbEq6hK2ZGYIT27Rtl0E4eD9KqwxhKiQeMZE/9xb3IdYwWaSOyIBQLExhQgXDTYoiCxnWA==", "license": "0BSD" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/typescript": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", @@ -5628,6 +3040,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.72.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.72.1.tgz", + "integrity": "sha512-3Li9FfPmQp45nxEtFD1ZCrYFI3cYK5kpyNtmm1H7lMagm8u9sy6PTjy3ytwQZs7KNukOyKFHAZ6z6GjYFeaeXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.72.1", + "@typescript-eslint/parser": "8.72.1", + "@typescript-eslint/typescript-estree": "8.72.1", + "@typescript-eslint/utils": "8.72.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/ua-parser-js": { "version": "1.0.41", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", @@ -5654,6 +3090,13 @@ "node": "*" } }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", @@ -5685,47 +3128,36 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/validate-npm-package-name": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz", - "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "ISC", - "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/varint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", - "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "dev": true, - "license": "MIT" - }, - "node_modules/verkit": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.3.2.tgz", - "integrity": "sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==", - "dev": true, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", + "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", "license": "MIT", - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/vite": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", - "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.5.tgz", + "integrity": "sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.33.0", "picomatch": "^4.0.7", - "postcss": "^8.5.28", - "rolldown": "~1.2.6", + "postcss": "^8.5.30", + "rolldown": "~1.2.14", "tinyglobby": "^0.2.17" }, "bin": { @@ -5742,7 +3174,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.7.1", + "@vitejs/devtools": "^0.7.1 || ^0.8.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -5793,109 +3225,79 @@ } } }, - "node_modules/weak-lru-cache": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", - "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/web-vitals": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-6.2.2.tgz", "integrity": "sha512-oto5x6dLEgrRqfcWed+pZEUb2q6ikbFmqF54CRDhI/QGbn+qxC49b4C4OkbH+kb9C3a8shpFD3SgR9kRcs80ZQ==", "license": "Apache-2.0" }, - "node_modules/wrap-ansi": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.2.tgz", - "integrity": "sha512-6OLRNZqRntVGBm26ghZ5eZhCuWWyOkRCSn8XsOIuq5stpCE/tjLbdozd93naILZig0lmD8ANfRwnhn0DLeXGlg==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-styles": "^6.2.3", - "string-width": "^8.2.0" + "isexe": "^2.0.0" }, - "engines": { - "node": ">=20" + "bin": { + "node-which": "bin/node-which" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/xxhash-wasm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", - "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", - "dev": true, - "license": "MIT" - }, - "node_modules/y18n": { - "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" + "node": ">= 8" } }, - "node_modules/yargs": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz", - "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^8.2.1", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" + "node": ">=0.10.0" } }, - "node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } + "license": "ISC" }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.6.tgz", + "integrity": "sha512-4UmzQUF5fxvfcYHlbjBmejU+w+hbDnWFx4aS8kBx7nPBHcO2SqPbpAG8snbdg+Xse4pRefR98hgjFgIMCI/UhA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/zone.js": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.16.3.tgz", - "integrity": "sha512-ihXL9+vhYyEhXz4TDNpHeAOZN9FVrbog0Il64OIEI28UP/n5AaI6gsccRuOHBfx+206agzyoK527bYIO0Foy6A==", - "license": "MIT" + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } } } } diff --git a/client/package.json b/client/package.json index 0b4787b..b37d11e 100644 --- a/client/package.json +++ b/client/package.json @@ -1,32 +1,36 @@ { "name": "skeleton-client", - "version": "0.0.0", + "version": "0.1.0", + "private": true, + "type": "module", + "engines": { "node": ">=24" }, "scripts": { - "ng": "ng", - "start": "ng serve --port 4250", - "build": "ng build", - "watch": "ng build --watch --configuration development" + "start": "vite --host 127.0.0.1 --port 4250", + "build": "tsc -b && vite build", + "lint": "eslint . --max-warnings 0", + "preview": "vite preview --host 127.0.0.1 --port 4250" }, - "private": true, "dependencies": { - "@angular/cdk": "22.2.2", - "@angular/common": "22.2.2", - "@angular/compiler": "22.2.2", - "@angular/core": "22.2.2", - "@angular/forms": "22.2.2", - "@angular/material": "22.2.2", - "@angular/platform-browser": "22.2.2", - "@angular/router": "22.2.2", - "@grafana/faro-web-sdk": "^2.7.0", - "@mucsi96/angular-material-theme": "^1.12.0", - "rxjs": "7.8.2", - "tslib": "2.8.1", - "zone.js": "0.16.3" + "@fontsource/roboto": "5.3.0", + "@grafana/faro-web-sdk": "^2.13.0", + "@mucsi96/react-ui": "^0.2.0", + "@tanstack/react-query": "^5.104.1", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "zod": "^4.6.5" }, "devDependencies": { - "@angular/build": "22.2.2", - "@angular/cli": "22.2.2", - "@angular/compiler-cli": "22.2.2", - "typescript": "6.0.3" + "@eslint/js": "^10.0.1", + "@types/node": "^26.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@vitejs/plugin-react": "^6.1.2", + "eslint": "^10.12.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.7", + "globals": "^17.0.0", + "typescript": "~6.0.3", + "typescript-eslint": "^8.71.1", + "vite": "^8.3.4" } } diff --git a/client/proxy.conf.json b/client/proxy.conf.json deleted file mode 100644 index 7c96427..0000000 --- a/client/proxy.conf.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "/api": { - "target": "http://localhost:8053", - "secure": false - } -} diff --git a/client/src/App.module.css b/client/src/App.module.css new file mode 100644 index 0000000..3c0e089 --- /dev/null +++ b/client/src/App.module.css @@ -0,0 +1,9 @@ +.main { + max-width: 1200px; + margin: 3rem auto; + padding: 0 2rem; +} + +@media (max-width: 600px) { + .main { padding: 0 1rem; } +} diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 0000000..e29cb3b --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,10 @@ +import { Suspense, lazy } from 'react'; +import { Header } from './Header'; +import { LoadingGreeting } from './LoadingGreeting'; +import styles from './App.module.css'; + +const Home = lazy(() => import('./Home')); + +export function App() { + return <>
}>
; +} diff --git a/client/src/Header.module.css b/client/src/Header.module.css new file mode 100644 index 0000000..c200fa2 --- /dev/null +++ b/client/src/Header.module.css @@ -0,0 +1,46 @@ +.topbar { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 72px; + padding: 1rem 2rem; + border-bottom: 1px solid var(--bt-outline); +} + +.topbar a { + color: inherit; + font-size: 1.3rem; + text-decoration: none; + font-weight: 700; +} + +.profile { position: relative; } + +.profile summary { + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + width: 40px; + height: 40px; + background: var(--bt-surface-2); + cursor: pointer; + list-style: none; +} + +.profile summary::-webkit-details-marker { display: none; } + +.profileName { + position: absolute; + right: 0; + top: 48px; + min-width: 160px; + padding: 1rem; + background: var(--bt-surface-1); + border: 1px solid var(--bt-outline); + border-radius: 8px; +} + +@media (max-width: 600px) { + .topbar { padding: 1rem; } +} diff --git a/client/src/Header.tsx b/client/src/Header.tsx new file mode 100644 index 0000000..8198965 --- /dev/null +++ b/client/src/Header.tsx @@ -0,0 +1,16 @@ +import { useQuery } from '@tanstack/react-query'; +import { fetchJson, userInfoSchema } from './api'; +import styles from './Header.module.css'; + +export function Header() { + const { data } = useQuery({ queryKey: ['profile'], queryFn: ({ signal }) => fetchJson('/oauth2/userinfo', userInfoSchema, { signal }) }); + const name = (data?.additionalClaims?.name ?? data?.preferredUsername ?? data?.email)?.trim(); + const initials = name?.split(/\s+/).map(part => part[0]).join('').toUpperCase(); + return
+ Skeleton App + {name &&
+ {initials} +
{name}
+
} +
; +} diff --git a/client/src/Home.module.css b/client/src/Home.module.css new file mode 100644 index 0000000..520a695 --- /dev/null +++ b/client/src/Home.module.css @@ -0,0 +1,4 @@ +.greeting { + margin-top: 2rem; + padding: 1.5rem; +} diff --git a/client/src/Home.tsx b/client/src/Home.tsx new file mode 100644 index 0000000..a24d179 --- /dev/null +++ b/client/src/Home.tsx @@ -0,0 +1,20 @@ +import { useQuery } from '@tanstack/react-query'; +import { Alert, Button, Card, Heading, Text } from '@mucsi96/react-ui'; +import { fetchJson, greetingSchema } from './api'; +import { LoadingGreeting } from './LoadingGreeting'; +import styles from './Home.module.css'; + +export default function Home() { + const { data, error, isPending, refetch } = useQuery({ + queryKey: ['greeting'], queryFn: ({ signal }) => fetchJson('/api/greeting', greetingSchema, { signal }), + }); + if (isPending) return ; + if (error) return + Unable to load greeting. + ; + return <> + Welcome, {data.name} + {data.message} + {data.aiGreeting} + ; +} diff --git a/client/src/LoadingGreeting.module.css b/client/src/LoadingGreeting.module.css new file mode 100644 index 0000000..504d79d --- /dev/null +++ b/client/src/LoadingGreeting.module.css @@ -0,0 +1,29 @@ +.skeleton { + display: grid; + gap: 1rem; +} + +.line, .card { + display: block; + background: var(--bt-surface-2); + border-radius: 8px; + animation: pulse 1.5s ease-in-out infinite; +} + +.line { + height: 2rem; + max-width: 50%; +} + +.card { + height: 7rem; + margin-top: 1rem; +} + +@keyframes pulse { + 50% { opacity: .45; } +} + +@media (prefers-reduced-motion: reduce) { + .line, .card { animation: none; } +} diff --git a/client/src/LoadingGreeting.tsx b/client/src/LoadingGreeting.tsx new file mode 100644 index 0000000..eb99c9f --- /dev/null +++ b/client/src/LoadingGreeting.tsx @@ -0,0 +1,7 @@ +import styles from './LoadingGreeting.module.css'; + +export function LoadingGreeting() { + return
+ +
; +} diff --git a/client/src/api.ts b/client/src/api.ts new file mode 100644 index 0000000..9239cde --- /dev/null +++ b/client/src/api.ts @@ -0,0 +1,27 @@ +import { z } from 'zod'; + +export const greetingSchema = z.object({ name: z.string(), message: z.string(), aiGreeting: z.string() }); +export const userInfoSchema = z.object({ + email: z.string(), + preferredUsername: z.string().optional(), + additionalClaims: z.object({ name: z.string().optional() }).optional(), +}); + +// OAuth credentials stay at the gateway. Only same-origin unsafe requests carry +// the readable CSRF proof, matching the API's host-only double-submit cookie. +export async function fetchJson(path: string, schema: z.ZodType, init: RequestInit = {}): Promise { + const url = new URL(path, window.location.origin); + if (url.origin !== window.location.origin) throw new Error('API requests must be same-origin'); + const headers = new Headers(init.headers); + headers.set('Accept', 'application/json'); + headers.set('X-Timezone', Intl.DateTimeFormat().resolvedOptions().timeZone); + if (!['GET', 'HEAD', 'OPTIONS', 'TRACE'].includes((init.method ?? 'GET').toUpperCase())) { + const token = document.cookie.split(';').map(value => value.trim()) + .find(value => value.startsWith('__Host-XSRF-TOKEN='))?.split('=')[1]; + if (!token) throw new Error('Missing CSRF token'); + headers.set('X-XSRF-TOKEN', decodeURIComponent(token)); + } + const response = await fetch(url, { ...init, headers, credentials: 'same-origin' }); + if (!response.ok) throw new Error(`Request failed (${response.status})`); + return schema.parse(await response.json()); +} diff --git a/client/src/app/app.component.css b/client/src/app/app.component.css deleted file mode 100644 index 109eb22..0000000 --- a/client/src/app/app.component.css +++ /dev/null @@ -1,36 +0,0 @@ -.header { - border-bottom: 1px solid var(--bt-outline); - display: block; - /* Let the toolbar grow by the status-bar inset instead of letting the - padding eat into Material's fixed toolbar height (which crushes the - content under the iOS status bar in standalone PWA mode). */ - height: auto; - padding: env(safe-area-inset-top) 0 0; - - nav { - padding: 0 max(1rem, env(safe-area-inset-right)) 0 max(1rem, env(safe-area-inset-left)); - max-width: 90rem; - margin: 0 auto; - display: flex; - justify-content: space-between; - align-items: center; - min-height: var(--mat-toolbar-standard-height, 64px); - - a[mat-button] { - font-size: 16px; - } - } -} - -.header-right { - display: flex; - align-items: center; - gap: 1rem; -} - -main { - display: block; - padding: 1px max(1rem, env(safe-area-inset-right)) env(safe-area-inset-bottom) max(1rem, env(safe-area-inset-left)); - max-width: 90rem; - margin: 50px auto 0; -} diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html deleted file mode 100644 index 6ecfb55..0000000 --- a/client/src/app/app.component.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - -
- -
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts deleted file mode 100644 index 5185854..0000000 --- a/client/src/app/app.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatToolbarModule } from '@angular/material/toolbar'; -import { RouterOutlet } from '@angular/router'; -import { HeaderComponent } from './header/header.component'; - -@Component({ - selector: 'app-root', - imports: [ - RouterOutlet, - MatToolbarModule, - MatButtonModule, - HeaderComponent, - ], - templateUrl: './app.component.html', - styleUrl: './app.component.css', -}) -export class AppComponent {} diff --git a/client/src/app/app.config.ts b/client/src/app/app.config.ts deleted file mode 100644 index 8eecf07..0000000 --- a/client/src/app/app.config.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - ApplicationConfig, - provideZoneChangeDetection, -} from '@angular/core'; -import { provideRouter } from '@angular/router'; - -import { - provideHttpClient, - withInterceptors, - withXsrfConfiguration, -} from '@angular/common/http'; -import { - MAT_RIPPLE_GLOBAL_OPTIONS, - RippleGlobalOptions, -} from '@angular/material/core'; -import { provideAngularMaterialTheme } from '@mucsi96/angular-material-theme'; -import { routes } from './app.routes'; -import { errorInterceptor } from './utils/error.interceptor'; -import { timezoneInterceptor } from './utils/timezone.interceptor'; - -const globalRippleConfig: RippleGlobalOptions = { - disabled: true, -}; - -export const appConfig: ApplicationConfig = { - providers: [ - provideZoneChangeDetection({ eventCoalescing: true }), - provideRouter(routes), - provideHttpClient( - withXsrfConfiguration({ cookieName: '__Host-XSRF-TOKEN' }), - withInterceptors([ - errorInterceptor, - timezoneInterceptor, - ]) - ), - { provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: globalRippleConfig }, - provideAngularMaterialTheme(), - ], -}; diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts deleted file mode 100644 index fcb2fad..0000000 --- a/client/src/app/app.routes.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Routes } from '@angular/router'; - -export const routes: Routes = [ - { - path: '', - pathMatch: 'full', - loadComponent: () => - import('./home/home.component').then((m) => m.HomeComponent), - title: 'Hello', - }, -]; diff --git a/client/src/app/greeting.service.ts b/client/src/app/greeting.service.ts deleted file mode 100644 index 206bb39..0000000 --- a/client/src/app/greeting.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable, inject, resource } from '@angular/core'; -import { fetchJson } from './utils/fetchJson'; - -export interface GreetingResponse { - name: string; - message: string; - aiGreeting: string; -} - -@Injectable({ - providedIn: 'root', -}) -export class GreetingService { - private readonly http = inject(HttpClient); - - greeting = resource({ - loader: () => - fetchJson(this.http, '/api/greeting'), - }); -} diff --git a/client/src/app/header/header.component.css b/client/src/app/header/header.component.css deleted file mode 100644 index 325a38a..0000000 --- a/client/src/app/header/header.component.css +++ /dev/null @@ -1,27 +0,0 @@ -.avatar { - display: inline-flex; - user-select: none; - background-color: var(--bt-outline); - border-radius: 50%; - height: 40px; - justify-content: center; - align-items: center; - aspect-ratio: 1; - color: var(--bt-text-on-brand); - font-size: 18px; - border: unset; -} - -.profile-menu { - margin: 10px; -} - -.profile-name { - display: flex; - justify-content: flex-start; - align-items: center; - padding-left: var(--mat-menu-item-leading-spacing); - padding-right: var(--mat-menu-item-trailing-spacing); - min-height: 36px; - color: var(--bt-text-default); -} diff --git a/client/src/app/header/header.component.html b/client/src/app/header/header.component.html deleted file mode 100644 index 7ba1328..0000000 --- a/client/src/app/header/header.component.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - {{ profile()?.name }} - - diff --git a/client/src/app/header/header.component.ts b/client/src/app/header/header.component.ts deleted file mode 100644 index 3903fc7..0000000 --- a/client/src/app/header/header.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Component, inject } from '@angular/core'; -import { UserProfileService } from '../user-profile.service'; -import { MatMenuModule } from '@angular/material/menu'; - -@Component({ - selector: 'app-header', - imports: [ - MatMenuModule, - ], - templateUrl: './header.component.html', - styleUrl: './header.component.css', -}) -export class HeaderComponent { - profile = inject(UserProfileService).profile; -} diff --git a/client/src/app/home/home.component.css b/client/src/app/home/home.component.css deleted file mode 100644 index 94f17a8..0000000 --- a/client/src/app/home/home.component.css +++ /dev/null @@ -1,34 +0,0 @@ -:host { - display: block; - max-width: 1200px; - margin: 0 auto; - padding: 0 2rem; -} - -h1 { - color: var(--bt-text-strong); - margin-bottom: 0.5rem; -} - -p { - color: var(--bt-text-muted); - margin-bottom: 2rem; -} - -mat-card { - background: var(--bt-surface-1); - border: 1px solid var(--bt-outline); -} - -.ai-greeting { - color: var(--bt-text-default); - font-size: 1.1rem; - line-height: 1.6; - margin: 0; -} - -.page-loading { - display: flex; - justify-content: center; - margin: 150px auto; -} diff --git a/client/src/app/home/home.component.html b/client/src/app/home/home.component.html deleted file mode 100644 index 9fb58c7..0000000 --- a/client/src/app/home/home.component.html +++ /dev/null @@ -1,11 +0,0 @@ -@if (greeting.isLoading()) { - -} @else { -

Welcome, {{ greeting.value()?.name }}

-

{{ greeting.value()?.message }}

- - -

{{ greeting.value()?.aiGreeting }}

-
-
-} diff --git a/client/src/app/home/home.component.ts b/client/src/app/home/home.component.ts deleted file mode 100644 index 645f689..0000000 --- a/client/src/app/home/home.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Component, inject } from '@angular/core'; -import { MatCardModule } from '@angular/material/card'; -import { BarLoaderComponent } from '@mucsi96/angular-material-theme'; -import { GreetingService } from '../greeting.service'; - -@Component({ - selector: 'app-home', - standalone: true, - imports: [ - BarLoaderComponent, - MatCardModule, - ], - templateUrl: './home.component.html', - styleUrl: './home.component.css', -}) -export class HomeComponent { - private readonly greetingService = inject(GreetingService); - readonly greeting = this.greetingService.greeting; -} diff --git a/client/src/app/runtime-config.ts b/client/src/app/runtime-config.ts deleted file mode 100644 index 254a17c..0000000 --- a/client/src/app/runtime-config.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface RuntimeConfig { - clientLogUrl: string; - clientAppName: string; -} - -declare global { - interface Window { - __APP_CONFIG__?: RuntimeConfig; - } -} diff --git a/client/src/app/user-profile.service.ts b/client/src/app/user-profile.service.ts deleted file mode 100644 index 082c967..0000000 --- a/client/src/app/user-profile.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { httpResource } from '@angular/common/http'; -import { computed, Injectable } from '@angular/core'; - -interface UserInfo { - email: string; - preferredUsername?: string; - additionalClaims?: { name?: string }; -} - -@Injectable({ providedIn: 'root' }) -export class UserProfileService { - private readonly userInfo = httpResource(() => '/oauth2/userinfo'); - - readonly profile = computed(() => { - if (!this.userInfo.hasValue()) return undefined; - const user = this.userInfo.value(); - const name = (user.additionalClaims?.name ?? user.preferredUsername ?? user.email).trim(); - return name ? { - name, - initials: name.split(/\s+/).map(part => part[0]).join('').toUpperCase(), - } : undefined; - }); -} diff --git a/client/src/app/utils/error.interceptor.ts b/client/src/app/utils/error.interceptor.ts deleted file mode 100644 index bb5f776..0000000 --- a/client/src/app/utils/error.interceptor.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'; -import { inject } from '@angular/core'; -import { NotificationsService } from '@mucsi96/angular-material-theme'; -import { catchError } from 'rxjs'; - -export const errorInterceptor: HttpInterceptorFn = (req, next) => { - const notifications = inject(NotificationsService); - return next(req).pipe( - catchError((error) => { - if (!(error instanceof HttpErrorResponse && error.status === 401)) notifications.error('An error occurred. ' + error.message); - return Promise.reject(error); - }) - ); -}; diff --git a/client/src/app/utils/faro.ts b/client/src/app/utils/faro.ts deleted file mode 100644 index e95b614..0000000 --- a/client/src/app/utils/faro.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { faro, initializeFaro, LogLevel } from '@grafana/faro-web-sdk'; - -// Network sends currently in flight. Populated by wrapping each transport's -// `send` (FetchTransport resolves its promise when the POST settles), so -// flushFaro() can await actual delivery before a redirect navigates away. -const inFlightSends = new Set>(); - -// Mirrors Faro's DEFAULT_SEND_TIMEOUT_MS - the batch interval we keep. -const FARO_BATCH_INTERVAL_MS = 250; - -export function initFaro(clientLogUrl: string, clientAppName: string): void { - if (!clientLogUrl) { - return; - } - - initializeFaro({ - url: clientLogUrl, - app: { - name: clientAppName, - version: '1.0.0', - }, - // Faro filters out console.log/debug/trace by default; capture every level - // so the auth/token-renewal traces and any third-party console output land - // in the backend logs. - consoleInstrumentation: { - disabledLevels: [], - }, - // Keep Faro's default 250 ms batching. Before a full-page redirect we call - // flushFaro(), which drains the queue and awaits the network sends, so we - // no longer need to collapse the batch timer to catch that window. - }); - - trackTransportSends(); - installFlushOnHide(); -} - -/** - * Wraps each transport's `send` so the promise it returns is tracked. Faro's - * batch layer calls `send` fire-and-forget and discards the promise; capturing - * it here is what lets flushFaro() await real delivery. - */ -function trackTransportSends(): void { - faro?.transports?.transports.forEach((transport) => { - const originalSend = transport.send.bind(transport); - transport.send = (items) => { - const result = originalSend(items); - if (result && typeof (result as Promise).then === 'function') { - const promise = result as Promise; - inFlightSends.add(promise); - promise.finally(() => inFlightSends.delete(promise)); - } - return result; - }; - }); -} - -/** - * Awaits delivery of all pending Faro logs, then resolves. Call this before a - * full-page redirect (signinRedirect/signoutRedirect) so the pre-redirect trace - * reaches the backend instead of being lost when the page navigates away. - * - * Faro 2.x exposes no public flush, so we push a marker, let the 250 ms batch - * interval dispatch the buffered logs (waiting for the resulting network send), - * then await every tracked send. Bounded by maxWaitMs so the redirect never - * hangs if the backend is slow or unreachable. - */ -export async function flushFaro(maxWaitMs = 1500): Promise { - if (!faro) { - return; - } - - faro.api.pushLog(['[faro] flush before redirect'], { level: LogLevel.INFO }); - - const deadline = Date.now() + maxWaitMs; - - // 1. Wait for the batch interval to turn the buffered logs into a network - // send. The buffer is non-empty (we just pushed), so a flush is due within - // one interval. - while (inFlightSends.size === 0 && Date.now() < deadline) { - await delay(Math.min(30, FARO_BATCH_INTERVAL_MS)); - } - - // 2. Drain all network sends; later batches may enqueue more as we wait. - while (inFlightSends.size > 0 && Date.now() < deadline) { - await Promise.allSettled([...inFlightSends]); - await delay(0); - } -} - -function delay(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -/** - * Belt-and-suspenders flush on page lifecycle transitions. Faro's batch - * executor already flushes on visibilitychange=hidden internally; this just - * adds a marker log showing whether the hide hook fired before a navigation. - */ -function installFlushOnHide(): void { - const flush = (reason: 'pagehide' | 'visibilitychange'): void => { - faro?.api?.pushLog([`[faro] flush on ${reason}`], { level: LogLevel.INFO }); - }; - - window.addEventListener('pagehide', () => flush('pagehide')); - document.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'hidden') { - flush('visibilitychange'); - } - }); -} diff --git a/client/src/app/utils/fetchJson.ts b/client/src/app/utils/fetchJson.ts deleted file mode 100644 index e7d2b04..0000000 --- a/client/src/app/utils/fetchJson.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { firstValueFrom } from 'rxjs'; - -export async function fetchJson( - http: HttpClient, - url: string, - options: { body?: any; method?: string; headers?: Record } = {} -) { - const { body, method = 'get', headers: extraHeaders = {} } = options; - const response = await firstValueFrom( - http.request(method, url, { - headers: new HttpHeaders({ - 'Content-Type': 'application/json', - Accept: 'application/json', - ...extraHeaders, - }), - body, - responseType: 'json', - }) - ); - return response as T; -} diff --git a/client/src/app/utils/timezone.interceptor.ts b/client/src/app/utils/timezone.interceptor.ts deleted file mode 100644 index 3e3acb6..0000000 --- a/client/src/app/utils/timezone.interceptor.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { HttpInterceptorFn } from '@angular/common/http'; - -export const timezoneInterceptor: HttpInterceptorFn = (req, next) => { - const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone; - return next(req.clone({ setHeaders: { 'X-Timezone': timezone } })); -}; diff --git a/client/src/main.ts b/client/src/main.ts deleted file mode 100644 index e66afde..0000000 --- a/client/src/main.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app/app.config'; -import { AppComponent } from './app/app.component'; -import type { RuntimeConfig } from './app/runtime-config'; -import { initFaro } from './app/utils/faro'; - -const config: RuntimeConfig | undefined = window.__APP_CONFIG__; -if (!config || typeof config.clientLogUrl !== 'string' || typeof config.clientAppName !== 'string') { - throw new Error('Missing frontend runtime configuration in index.html'); -} - -initFaro(config.clientLogUrl, config.clientAppName); -bootstrapApplication(AppComponent, appConfig) - .catch(error => console.error('[boot] Angular bootstrap failed', error)); diff --git a/client/src/main.tsx b/client/src/main.tsx new file mode 100644 index 0000000..a6f176d --- /dev/null +++ b/client/src/main.tsx @@ -0,0 +1,25 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { initializeFaro } from '@grafana/faro-web-sdk'; +import '@mucsi96/react-ui/styles.css'; +import '@fontsource/roboto/400.css'; +import '@fontsource/roboto/700.css'; +import './styles.css'; +import { App } from './App'; + +const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, refetchOnWindowFocus: false } } }); + +initializeFaro({ + url: new URL('/_telemetry/collect', window.location.origin).href, + app: { name: 'hello-client', version: '1.0.0' }, + consoleInstrumentation: { disabledLevels: [] }, +}); + +createRoot(document.getElementById('root')!).render( + + + + + , +); diff --git a/client/src/styles.css b/client/src/styles.css new file mode 100644 index 0000000..1985878 --- /dev/null +++ b/client/src/styles.css @@ -0,0 +1,3 @@ +:root { --bt-font: Roboto, sans-serif; color-scheme: dark; font-family: var(--bt-font); background: var(--bt-surface-0); color: var(--bt-text-default); } +* { box-sizing: border-box; } +body { margin: 0; } diff --git a/client/src/styles.scss b/client/src/styles.scss deleted file mode 100644 index 51251cc..0000000 --- a/client/src/styles.scss +++ /dev/null @@ -1,14 +0,0 @@ -@use '@mucsi96/angular-material-theme/styles' as bt; - -html, -body { - height: 100%; -} - -html { - @include bt.theme(); -} - -body { - margin: 0; -} diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json index 7d7c716..5bb4902 100644 --- a/client/tsconfig.app.json +++ b/client/tsconfig.app.json @@ -1,13 +1,20 @@ { - "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] + "target": "ES2023", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.cache/tsconfig.app.tsbuildinfo", + "strict": true, + "skipLibCheck": true, + "verbatimModuleSyntax": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "erasableSyntaxOnly": true, + "types": ["vite/client"] }, - "files": [ - "src/main.ts" - ], - "include": [ - "src/**/*.d.ts" - ] + "include": ["src"] } diff --git a/client/tsconfig.json b/client/tsconfig.json index 41897a8..d32ff68 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,30 +1,4 @@ { - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist/out-tsc", - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "esModuleInterop": true, - "sourceMap": true, - "declaration": false, - "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", - "lib": [ - "ES2022", - "dom" - ] - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] } diff --git a/client/tsconfig.node.json b/client/tsconfig.node.json new file mode 100644 index 0000000..25d2949 --- /dev/null +++ b/client/tsconfig.node.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2023", + "lib": ["ES2023", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.cache/tsconfig.node.tsbuildinfo", + "strict": true, + "skipLibCheck": true, + "verbatimModuleSyntax": true, + "types": ["node"] + }, + "include": ["vite.config.ts"] +} diff --git a/client/tsconfig.spec.json b/client/tsconfig.spec.json deleted file mode 100644 index b18619f..0000000 --- a/client/tsconfig.spec.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ] - }, - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/client/vite.config.ts b/client/vite.config.ts new file mode 100644 index 0000000..d84e801 --- /dev/null +++ b/client/vite.config.ts @@ -0,0 +1,10 @@ +import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + // Relative module/CSS URLs continue to work on the public Blob asset origin. + base: './', + plugins: [react()], + build: { rollupOptions: { output: { chunkFileNames: 'assets/chunk-[name]-[hash].js' } } }, + server: { proxy: { '/api': 'http://localhost:8053', '/oauth2': 'http://localhost:8150' } }, +}); diff --git a/docs/static-hosting.md b/docs/static-hosting.md new file mode 100644 index 0000000..8630f52 --- /dev/null +++ b/docs/static-hosting.md @@ -0,0 +1,72 @@ +# Static client deployment + +Production index HTML lives in Azure Storage's `$web` container. All other files +live in its public-read `assets` Blob container. The API uses `mucsi96/rust-app` +**7.0.0** on Kubernetes. The `hello-client` release uses +`mucsi96/static-client-app` **5.0.0** for document-only gateway routing. + +Terraform supplies `client-storage-config` (`account_name`, `hostname`, `assets_base_url`) alongside +`forward-auth-config`. GitHub's existing federated deploy +identity receives Storage Blob Data Contributor separately on `$web` and `assets`. +Uploads use `--auth-mode login`; no account keys or SAS tokens are distributed. + +The pipeline builds React/Vite directly with `actions/setup-node`, `npm ci` and +`npm run build`. It passes `client/dist` as the `client-static` artifact to tests +and deployment, and attaches `client-static.tar.gz` to new client releases. +There is no client Dockerfile, image build or image publication. E2E tests mount +the compiled files and nginx configuration into the stock nginx image behind +Traefik; Traefik routes requests but does not serve files itself. + +`scripts/prepare-client.mjs` rewrites HTML asset +links to absolute Blob URLs with anonymous CORS requests, and keeps the document +base at `/`. Manifest navigation fields stay on the app origin. Module imports +and external CSS font URLs resolve relative to their Blob-hosted parents. Roboto +is bundled locally. Preparation separates `assets/` and +`documents/index.html` without changing the tested bundles. + +The official `azure/login` action authenticates with OIDC, then `azure/cli` runs +`az storage blob upload-batch` for assets. Azure CLI infers asset MIME types; +the manifest is explicitly published as `application/manifest+json`. Index HTML +is uploaded separately, last. Before uploading, deployment empties `$web`, then +`assets`, including old release directories. Only the latest assets are published, +directly at the asset root, with `Cache-Control: public, max-age=31536000, immutable`, +including the manifest and icons; index uses `no-store`. Downtime is intentional, +and a failed upload leaves the site unavailable until a successful deployment. +Deleting blobs does not clear browser caches for unchanged asset URLs. + +The storage website is publicly readable, including raw index HTML, by Azure's +static website design. It contains only public build resources. Faro's app name +and same-origin collector path are compiled into the bundle. The application +hostname authenticates documents; APIs validate JWT roles/scopes and CSRF. +Cookies and identity headers are stripped before requests reach Azure, and the +origin connection uses verified HTTPS with the storage hostname. Storage does not +perform SPA fallback; the gateway owns deep-link routing. + +Azure website endpoints do not support CORS. Browser assets therefore use Blob +URLs with CORS restricted to the app origin and GET/HEAD/OPTIONS. The gateway +has no asset catchall; it serves only SPA documents. + +`python3 scripts/check_static_assets.py ` exercises the actual +build in Chromium with separate origins: modules, lazy chunks, styles, fonts, +icons, manifest navigation, CORS enforcement, credential isolation and same-origin +API calls. + +## Shared contract with Cooking and Observatory + +All three clients use `static-client-app` 5.0.0 and the same hosting/auth deployment +secrets: `forward-auth-config.auth` and +`client-storage-config`. The gateway authenticates documents before rewriting +deep links. No response-body configuration middleware is installed. Browser assets use anonymous Blob +requests; APIs and Faro stay on the application hostname. There is no frontend +OAuth/token implementation or environment-bootstrap fetch. + +Each pipeline tests a static artifact, empties both static containers, uploads +assets before index and deploys the client route without a client container. Terraform owns +storage, app-origin CORS, scoped upload permissions and session infrastructure. +The app/API charts own routing and authentication middleware. + +Alignment preserves stack-specific security: Skeleton uses host-only double-submit +CSRF cookies with its same-origin fetch helper, Cooking uses strict mutation Origin checks, and Observatory's JWT-protected +API is read-only. Observatory also supplies a strict CSP via +`contentSecurityPolicy`; all clients receive the chart's fixed `no-referrer` and +`nosniff` document headers. diff --git a/docs/ui-auth-session-handoff.md b/docs/ui-auth-session-handoff.md index d0b6717..46a4c64 100644 --- a/docs/ui-auth-session-handoff.md +++ b/docs/ui-auth-session-handoff.md @@ -2,9 +2,18 @@ Snapshot: 20 October 2026. Read repository AGENTS.md before continuing. +Historical snapshot: current clients use Azure static hosting and compile Faro +settings into their bundles. The inline-config marker and Traefik body-rewrite +guidance below is superseded by `docs/static-hosting.md` and issue #105. + +Follow-up (23 October 2026): client chart `healthPath` was removed. All three +probes now use `/`; nginx explicitly serves `/index.html` at the origin root. +Deployment no longer supplies a probe-path override. Nested SPA routing remains +Gateway-owned. The snapshot details below describe the earlier implementation. + ## Start here -- Architecture and junior-friendly migration guide: +- Current architecture summary and diff links: https://github.com/mucsi96/skeleton-app/issues/105 - Charts PR (open, not merged at this snapshot): https://github.com/mucsi96/k8s-helm-charts/pull/22 @@ -72,8 +81,8 @@ before creating a PR; do not merge its whole history blindly. 7. API checks use private `/oauth2/auth` and return 401/403, not HTML redirects; document checks use private proxy `/` to start login. Preserve backend JWT issuer/audience/scope/roles and mutation CSRF, including proxy-bearer requests. - Skeleton keeps Spring SPA CSRF with `__Host-XSRF-TOKEN` / `X-XSRF-TOKEN`; its - matcher intentionally overrides bearer-request CSRF exemptions. + Skeleton keeps host-only double-submit CSRF with `__Host-XSRF-TOKEN` / `X-XSRF-TOKEN`; its + middleware intentionally requires proof even for bearer requests. 8. Faro uses `https:///_telemetry/collect`. Logging owns its exact POST/OPTIONS route to `/collect`, strips credentials and keeps origin/rate controls. Azure Storage hosting is future work, not provisioned here. diff --git a/flake.nix b/flake.nix index 10cfa52..6889791 100644 --- a/flake.nix +++ b/flake.nix @@ -18,9 +18,11 @@ # rootless Podman relies on setuid newuidmap/newgidmap helpers and # /etc/subuid mappings that a Nix store binary cannot provide. packages = [ - pkgs.temurin-bin-21 # JDK 21 (Temurin), matching the previous SDKMAN install - pkgs.maven - pkgs.nodejs_22 # matches the Node version used in CI + pkgs.rustup # server/rust-toolchain.toml pins the Rust toolchain + pkgs.pkg-config + pkgs.cmake + pkgs.gcc + pkgs.nodejs_24 pkgs.jq pkgs.kubectl pkgs.kubernetes-helm @@ -28,8 +30,7 @@ ]; shellHook = '' - export JAVA_HOME="${pkgs.temurin-bin-21}" - echo "skeleton-app dev shell: jdk21 (Temurin), maven, node $(node --version), jq, kubectl, helm, az" + echo "skeleton-app dev shell: rustup, node $(node --version), jq, kubectl, helm, az" echo "Podman is a distro-level prerequisite (e.g. 'apt install podman' on WSL) and is not provided by this flake." ''; }; diff --git a/mock_anthropic_server/package-lock.json b/mock_anthropic_server/package-lock.json index 71b6c75..9548dd6 100644 --- a/mock_anthropic_server/package-lock.json +++ b/mock_anthropic_server/package-lock.json @@ -14,7 +14,7 @@ "devDependencies": { "@tsconfig/node-ts": "23.6.4", "@types/express": "5.0.6", - "@types/node": "26.6.5", + "@types/node": "26.6.6", "tsx": "4.23.15", "typescript": "7.0.2" } @@ -522,9 +522,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.6.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", - "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "version": "26.6.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz", + "integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==", "dev": true, "license": "MIT", "dependencies": { diff --git a/mock_anthropic_server/package.json b/mock_anthropic_server/package.json index ad2acb6..fe2e5ad 100644 --- a/mock_anthropic_server/package.json +++ b/mock_anthropic_server/package.json @@ -12,7 +12,7 @@ "devDependencies": { "@tsconfig/node-ts": "23.6.4", "@types/express": "5.0.6", - "@types/node": "26.6.5", + "@types/node": "26.6.6", "tsx": "4.23.15", "typescript": "7.0.2" }, diff --git a/scripts/check_static_assets.py b/scripts/check_static_assets.py new file mode 100644 index 0000000..fd4aadb --- /dev/null +++ b/scripts/check_static_assets.py @@ -0,0 +1,89 @@ +"""Exercise the actual client build in Chromium against separate document/asset origins.""" +from functools import partial +from http.server import BaseHTTPRequestHandler, SimpleHTTPRequestHandler, ThreadingHTTPServer +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import threading +from urllib.parse import urlsplit + + +def main(directory): + records = [] + + class Assets(SimpleHTTPRequestHandler): + def log_message(self, *_): + pass + + def do_GET(self): + records.append({'origin': 'assets', 'path': self.path, 'cookie': self.headers.get('Cookie'), + 'authorization': self.headers.get('Authorization')}) + if not self.path.startswith('/assets/') or urlsplit(self.path).path.endswith('/index.html'): + self.send_error(404) + return + self.path = self.path.removeprefix('/assets') + super().do_GET() + + def end_headers(self): + if self.headers.get('Origin') == app_origin and 'no-cors' not in self.path: + self.send_header('Access-Control-Allow-Origin', app_origin) + self.send_header('Vary', 'Origin') + super().end_headers() + + def list_directory(self, path): + self.send_error(404) + + class Documents(BaseHTTPRequestHandler): + def log_message(self, *_): + pass + + def do_GET(self): + records.append({'origin': 'app', 'path': self.path}) + path = urlsplit(self.path).path + if path == '/api/greeting': + body = json.dumps({'name': 'World', 'message': 'Hello', 'aiGreeting': 'Fixture greeting'}).encode() + content_type = 'application/json' + elif path == '/oauth2/userinfo': + body = b'{"email":"owner@example.test","additionalClaims":{"name":"Owner"}}' + content_type = 'application/json' + elif path in ['/', '/index.html'] or 'text/html' in self.headers.get('Accept', ''): + body = (Path(prepared) / 'documents/index.html').read_bytes() + content_type = 'text/html' + else: + self.send_error(404) + return + self.send_response(200) + self.send_header('Content-Type', content_type) + self.send_header('Content-Length', str(len(body))) + self.end_headers() + self.wfile.write(body) + + with tempfile.TemporaryDirectory(dir=os.environ.get('RUNNER_TEMP', '/tmp/opencode')) as prepared: + app = ThreadingHTTPServer(('127.0.0.1', 0), Documents) + assets = ThreadingHTTPServer(('127.0.0.1', 0), partial(Assets, directory=str(Path(prepared) / 'assets'))) + app_origin = f'http://localhost:{app.server_port}' + asset_base_url = f'http://127.0.0.1:{assets.server_port}/assets/' + subprocess.run(['node', str(Path(__file__).with_name('prepare-client.mjs')), + directory, prepared, asset_base_url, app_origin], check=True) + for server in [app, assets]: + threading.Thread(target=server.serve_forever, daemon=True).start() + try: + subprocess.run(['node', str(Path(__file__).resolve().parents[1] / 'test/static-assets.mjs'), + app_origin, asset_base_url], check=True) + asset_requests = [item for item in records if item['origin'] == 'assets'] + assert asset_requests and all(not item['cookie'] and not item['authorization'] for item in asset_requests) + assert any(item['origin'] == 'app' and item['path'] == '/api/greeting' for item in records) + assert not any(item['origin'] == 'app' and urlsplit(item['path']).path.endswith( + ('.js', '.css', '.png', '.woff2', '.webmanifest')) for item in records) + print('Direct assets: browser CORS, modules/lazy chunks, CSS/fonts, icons, manifest and same-origin API passed') + finally: + for server in [app, assets]: + server.shutdown() + server.server_close() + + +if __name__ == '__main__': + main(*sys.argv[1:]) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 6b824bf..99c1f39 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,13 +1,11 @@ #!/bin/bash -set -e # Exit immediately if a command exits with a non-zero status +set -euo pipefail : "${AZURE_KEYVAULT_NAME:?Environment variable AZURE_KEYVAULT_NAME is required}" : "${SERVER_IMAGE:?Set the versioned server image to deploy}" -: "${CLIENT_IMAGE:?Set the versioned client image to deploy}" -if [[ ! "$SERVER_IMAGE" =~ ^ghcr\.io/.+(:[1-9][0-9]*|@sha256:[a-f0-9]{64})$ ]] || - [[ ! "$CLIENT_IMAGE" =~ ^ghcr\.io/.+(:[1-9][0-9]*|@sha256:[a-f0-9]{64})$ ]]; then - printf '%s\n' 'SERVER_IMAGE and CLIENT_IMAGE must use GHCR with a release version or sha256 digest.' >&2 +if [[ ! "$SERVER_IMAGE" =~ ^ghcr\.io/.+(:[1-9][0-9]*|@sha256:[a-f0-9]{64})$ ]]; then + printf '%s\n' 'SERVER_IMAGE must use GHCR with a release version or sha256 digest.' >&2 exit 1 fi @@ -29,48 +27,33 @@ API_CLIENT_ID=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --na AUTH_CONFIG=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --name forward-auth-config --query value -o tsv) AUTH_RELEASE=$(jq -er '.release_name | select(type == "string" and length > 0)' <<<"$AUTH_CONFIG") PROXY_AUTH=$(jq -ce '.auth | select(.proxyService | type == "string" and length > 0) | select(.proxyPort | type == "number") | select(.mode == "api-token")' <<<"$AUTH_CONFIG") -CLIENT_RUNTIME_CONFIG=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --name client-runtime-config --query value -o tsv | jq -ce 'select(.clientLogUrl | type == "string") | select(.clientAppName | type == "string")') +CLIENT_STORAGE_CONFIG=$(az keyvault secret show --vault-name "$AZURE_KEYVAULT_NAME" --name client-storage-config --query value -o tsv) +CLIENT_ORIGIN=$(jq -er '.hostname | select(test("^[a-z0-9.-]+\\.web\\.core\\.windows\\.net$"))' <<<"$CLIENT_STORAGE_CONFIG") echo "Updating Helm repositories..." -# The mucsi96 charts no longer bundle Prometheus exporter sidecars or -# ServiceMonitors (client-app >= 22.0.0, spring-app >= 30.0.0, node-app >= 20.0.0). -# This deploy rolls out the updated charts and drops those containers. helm repo add mucsi96 https://mucsi96.github.io/k8s-helm-charts --force-update -springAppChartVersion=$(helm search repo mucsi96/spring-app --output json | jq -r '.[0].version') -clientAppChartVersion=$(helm search repo mucsi96/client-app --output json | jq -r '.[0].version') +serverChartVersion=7.0.0 +staticClientAppChartVersion=5.0.0 helm status "$AUTH_RELEASE" --namespace hello >/dev/null -helm show values mucsi96/spring-app --version "$springAppChartVersion" | grep -q '^auth:' -helm show values mucsi96/client-app --version "$clientAppChartVersion" | grep -q '^auth:' -helm show values mucsi96/client-app --version "$clientAppChartVersion" | grep -q '^runtimeConfig:' +helm show chart mucsi96/rust-app --version "$serverChartVersion" >/dev/null +helm show chart mucsi96/static-client-app --version "$staticClientAppChartVersion" >/dev/null -echo "Deploying server: $SERVER_IMAGE using spring-app chart $springAppChartVersion" +echo "Deploying server: $SERVER_IMAGE using rust-app chart $serverChartVersion" -# CPU limits are intentionally omitted for both services (limits.cpu=null -# clears the chart default): on a single-user node they only throttle -# startup; memory limits are the ones that matter. -# -# The server is a GraalVM native executable, so there is no JVM metaspace, no -# code cache and no JIT-compiled code to hold: it idles far below what a JRE -# image would use, hence the smaller request. The request is what the -# scheduler reserves around the clock, so it is sized for idle: metrics-server -# reports a ~58Mi working set in production, so the request sits just above -# that measurement. -# -# The limit is the opposite question and stays where it is: it has to cover the -# idle footprint plus the 256Mi heap the image is capped at (see the ENTRYPOINT -# in server/Dockerfile - keep the two in step). -helm upgrade $SERVER_RELEASE_NAME mucsi96/spring-app \ +# CPU limits are omitted; memory remains bounded at 256Mi. +helm upgrade $SERVER_RELEASE_NAME mucsi96/rust-app \ --install \ --reset-values \ - --version $springAppChartVersion \ + --version $serverChartVersion \ --set-string image="$SERVER_IMAGE" \ --set host=$HOSTNAME \ --set basePath=/api \ --set-json auth="$PROXY_AUTH" \ --set clientId=$API_CLIENT_ID \ --set serviceAccountName=hello-api-workload-identity \ + --set env.LOCO_ENV=production \ --set env.AZURE_KEYVAULT_ENDPOINT=$AZURE_KEYVAULT_ENDPOINT \ --set resources.requests.memory=64Mi \ --set resources.requests.cpu=25m \ @@ -78,19 +61,13 @@ helm upgrade $SERVER_RELEASE_NAME mucsi96/spring-app \ --set resources.limits.cpu=null \ --wait -echo "Deploying client: $CLIENT_IMAGE using client-app chart $clientAppChartVersion" +echo "Updating client gateway using static-client-app chart $staticClientAppChartVersion" -helm upgrade $CLIENT_RELEASE_NAME mucsi96/client-app \ +helm upgrade $CLIENT_RELEASE_NAME mucsi96/static-client-app \ --install \ --reset-values \ - --version $clientAppChartVersion \ - --set-string image="$CLIENT_IMAGE" \ + --version $staticClientAppChartVersion \ + --set-string staticOrigin="$CLIENT_ORIGIN" \ --set host=$HOSTNAME \ --set-json auth="$PROXY_AUTH" \ - --set-json runtimeConfig="$CLIENT_RUNTIME_CONFIG" \ - --set healthPath=/index.html \ - --set resources.requests.memory=16Mi \ - --set resources.requests.cpu=5m \ - --set resources.limits.memory=32Mi \ - --set resources.limits.cpu=null \ --wait diff --git a/scripts/install_dependencies.sh b/scripts/install_dependencies.sh index 8d2a0f9..30cf71f 100755 --- a/scripts/install_dependencies.sh +++ b/scripts/install_dependencies.sh @@ -2,19 +2,19 @@ set -e # Exit immediately if a command exits with a non-zero status -# System tooling (JDK 21, Maven, Node, jq, kubectl, helm, azure-cli) is provided +# System tooling (Rust, Node, jq, kubectl, helm, azure-cli) is provided # by the Nix flake dev shell — run `nix develop`, or let direnv load it via the # `.envrc`. Podman is a distro-level prerequisite (e.g. `apt install podman` on # WSL). This script only installs the per-project dependencies. echo "Building server..." -cd server && mvn clean install && cd .. +cd server && cargo build --locked && cd .. echo "Installing client dependencies..." -cd client && npm install && cd .. +cd client && npm ci && cd .. echo "Installing mock Anthropic server dependencies..." -cd mock_anthropic_server && npm install && cd .. +cd mock_anthropic_server && npm ci && cd .. echo "Installing test dependencies..." -cd test && npm install && npx playwright install --with-deps chromium && cd .. +cd test && npm ci && npx playwright install --with-deps chromium && cd .. diff --git a/scripts/pod_up.sh b/scripts/pod_up.sh index f4262f0..35cfa93 100755 --- a/scripts/pod_up.sh +++ b/scripts/pod_up.sh @@ -9,15 +9,19 @@ if [ "${SKIP_BUILD:-}" = "1" ]; then echo "Skipping image build (SKIP_BUILD=1)..." else echo "Building container images..." - # The Spring profile is baked into the native executable during AOT - # processing, so the pod image has to be built with the test profile. - podman build --build-arg SPRING_PROFILE=test \ - -t localhost/skeleton-app-server:test "$PROJECT_DIR/server" & - podman build -t localhost/skeleton-app-client:test "$PROJECT_DIR/client" & + podman build -t localhost/skeleton-app-server:test "$PROJECT_DIR/server" & + server_build=$! + (cd "$PROJECT_DIR/client" && npm ci && npm run build) & + client_build=$! podman build -t localhost/skeleton-app-mock-anthropic:test "$PROJECT_DIR/mock_anthropic_server" & - wait + mock_build=$! + wait "$server_build" + wait "$client_build" + wait "$mock_build" fi +test -f "$PROJECT_DIR/client/dist/index.html" + echo "Cleaning up existing pod..." podman kube down "$PROJECT_DIR/test/test-pod.yaml" 2>/dev/null || true diff --git a/scripts/prepare-client.mjs b/scripts/prepare-client.mjs new file mode 100644 index 0000000..4b6e06a --- /dev/null +++ b/scripts/prepare-client.mjs @@ -0,0 +1,41 @@ +import { cp, lstat, mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises'; +import { resolve, join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +// Prepare the tested build without changing its bundles or document base URL. +export async function prepareClient(directory, destination, assetBaseUrl, appOrigin) { + const root = resolve(directory); + const index = await readFile(join(root, 'index.html'), 'utf8'); + for (const entry of await readdir(root, { recursive: true })) { + if ((await lstat(join(root, entry))).isSymbolicLink()) throw new Error(`Unexpected symlink: ${entry}`); + } + const assets = join(destination, 'assets'); + const documents = join(destination, 'documents'); + await mkdir(documents, { recursive: true }); + await cp(root, assets, { recursive: true }); + // Vite emits quoted attributes; only script/link asset URLs are rewritten. + const html = index.replace(/<(script|link)\b[^>]*>/gi, tag => { + const attribute = /^ { + if (/^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(path)) throw new Error(`Build assets must be local: ${path}`); + const url = new URL(path.replace(/^\/+/, ''), assetBaseUrl).href; + return `${attribute}="${url.replaceAll('&', '&').replaceAll('"', '"')}"`; + }).replace(/\s+crossorigin(?:=(?:"[^"]*"|'[^']*'|[^\s>]+))?/gi, ''); + return rewritten.replace(/\s*\/?>(?=$)/, ' crossorigin="anonymous">'); + }); + await rename(join(assets, 'index.html'), join(documents, 'index.html')); + await writeFile(join(documents, 'index.html'), html); + const manifestPath = join(assets, 'manifest.webmanifest'); + const manifest = JSON.parse(await readFile(manifestPath, 'utf8')); + for (const key of ['id', 'start_url', 'scope']) { + manifest[key] = new URL(manifest[key] ?? '/', `${appOrigin}/`).href; + } + await writeFile(manifestPath, JSON.stringify(manifest)); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + if (process.argv.length !== 6) throw new Error('Usage: prepare-client.mjs '); + await prepareClient(...process.argv.slice(2)); +} diff --git a/scripts/prepare-client.test.mjs b/scripts/prepare-client.test.mjs new file mode 100644 index 0000000..1441494 --- /dev/null +++ b/scripts/prepare-client.test.mjs @@ -0,0 +1,45 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; +import { prepareClient } from './prepare-client.mjs'; + +const assetUrl = 'https://fixture.blob.core.windows.net/assets/'; +const appOrigin = 'https://hello.example.test'; + +async function fixture(t) { + const root = await mkdtemp(join(process.env.RUNNER_TEMP ?? tmpdir(), 'prepare-client-')); + t.after(() => rm(root, { recursive: true, force: true })); + const input = join(root, 'input'); + const output = join(root, 'output'); + await mkdir(input); + await writeFile(join(input, 'index.html'), ` + + +`); + await writeFile(join(input, 'manifest.webmanifest'), JSON.stringify({ start_url: '/', scope: '/', icons: [{ src: 'icons/icon.png' }] })); + await writeFile(join(input, 'main.js'), 'import "./chunk.js";'); + return { input, output }; +} + +test('separates document and assets, preserves bundles and app navigation', async t => { + const { input, output } = await fixture(t); + await prepareClient(input, output, assetUrl, appOrigin); + const html = await readFile(join(output, 'documents/index.html'), 'utf8'); + assert(html.includes('')); + for (const file of ['styles.css', 'manifest.webmanifest', 'favicon.png', 'chunk.js', 'main.js']) assert(html.includes(assetUrl + file)); + assert.equal((html.match(/crossorigin="anonymous"/g) ?? []).length, 5); + await assert.rejects(readFile(join(output, 'assets/index.html')), { code: 'ENOENT' }); + assert.equal(await readFile(join(output, 'assets/main.js'), 'utf8'), 'import "./chunk.js";'); + const manifest = JSON.parse(await readFile(join(output, 'assets/manifest.webmanifest'), 'utf8')); + for (const field of ['id', 'start_url', 'scope']) assert.equal(manifest[field], `${appOrigin}/`); + assert.equal(manifest.icons[0].src, 'icons/icon.png'); + assert(!(await readFile(join(input, 'index.html'), 'utf8')).includes(assetUrl)); +}); + +test('rejects symlinks before copying the artifact', async t => { + const { input, output } = await fixture(t); + await symlink('/etc/passwd', join(input, 'linked-file')); + await assert.rejects(prepareClient(input, output, assetUrl, appOrigin), /Unexpected symlink/); +}); diff --git a/server/.dockerignore b/server/.dockerignore index ead3783..c7f83c2 100644 --- a/server/.dockerignore +++ b/server/.dockerignore @@ -1,3 +1,2 @@ -# The native build produces a multi-GB target directory; keep it out of the -# build context so local podman/docker builds stay fast. target +.git diff --git a/server/.gitignore b/server/.gitignore index 64166f2..b83d222 100644 --- a/server/.gitignore +++ b/server/.gitignore @@ -1,35 +1 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ -postgres-data/ -storage/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ +/target/ diff --git a/server/Cargo.lock b/server/Cargo.lock new file mode 100644 index 0000000..7525f35 --- /dev/null +++ b/server/Cargo.lock @@ -0,0 +1,6231 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "alloc-no-stdlib" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a" + +[[package]] +name = "alloc-stdlib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "ar_archive_writer" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cd58deff2140a0a8eae87e417bd01db68a33e148aa93d1e8cd837e55e312b6" +dependencies = [ + "object", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures 0.2.17", + "password-hash", +] + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "arrow" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965156f2220e94dcf676e04322b7b0b41c97e85cb3e1c365b8e56d0f70be999" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca16fdd1daeb1eccefb42df52ec65448ef33eec72488598675d46dfa9ce58923" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] + +[[package]] +name = "arrow-array" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3d22a41d3df78b71df0b685af219ae3a94188ab98d6fb29c958eb55c3247f4" +dependencies = [ + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.17.1", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd46a530bc1a8e763102fc36c1dc0f51f3ffa150c78e7f5658ccb54b1458ade" +dependencies = [ + "bytes", + "half", + "num-bigint 0.5.1", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa83a0752814a1922d5ee75032524ca9bbfb7f60ee35a67ed4ab8b275260aaf" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi 3.1.1", + "base64 0.23.1", + "chrono", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-cmp" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1913e57a64fbf2c4502fa6d54b547d6a1ae59e3146cbc15321d47468c937abd1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-schema", +] + +[[package]] +name = "arrow-data" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "415b7fbc4cf56b080bb5677a4ae74211b5c79e571ed37a1d547633ec07f3b43b" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ord" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c58f2ae6dd1480fc413f7320a547e39dcc499c23d4f36ca19572b685811e6e4" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cmp", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f9db8345b0638416d3b56d117d262d13070fdef788c6d75b53a180215c477e" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de2c8e714b466404cdc1189e89f892426efea614d938e16c15518c340cd43ba3" + +[[package]] +name = "arrow-select" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5af3f6656c5f2c6944f93d9a357a7f204c93d5f349385a44cf46c4a26fbcf30" +dependencies = [ + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-cmp", + "arrow-data", + "arrow-schema", + "num-traits", +] + +[[package]] +name = "arrow-string" +version = "60.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab1be9306b9a413b5b004e2a5a19caac728870d76e8891b351f040d554c93862" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] + +[[package]] +name = "async-compression" +version = "0.4.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad47a740fb906fffdd891e8b6d5fde2511600f7bfaebd68939fa08a14999459" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0876700b0d007ad25d5508865a4259c3af9af6d296bf663a0d586d0bc3369f6f" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "asyncband" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a214ba60d6231afd0e805e3c27c45a1626d9debaa5a5061c45a1ea1b2f1ed0" +dependencies = [ + "hashbrown 0.17.1", + "slab", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atoi" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d12c37257553c19e9aee6cba77814fdc9e07844abfc8b3a2c377cd920ee5a993" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "aws-lc-rs" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048006790404103c488e6c5616b3e7e702a71292aadda08e8f7698a9e0d2eb53" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bfbe32ac36b3c428696ce315464181bc4029d689fd58e3f2a4e58c252242f52" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "axum-macros", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-client-ip" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ba1af5b620232acf37f2eb6d22151ea465491e0b4c25f552d1990f64ec5a67" +dependencies = [ + "axum", + "client-ip", + "serde", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-extra" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +dependencies = [ + "axum", + "axum-core", + "bytes", + "cookie", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "serde_core", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "azure_core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e41cbd819986ba41904c207d8ffc4106f8f8352a548d773e9554906379bb2fb" +dependencies = [ + "async-lock", + "async-trait", + "azure_core_macros", + "bytes", + "futures", + "pin-project", + "rustc_version", + "serde", + "serde_json", + "tokio", + "tracing", + "typespec", + "typespec_client_core", +] + +[[package]] +name = "azure_core_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b52dba6a345f3ad2d42ff8d0d63df9d0994cfa29657bf18ffdbf149f78a4f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "tracing", +] + +[[package]] +name = "azure_identity" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32edf96b356ca7c51d7590c4925cc36efc3947a5da4468e8e0b25c56ecbb3de5" +dependencies = [ + "async-lock", + "async-trait", + "azure_core", + "futures", + "pin-project", + "serde", + "serde_json", + "time", + "tracing", + "url", +] + +[[package]] +name = "azure_security_keyvault_secrets" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a344d7c923ea305fa36bdad4d36c54e7c6fb806077430efcafb19ee40ed7b786" +dependencies = [ + "async-lock", + "async-trait", + "azure_core", + "futures", + "rustc_version", + "serde", + "serde_json", + "time", + "tokio", +] + +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + +[[package]] +name = "backtrace_printer" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d28de81c708c843640982b66573df0f0168d87e42854b563971f326745aab7" +dependencies = [ + "btparse-stable", + "colored 2.2.0", + "regex", + "thiserror 1.0.69", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bigdecimal" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fa3f3d8cbf4dffcfe4991de61d012bef509a409ecbe9dd41049bfe32b4d4653" +dependencies = [ + "autocfg", + "libm", + "num-bigint 0.4.8", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "brotli" +version = "9.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "627b7cfb0578f0eafce087a90fcd40add1231900b69e4d4de2d456260a4f5d81" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34c6783f42c21c952ad7112b354f0ba2f10760e9decea5b1b60523d6e270faaf" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr", + "serde_core", +] + +[[package]] +name = "btparse-stable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d75b8252ed252f881d1dc4482ae3c3854df6ee8183c1906bac50ff358f4f89f" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "byte-unit" +version = "5.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c719d56f7e96194cfc53460976d3ba51c85719747c9c62ed99981847b551152b" +dependencies = [ + "rust_decimal", + "schemars", + "serde", + "utf8-width", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cargo-lock" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50524592e6bfbb1bf6f94e8184a786f637faeaf1cf37bbe65502b9a2c5c48939" +dependencies = [ + "semver", + "serde", + "toml 1.1.8+spec-1.1.0", + "url", +] + +[[package]] +name = "cc" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375989decec1a0fa424442bed520fa12ede43a48475ce8c7417d2c69b32b5f6b" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf 0.11.3", +] + +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf 0.12.1", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf 0.11.3", + "phf_codegen", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "client-ip" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39d2056bf065c8b4bce5a8898d40e175211ff4410add2a84d695845d3937c729" +dependencies = [ + "forwarded-header-value", + "http", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.52.0", +] + +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "combine" +version = "4.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f840cff84d10085260e460023934d0af699e71212b09b2a41452e8bd9cda43" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", + "zstd", + "zstd-safe", +] + +[[package]] +name = "compression-core" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ebdda89edc534bf8d5dd2857562633b6495557e5846552ade994b99ed13c36a" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crc32fast" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f97d3416d5337d15c4b0d78c8c91df922ca143f57ec20e2d1c188333047ef04" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "croner" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa42bcd3d846ebf66e15bd528d1087f75d1c6c1c66ebff626178a106353c576" +dependencies = [ + "chrono", + "derive_builder", + "strum 0.27.2", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "cruet" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113a9e83d8f614be76de8df1f25bf9d0ea6e85ea573710a3d3f3abe1438ae49c" +dependencies = [ + "once_cell", + "regex", +] + +[[package]] +name = "cruet" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28049cb85be0d073a0e90983c15b50d730f59292985cd17bfab0ce090f158c31" +dependencies = [ + "regex", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261af4dc7a06ea8a527a8717d8cbba3417530d6ea14e1edb3de6b67806be474f" +dependencies = [ + "cmov", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "defmt" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a0795ac740cb54d7b3775c9c17345f6aaecf884c01733b39d6017738e0e3e1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "840bb056bd99c495c9188198a258ab787c79f306d864db3e6e8451442d6d8366" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "defmt-parser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71958f69fb2de856c5dd51ac9377e986ca1aa5919f931bf5395a807277f889a0" +dependencies = [ + "thiserror 2.0.21", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derive-where" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2b94854e8576378ccda7c8de8a66ed8b4e8acbd2c50ec3418ea6c8aaf4b567" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.119", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "duct" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b9e2a29ff01e8bb526a571ad06c10ed72aae80d5999ed204f7971f99f19974" +dependencies = [ + "libc", + "os_pipe", + "shared_child", + "shared_thread", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" +dependencies = [ + "serde", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "hkdf 0.12.4", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "email-encoding" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420b9da095f052ea597503e39073b5b3c522f7db933fbac202d91d24492693fd" +dependencies = [ + "base64 0.23.1", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" + +[[package]] +name = "encoding_rs" +version = "0.8.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89253175e704ab869b04f9db224d38630e0211a53841a79181deae0889e169f5" +dependencies = [ + "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + +[[package]] +name = "english-to-cron" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d16f6dc9dc43a9a2fd5bce09b6cf8df250dcf77cffdaa66be21c527e2d05c" +dependencies = [ + "regex", +] + +[[package]] +name = "equivalent" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror 1.0.69", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "globset" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98b0d85522dc0a824cfebbc9594ff4a9b289c568bea0370319dfbdf20ccdd2d" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "globwalk" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" +dependencies = [ + "bitflags 2.13.2", + "ignore", + "walkdir", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac 0.13.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3e324da4c95177d6291d4c8730197c0d1822f8a9766814a4a44fa5ab797c9c" +dependencies = [ + "atomic-waker", + "bytes", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" + +[[package]] +name = "icu_properties" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" + +[[package]] +name = "icu_provider" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "484be5657551d7868d67587df967fb4fcbe9d266a761cc855aaa148fda0b3cc7" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "indoc" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37b2691796cffeb8a8cd305ac66e65841559f147f4e63231d0eafa4db5384d1" +dependencies = [ + "rustversion", +] + +[[package]] +name = "inotify" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592" +dependencies = [ + "bitflags 2.13.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" +dependencies = [ + "libc", +] + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ac703058abac89e5c39b0b879dce2b6b14a4ba36600c7e7e3d0c60a6883ef3c" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "js-sys", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aee43309eb53bafb8c36d35d6e444769c8f8e6206a9fbf7546f5db9d7d4a0e93" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc32470c67eb7d0e9ccb74303fa925313dc04cecb1aa048beaa6f391e36a93d" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8377070c6bae868759445e5a77f66d84f0b72f3a054bfb00e6d038b8282da7" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.21", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75fe14a82d81e5f5af639997db37d8b96045938a7ac6ab18cdbe1c7467e05e1" +dependencies = [ + "base64 0.22.1", + "ed25519-dalek", + "getrandom 0.2.17", + "hmac 0.12.1", + "js-sys", + "p256", + "p384", + "pem", + "rand 0.8.8", + "rsa", + "serde", + "serde_json", + "sha2 0.10.9", + "signature", + "simple_asn1", + "zeroize", +] + +[[package]] +name = "kqueue" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d763e5b24120b4ddf50de6c92308156765aabfbbccebf401da7cff2d70a41ea" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087" +dependencies = [ + "bitflags 2.13.2", + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb" +dependencies = [ + "spin", +] + +[[package]] +name = "lettre" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c646bd5cc763b1087b15493e29a64be6147ba8f19342004fa52048ee596eae" +dependencies = [ + "async-trait", + "base64 0.23.1", + "email-encoding", + "email_address", + "fastrand", + "futures-io", + "futures-util", + "hostname", + "httpdate", + "idna", + "mime", + "nom", + "percent-encoding", + "quoted_printable", + "rustls", + "socket2", + "tokio", + "tokio-rustls", + "url", + "webpki-roots", +] + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.191" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "loco-gen" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04fee46be63916df1546d7b7b8eab02fc50583c66c29e63a1fb7db9f9d595edc" +dependencies = [ + "chrono", + "clap", + "colored 3.1.1", + "cruet 1.0.0", + "duct", + "heck 0.5.0", + "include_dir", + "regex", + "rrgen", + "serde", + "serde_json", + "thiserror 2.0.21", + "tracing", +] + +[[package]] +name = "loco-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5386baf405736a2620001f4561b00fa4874dae99eac3ccf01713fabc9ef13af4" +dependencies = [ + "argon2", + "async-trait", + "axum", + "axum-client-ip", + "axum-extra", + "backtrace_printer", + "byte-unit", + "bytes", + "cargo-lock", + "chrono", + "clap", + "colored 3.1.1", + "cruet 1.0.0", + "dashmap", + "duct", + "english-to-cron", + "futures-util", + "heck 0.5.0", + "http", + "include_dir", + "lettre", + "loco-gen", + "notify", + "opendal", + "rand 0.9.5", + "regex", + "sea-orm", + "sea-orm-migration", + "semver", + "serde", + "serde_json", + "serde_variant", + "serde_yaml_ng", + "sqlx", + "tera 2.4.0", + "thiserror 2.0.21", + "tokio", + "tokio-cron-scheduler", + "tokio-util", + "toml 0.8.23", + "tower", + "tower-http", + "tracing", + "tracing-appender", + "tracing-subscriber", + "url", + "uuid", + "validator", +] + +[[package]] +name = "log" +version = "0.4.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c" + +[[package]] +name = "lru-slab" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" + +[[package]] +name = "mac_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0581a75c45969c63afd2bb87b1d8b25cfcc556c7a918cf9bb13b0fe8d2381" +dependencies = [ + "nix", + "serde", + "windows-sys 0.61.2", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "migration" +version = "0.1.0" +dependencies = [ + "sea-orm-migration", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "memchr", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + +[[package]] +name = "notify" +version = "8.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f812702fbc75d35416d3f884e04925be7e9498f4eceea2e24ba34559284674" +dependencies = [ + "bitflags 2.13.2", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "notify-types", + "objc2-core-foundation", + "objc2-core-services", + "walkdir", + "windows-sys 0.61.2", +] + +[[package]] +name = "notify-types" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a437a9308232ce794b1e7fdf540d38ea37efc3c73492640c13b4c8568b8f108" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e7820bc0a80a0238e650327316f929ba18d5be054b647490a3a6a339f3e7c0" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.8", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "objc2-core-services" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583300ad934cba24ff5292aee751ecc070f7ca6b39a574cc21b7b5e588e06a0b" +dependencies = [ + "libc", + "objc2-core-foundation", +] + +[[package]] +name = "object" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opendal" +version = "0.58.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33dbff14cc9bb085224256d6a81289d2f3202e85b06f408d42534b42162a4231" +dependencies = [ + "opendal-core", + "opendal-layer-retry", + "opendal-service-fs", +] + +[[package]] +name = "opendal-core" +version = "0.58.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48dbcef97d3eb7591db2c18d5cae95c836bcce07359b98d98dd6f4e861eb77b7" +dependencies = [ + "anyhow", + "asyncband", + "base64 0.23.1", + "bytes", + "futures", + "http", + "jiff", + "log", + "md-5", + "percent-encoding", + "quick-xml", + "serde", + "serde_json", + "tokio", + "url", + "uuid", + "web-time", +] + +[[package]] +name = "opendal-layer-retry" +version = "0.58.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94db301964a25366090484d61e6da16d5979cc8faf02c3e12210dc74fafed38" +dependencies = [ + "backon", + "log", + "opendal-core", +] + +[[package]] +name = "opendal-service-fs" +version = "0.58.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7ef1e1c45f3f89282a59073897e0d685e51385fed0aea771714789525cff996" +dependencies = [ + "bytes", + "log", + "opendal-core", + "serde", + "tokio", + "xattr", +] + +[[package]] +name = "openssl-probe" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e036b411754132fd6b74e94b74e9a13c5cf606fa93d1885c35860d3060820b1" + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "ouroboros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8db75153506001cb36ed924f08cadc862eb3f8c4d0d534139f29074769d7660" +dependencies = [ + "memchr", + "pest_stack_guard", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20aa17e11fb35664b67d5214a0afac57a360d231b6ec53d6eba0700b27d933b4" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ec5afccf44ccbfeb2b232316510bb55b4bf34d891afcb0fb07d2b17d7fe9d" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "pest_meta" +version = "2.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f45b6caa65c1b08186832745159c2529994146340a7bf44168095469720f5d" +dependencies = [ + "pest", +] + +[[package]] +name = "pest_stack_guard" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac6154fd4418b8f0b82532c59c26f303f9ca59a64c883e8ce3971fd82733439" +dependencies = [ + "psm", + "stacker", +] + +[[package]] +name = "pgvector" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3673cba5b9a124916096a423b806a9f29620972c6c97b08db5f2053e9428b481" +dependencies = [ + "serde", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.8", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "pluralizer" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b3eba432a00a1f6c16f39147847a870e94e2e9b992759b503e330efec778cbe" +dependencies = [ + "once_cell", + "regex", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.17+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error-attr3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e564d14133360e1ae169ffde5da25881b5fa47261665b8e5713c212c27799da" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0d4471b3436c22106b21913b1dda531558918ae9b7ec55d58aa84b43552233" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "version_check", + "yansi", +] + +[[package]] +name = "psm" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quinn" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.21", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.3", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.21", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "quoted_printable" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rrgen" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57fda81c7dd629ed81a33807d33097613c5a3c67cb5dc30fcbda20683dc6481" +dependencies = [ + "cruet 0.13.3", + "fs-err", + "glob", + "heck 0.4.1", + "regex", + "serde", + "serde_json", + "serde_regex", + "serde_yaml", + "tera 1.20.1", + "thiserror 1.0.69", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid 0.9.6", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust_decimal" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7653272e75dcac41dc199fbea6f5797633994fafd339943c06c9af16bf29cd3a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.8", + "rand 0.9.5", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a073f5dc7469f984c52ad2752b63b0807745133b6de880b7b64c1ac4c48aec4" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f" + +[[package]] +name = "rustls-webpki" +version = "0.103.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cb23c424d8ee841bb4d813677ca237e2a610067d594fec130f87d6093495ab5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab508826f74a77ca9d5aba6ff19b522583ee3eaf28a19384ff3d0e5835fadf6e" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sea-bae" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260bbc7148a8d6818ac5032a1b9970da1a68bdd723d45b12d59f7c1bf3565e24" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sea-orm" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40bc08e0aa1963295a30473f98d9b4c9c2b0b3a028381e0143cb2647d0a59a32" +dependencies = [ + "async-stream", + "async-trait", + "bigdecimal", + "chrono", + "derive-where", + "derive_more", + "futures-util", + "itertools", + "log", + "mac_address", + "ouroboros", + "pgvector", + "rust_decimal", + "sea-orm-arrow", + "sea-orm-macros", + "sea-query", + "sea-query-sqlx", + "sea-schema", + "serde", + "serde_json", + "sqlx", + "sqlx-core", + "strum 0.28.0", + "thiserror 2.0.21", + "time", + "tracing", + "url", + "uuid", + "web-time", +] + +[[package]] +name = "sea-orm-arrow" +version = "2.0.0-rc.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2edbdc3c8e00e855d7911b6c6c4048f61c28eba40a1d40456f363d7b4969a4" +dependencies = [ + "arrow", + "sea-query", + "thiserror 2.0.21", +] + +[[package]] +name = "sea-orm-cli" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04469c4a54e7271fe3fe2b8140102a2cd2eb7e48129a3afcd013b9909ddebc3c" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "indoc", + "regex", + "sea-schema", + "sqlx", + "tokio", + "tracing", + "tracing-subscriber", + "url", +] + +[[package]] +name = "sea-orm-macros" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fa8c81c20fc8cfe78d22d9a2721ca5ef151dc4a8a7b372de218aaba33733fa" +dependencies = [ + "heck 0.5.0", + "itertools", + "pluralizer", + "proc-macro2", + "quote", + "sea-bae", + "syn 2.0.119", + "unicode-ident", +] + +[[package]] +name = "sea-orm-migration" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07970137dbbed6daf56a2429db349abfb68ed1c79206957c30d4a0e9ea808c08" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "sea-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "546040c653a705e60ec65ecd3191a809603734bebbc225775916dea9ae409b31" +dependencies = [ + "chrono", + "ordered-float", + "rust_decimal", + "sea-query-derive", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "sea-query-derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b0f466921cdd3cf4b89d5c3ac2173dba89a873ab395b123a645de181ec7537" +dependencies = [ + "darling 0.20.11", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.119", + "thiserror 2.0.21", +] + +[[package]] +name = "sea-query-sqlx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eaa419cdb9157da1361186b1959983eb2ea0dcb9a3c69dc45c449ecb2af8fef" +dependencies = [ + "sea-query", + "sqlx", +] + +[[package]] +name = "sea-schema" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3553c77dceed56e95bece9ea876c4dd67ca879ef51055a0b97a7bb89a8ae4fed" +dependencies = [ + "async-trait", + "sea-query", + "sea-query-sqlx", + "sea-schema-derive", + "sqlx", +] + +[[package]] +name = "sea-schema-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_regex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafc8d0c5330cecff10f16b459b479fd9acaa5b4acd7167301414e21b0057012" +dependencies = [ + "regex", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_variant" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0068df419f9d9b6488fdded3f1c818522cdea328e02ce9d9f147380265a432" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serde_yaml_ng" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4db627b98b36d4203a7b458cf3573730f2bb591b28871d916dfa9efabfd41f" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shared_child" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "607549934f6cc26b89cfecfdc46fa90f1e5d1536a68349b0c3a4f9d1c0d37959" +dependencies = [ + "libc", + "sigchld", + "windows-sys 0.61.2", +] + +[[package]] +name = "shared_thread" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1c6cdf07f3a4b1900680728ac1a12f72aa6424f37138f9253116461576e00f" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "sigchld" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f2b37f04360cd465089b87a9c3869c08220a2f3458463f0adf8badf5e77f2c" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f7447afd772ca79ad17ae0a3972a6b0df0cb4b80990fd82707593e9e012a74" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "thiserror 2.0.21", + "time", +] + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "skeleton-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "axum", + "azure_identity", + "azure_security_keyvault_secrets", + "jsonwebtoken", + "loco-rs", + "migration", + "reqwest", + "rustls", + "sea-orm", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + +[[package]] +name = "smallvec" +version = "1.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d5d4b1981b8bbbb7aed204cae5726d683d5d6ac7e74ec54122ea28f315e7c8" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64 0.22.1", + "bytes", + "cfg-if", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "rust_decimal", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror 2.0.21", + "time", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags 2.13.2", + "byteorder", + "bytes", + "chrono", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "rust_decimal", + "serde", + "sha1", + "sha2 0.11.1", + "sqlx-core", + "thiserror 2.0.21", + "time", + "tracing", + "uuid", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi 2.0.0", + "base64 0.22.1", + "bitflags 2.13.2", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf 0.13.0", + "hmac 0.13.0", + "itoa", + "log", + "md-5", + "memchr", + "rand 0.10.3", + "rust_decimal", + "serde", + "serde_json", + "sha2 0.11.1", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.21", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi 2.0.0", + "chrono", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror 2.0.21", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tera" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8004bca281f2d32df3bacd59bc67b312cb4c70cea46cbd79dbe8ac5ed206722" +dependencies = [ + "chrono", + "chrono-tz 0.9.0", + "globwalk", + "humansize", + "lazy_static", + "percent-encoding", + "pest", + "pest_derive", + "rand 0.8.8", + "regex", + "serde", + "serde_json", + "slug", + "unicode-segmentation", +] + +[[package]] +name = "tera" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e0cadeeb54426080b4c5395d59769ce8293f542cc25511c167c742b2175809" +dependencies = [ + "globset", + "serde", + "walkdir", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl 2.0.21", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.54.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-cron-scheduler" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f50e41f200fd8ed426489bd356910ede4f053e30cebfbd59ef0f856f0d7432a" +dependencies = [ + "chrono", + "chrono-tz 0.10.4", + "croner", + "num-derive", + "num-traits", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml" +version = "1.1.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.1.2", + "toml_datetime 1.1.2+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_edit" +version = "0.25.17+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" +dependencies = [ + "indexmap", + "toml_datetime 1.1.2+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "async-compression", + "bitflags 2.13.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "tracing", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.21", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "typespec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "753a2fe021e407d4fc9ee6f4f0a33403cc306d5c54c4e4ebe1b8cbde0ca052b9" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "typespec_client_core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0373af0f9d4f580b3a1a9d9639cedaabe015ed262b35bfbe13941bfb14fe1ea6" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "dyn-clone", + "futures", + "pin-project", + "rand 0.10.3", + "reqwest", + "serde", + "serde_json", + "time", + "tokio", + "tracing", + "typespec", + "typespec_macros", + "url", + "uuid", +] + +[[package]] +name = "typespec_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c608f4427943f8adb211abc95c87672b1b98847152783507d54e3246e502f60" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" + +[[package]] +name = "unicode-normalization" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993ad287eb20e8ba755312801cfe1413e0f25d604075863acaddca10b04c1833" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "159a7cadce548703edd50d24069bc294c5415ecab0a480e0cd1ca06d112dc94a" + +[[package]] +name = "utf8_iter" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af3bd9d3e571c26fcce9d033b87ea5ab061b8d2ffe9b7a5675d810d68f03edf0" +dependencies = [ + "utf_types", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "utf_types" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3b425286980a367278453f3b6d28cdcb134b574e5a35824a6ff5eebad50bb6" + +[[package]] +name = "uuid" +version = "1.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "rand 0.10.3", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "validator" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240e4b81c20a1d6d50d1d7265c658dfbd204e8b9ac4d80f3c931f39462196335" +dependencies = [ + "darling 0.23.0", + "proc-macro-error3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4cdd0dd910afe868b7ef477227d8d538b46b3075031afee8a9f2acb0a2ed0b" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c" +dependencies = [ + "cfg-if", + "rustversion", + "serde", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e14e0327cb5368ad60ccb22d04a9827a693c95a926d8d125e9fa39e0baec501" +dependencies = [ + "js-sys", + "tokio", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.9", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d179596ff5ec0f6de4db64d54011bde6289cc49603d3a6e4ce3f329207ab88" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e49d0e65abc00c142e8f9428da991da9f1a250c39be97459901eb12b9b49f62a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f280bbb2b287bc8e7de7e3852945a0ff50d1bbcb5ed42b6c7a568c546df171" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xattr" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963d6fab92d5504b971dc8bd90ca743c2575e590bc8071ea5bc571598667ae08" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yoke" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3ae9bf90af6e40197bef767eeefc46ad6397420fe873830bd85e5fbbfb3c70" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded520f16b29e1a9b771c722221b2b0a0398c2316d9bb3c42b458a5414d7434b" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.2+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "481ada9c543b2323cbb7bbdbb5249177fbf0188ed959ed2c15e4b22421c84ed3" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..9e2eec6 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "skeleton-server" +version = "0.1.0" +edition = "2024" +rust-version = "1.99" +publish = false +license = "MIT" + +[workspace] +members = ["migration"] + +[dependencies] +anyhow = "1" +async-trait = "0.1" +axum = "0.8" +azure_identity = "1.0" +azure_security_keyvault_secrets = "1.0" +jsonwebtoken = { version = "11", features = ["rust_crypto"] } +loco-rs = { version = "1.2", default-features = false, features = ["cli", "with-db"] } +migration = { path = "migration" } +reqwest = { version = "0.13", default-features = false, features = ["rustls-no-provider", "json"] } +rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sea-orm = { version = "2", default-features = false, features = ["macros", "sqlx-postgres", "runtime-tokio-rustls"] } +thiserror = "2" +tokio = { version = "1", features = ["macros", "rt-multi-thread", "net", "signal", "sync", "time"] } +tracing = "0.1" +url = "2" +uuid = { version = "1", features = ["v4"] } + +[profile.release] +lto = "thin" +strip = true + +[lints.rust] +unsafe_code = "forbid" + +[lints.clippy] +dbg_macro = "deny" +todo = "deny" diff --git a/server/Dockerfile b/server/Dockerfile index 234243c..bb27095 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,60 +1,17 @@ -# Stage 1: Maven distribution, copied into the native build stage below. -# The GraalVM image ships a JDK but no build tool, and Maven is pure Java, so -# copying it in is cheaper and more predictable than installing it there. -FROM docker.io/library/maven:3-eclipse-temurin-25-alpine AS maven - -# Stage 2: Compile the application into a native executable. -# The toolchain is JDK 25 while the project's language level stays at 21: the -# compiler targets 21 via java.version, and 25 is simply the JDK the current -# Liberica NIK release ships. -FROM docker.io/bellsoft/liberica-native-image-kit-container:jdk-25-nik-25-musl AS build - -COPY --from=maven /usr/share/maven /usr/share/maven -ENV PATH="/usr/share/maven/bin:${PATH}" - -# The Spring profile is resolved during AOT processing and baked into the -# executable, so an image serves exactly one profile. Build one image per -# profile: `test` for the e2e pod, `prod` for the published image. -ARG SPRING_PROFILE=prod - -WORKDIR /workspace - -# Copy POM and download dependencies (cached separately from source) -COPY pom.xml ./ -RUN mvn dependency:go-offline -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn - -# Copy source code and compile the native executable -COPY native-image.security ./ -COPY src ./src -RUN mvn -Pnative native:compile -DskipTests -B \ - -Dapp.profile=${SPRING_PROFILE} \ - -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn - -# Stage 3: Runtime image -FROM docker.io/library/alpine:3.24 +FROM docker.io/library/rust:1.99.1-bookworm AS build +WORKDIR /src +COPY Cargo.toml Cargo.lock rust-toolchain.toml ./ +COPY src/ ./src/ +COPY migration/ ./migration/ +RUN cargo build --release --locked + +FROM gcr.io/distroless/cc-debian12:nonroot +WORKDIR /app +COPY --from=build /src/target/release/skeleton-server /app/skeleton-server +COPY config/ /app/config/ LABEL org.opencontainers.image.source="https://github.com/mucsi96/skeleton-app" - -VOLUME /tmp - -# curl is used for health checks. The executable is linked against musl and -# zlib, both of which Alpine provides - but no JRE, which is the point. -RUN apk add --no-cache curl zlib - -COPY --from=build /workspace/target/skeleton /app/skeleton - -# There is no JDK in this image, so java.home is unset, and the Azure SDK's JDK -# HTTP client builder dereferences it to read /conf/net.properties. -# Point it at an empty file: the JDK ships that property empty by default too, -# and the header allow-list below is what actually matters. -RUN mkdir -p /app/conf && : > /app/conf/net.properties - -# An absolute heap cap rather than the percentage of physical memory the default -# uses: the executable's own footprint before any heap is allocated is a -# constant, so the headroom the container needs is one too. 256Mi of heap fits -# the 768Mi limit in scripts/deploy.sh alongside it - keep the two in step. The -# Azure SDK sets Content-Length explicitly on the JDK HTTP client, which the -# client rejects unless the header is allow-listed. -ENTRYPOINT ["/app/skeleton", \ - "-XX:MaxHeapSize=256m", \ - "-Djava.home=/app", \ - "-Djdk.httpclient.allowRestrictedHeaders=content-length"] +ENV LOCO_ENV=production PORT=8080 BINDING=0.0.0.0 +EXPOSE 8080 +USER 65532:65532 +ENTRYPOINT ["/app/skeleton-server"] +CMD ["start", "--no-banner"] diff --git a/server/config/development.yaml b/server/config/development.yaml new file mode 100644 index 0000000..78e334b --- /dev/null +++ b/server/config/development.yaml @@ -0,0 +1,42 @@ +logger: + enable: true + level: info + format: compact +server: + binding: <%= get_env(name="BINDING", default="127.0.0.1") %> + port: <%= get_env(name="PORT", default="8053") %> + host: http://localhost + middlewares: + etag: + enable: false + fallback: + enable: false + secure_headers: + enable: true + preset: empty + overrides: + Cache-Control: no-store + X-Content-Type-Options: nosniff +workers: + mode: BackgroundAsync +database: + uri: <%= get_env(name="DATABASE_URL") %> + enable_logging: false + min_connections: 1 + max_connections: 10 + connect_timeout: 30000 + idle_timeout: 300000 + auto_migrate: true + dangerously_truncate: false + dangerously_recreate: false + run_on_start: CREATE SCHEMA IF NOT EXISTS hello +settings: + oidc: + issuer: <%= get_env(name="OIDC_ISSUER") %> + audience: <%= get_env(name="API_CLIENT_ID") %> + anthropic: + base_url: <%= get_env(name="ANTHROPIC_BASE_URL") %> + api_key: <%= get_env(name="ANTHROPIC_API_KEY") %> + model: claude-sonnet-4-6 + max_tokens: 1024 + timeout_seconds: 30 diff --git a/server/config/production.yaml b/server/config/production.yaml new file mode 100644 index 0000000..120f9ef --- /dev/null +++ b/server/config/production.yaml @@ -0,0 +1,43 @@ +logger: + enable: true + level: info + format: json +server: + binding: 0.0.0.0 + port: <%= get_env(name="PORT", default="8080") %> + host: http://localhost + middlewares: + etag: + enable: false + fallback: + enable: false + secure_headers: + enable: true + preset: empty + overrides: + Cache-Control: no-store + X-Content-Type-Options: nosniff +workers: + mode: BackgroundAsync +database: + # Supplied by workload identity before connecting. + uri: "" + enable_logging: false + min_connections: 1 + max_connections: 10 + connect_timeout: 30000 + idle_timeout: 300000 + auto_migrate: true + dangerously_truncate: false + dangerously_recreate: false + run_on_start: CREATE SCHEMA IF NOT EXISTS hello +settings: + oidc: + issuer: "" + audience: "" + anthropic: + base_url: https://api.anthropic.com + api_key: "" + model: claude-sonnet-4-6 + max_tokens: 1024 + timeout_seconds: 30 diff --git a/server/config/test.yaml b/server/config/test.yaml new file mode 100644 index 0000000..bd92088 --- /dev/null +++ b/server/config/test.yaml @@ -0,0 +1,42 @@ +logger: + enable: true + level: info + format: compact +server: + binding: <%= get_env(name="BINDING", default="127.0.0.1") %> + port: <%= get_env(name="PORT", default="8054") %> + host: http://localhost + middlewares: + etag: + enable: false + fallback: + enable: false + secure_headers: + enable: true + preset: empty + overrides: + Cache-Control: no-store + X-Content-Type-Options: nosniff +workers: + mode: BackgroundAsync +database: + uri: <%= get_env(name="DATABASE_URL") %> + enable_logging: false + min_connections: 1 + max_connections: 10 + connect_timeout: 30000 + idle_timeout: 300000 + auto_migrate: true + dangerously_truncate: false + dangerously_recreate: false + run_on_start: CREATE SCHEMA IF NOT EXISTS hello +settings: + oidc: + issuer: <%= get_env(name="OIDC_ISSUER") %> + audience: <%= get_env(name="API_CLIENT_ID") %> + anthropic: + base_url: <%= get_env(name="ANTHROPIC_BASE_URL") %> + api_key: <%= get_env(name="ANTHROPIC_API_KEY") %> + model: claude-sonnet-4-6 + max_tokens: 1024 + timeout_seconds: 30 diff --git a/server/migration/Cargo.toml b/server/migration/Cargo.toml new file mode 100644 index 0000000..306fd02 --- /dev/null +++ b/server/migration/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "migration" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +sea-orm-migration = { version = "2", default-features = false, features = ["runtime-tokio-rustls", "sqlx-postgres"] } diff --git a/server/migration/src/lib.rs b/server/migration/src/lib.rs new file mode 100644 index 0000000..dd418e4 --- /dev/null +++ b/server/migration/src/lib.rs @@ -0,0 +1,12 @@ +use sea_orm_migration::prelude::*; + +mod m20261103_000001_greetings; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![Box::new(m20261103_000001_greetings::Migration)] + } +} diff --git a/server/migration/src/m20261103_000001_greetings.rs b/server/migration/src/m20261103_000001_greetings.rs new file mode 100644 index 0000000..c86b331 --- /dev/null +++ b/server/migration/src/m20261103_000001_greetings.rs @@ -0,0 +1,21 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .get_connection() + .execute_unprepared(include_str!("m20261103_000001_greetings.sql")) + .await?; + Ok(()) + } + + async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> { + Err(DbErr::Migration( + "The greetings baseline is irreversible: it may contain existing user data".into(), + )) + } +} diff --git a/server/migration/src/m20261103_000001_greetings.sql b/server/migration/src/m20261103_000001_greetings.sql new file mode 100644 index 0000000..8aa9f9e --- /dev/null +++ b/server/migration/src/m20261103_000001_greetings.sql @@ -0,0 +1,15 @@ +-- Seed only a new table. Existing rows, IDs and sequences are never modified. +CREATE SCHEMA IF NOT EXISTS hello; +DO $$ +BEGIN + IF to_regclass('hello.greetings') IS NULL THEN + CREATE TABLE hello.greetings ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name TEXT NOT NULL, + message TEXT NOT NULL + ); + INSERT INTO hello.greetings (name, message) + VALUES ('Igor', 'Welcome to the skeleton app!'); + END IF; +END +$$; diff --git a/server/native-image.security b/server/native-image.security deleted file mode 100644 index d213a35..0000000 --- a/server/native-image.security +++ /dev/null @@ -1,18 +0,0 @@ -# Spring AOT generates bean-definition classes into the packages of the -# configuration classes it processes. For the signed Spring Cloud Azure jars -# that mixes unsigned (generated) and signed classes in one package, and the -# native-image builder's class loader rejects that with -# SecurityException: ...'s signer information does not match signer -# information of other classes in the same package -# Disabling the jar signature algorithms makes the builder treat those jars as -# unsigned. Note what that means: signatures on those jars are not verified at -# all during the build, rather than the signer mismatch alone being tolerated. -# RSA and DSA are named because they are the signature algorithms jar signing -# actually uses (MD2 and MD5 are digests, and carry no weight on their own); -# dropping them is what makes a signed jar read as unsigned. The JVM offers no -# way to scope this to particular jars - the property is global to whichever -# JVM reads it, which is why it is confined to the builder. -# This file is only ever passed to the native-image builder JVM (see -# native-maven-plugin in pom.xml); it is not part of the application, and the -# jars it applies to are the ones Maven already resolved and checksummed. -jdk.jar.disabledAlgorithms=MD2, MD5, RSA, DSA diff --git a/server/pom.xml b/server/pom.xml deleted file mode 100644 index 114b426..0000000 --- a/server/pom.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 4.1.1 - - - io.github.mucsi96 - skeleton - 0.0.1-SNAPSHOT - skeleton - Skeleton reference application - - - - - - - - - - - - - - - 21 - - prod - - - - org.springframework.boot - spring-boot-starter-actuator - - - io.micrometer - micrometer-registry-prometheus - runtime - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-webmvc - - - org.springframework.boot - spring-boot-starter-validation - - - com.azure.spring - spring-cloud-azure-starter-keyvault-secrets - - - com.azure - azure-core-http-netty - - - - - - com.azure - azure-core-http-jdk-httpclient - - - org.springframework.boot - spring-boot-starter-security-oauth2-resource-server - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - org.springframework.boot - spring-boot-starter-liquibase - - - org.postgresql - postgresql - runtime - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.ai - spring-ai-starter-model-anthropic - - - - - - com.azure.spring - spring-cloud-azure-dependencies - 7.4.0 - pom - import - - - org.springframework.ai - spring-ai-bom - 2.0.1 - pom - import - - - - com.azure - azure-core - 1.60.0 - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - - org.projectlombok - lombok - - - org.hibernate.orm - hibernate-processor - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - process-aot - - - ${app.profile} - - - - false - 8152 - - - - - - - org.graalvm.buildtools - native-maven-plugin - - - - true - - - - --libc=musl - -H:+ReportExceptionStackTraces - - --initialize-at-build-time=com.fasterxml.jackson.core - - -J-Djava.security.properties=${project.basedir}/native-image.security - - - - - - - diff --git a/server/rust-toolchain.toml b/server/rust-toolchain.toml new file mode 100644 index 0000000..955e964 --- /dev/null +++ b/server/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.99.1" +components = ["rustfmt", "clippy"] +profile = "minimal" diff --git a/server/src/app.rs b/server/src/app.rs new file mode 100644 index 0000000..ce4916c --- /dev/null +++ b/server/src/app.rs @@ -0,0 +1,93 @@ +use std::path::Path; + +use async_trait::async_trait; +use axum::{Extension, Router, middleware}; +use loco_rs::{ + Result, + app::{AppContext, Hooks}, + bgworker::Queue, + boot::{self, BootResult, StartMode}, + config::Config, + controller::{AppRoutes, Routes, monitoring}, + environment::Environment, + task::Tasks, +}; +use migration::Migrator; + +use crate::{ + controllers, key_vault, + middleware::{ + auth::{self, Auth}, + csrf, + }, + services::anthropic::Anthropic, + settings::Settings, +}; + +pub struct App; + +#[async_trait] +impl Hooks for App { + fn app_name() -> &'static str { + env!("CARGO_PKG_NAME") + } + fn app_version() -> String { + env!("CARGO_PKG_VERSION").into() + } + + async fn load_config(environment: &Environment) -> Result { + let mut config = environment.load()?; + if *environment == Environment::Production { + key_vault::configure(&mut config) + .await + .map_err(|error| loco_rs::Error::Any(error.into()))?; + } + // All pooled connections use the app schema, including migration metadata. + let mut uri = url::Url::parse(&config.database.uri).map_err(loco_rs::Error::wrap)?; + uri.query_pairs_mut() + .append_pair("options", "-csearch_path=hello"); + config.database.uri = uri.into(); + config + .settings::()? + .validate() + .map_err(|error| loco_rs::Error::Any(error.into()))?; + Ok(config) + } + + async fn boot( + mode: StartMode, + environment: &Environment, + config: Config, + ) -> Result { + boot::create_app::(mode, environment, config).await + } + + fn routes(_ctx: &AppContext) -> AppRoutes { + AppRoutes::empty() + .add_route(controllers::greetings::routes()) + .add_route(Routes::new().get("/healthz", monitoring::readiness)) + } + + async fn after_routes(router: Router, ctx: &AppContext) -> Result { + let settings: Settings = ctx.config.settings()?; + let auth = Auth::new(settings.oidc.issuer, settings.oidc.audience) + .await + .map_err(|error| loco_rs::Error::Any(error.into()))?; + let ai = Anthropic::new(settings.anthropic).map_err(loco_rs::Error::wrap)?; + Ok(router + .layer(Extension(ai)) + .layer(middleware::from_fn_with_state(auth, auth::authorize)) + .layer(middleware::from_fn(csrf::protect))) + } + + async fn connect_workers(_ctx: &AppContext, _queue: &Queue) -> Result<()> { + Ok(()) + } + fn register_tasks(_tasks: &mut Tasks) {} + async fn truncate(_ctx: &AppContext) -> Result<()> { + Ok(()) + } + async fn seed(_ctx: &AppContext, _path: &Path) -> Result<()> { + Ok(()) + } +} diff --git a/server/src/controllers/greetings.rs b/server/src/controllers/greetings.rs new file mode 100644 index 0000000..35aa4c9 --- /dev/null +++ b/server/src/controllers/greetings.rs @@ -0,0 +1,38 @@ +use axum::Extension; +use loco_rs::prelude::*; +use sea_orm::{EntityTrait, QueryOrder}; +use serde::Serialize; + +use crate::{models::greetings, services::anthropic::Anthropic}; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +struct Greeting { + name: String, + message: String, + ai_greeting: String, +} + +async fn show( + State(ctx): State, + Extension(ai): Extension, +) -> Result { + let greeting = greetings::Entity::find() + .order_by_asc(greetings::Column::Id) + .one(&ctx.db) + .await? + .ok_or(Error::InternalServerError)?; + let ai_greeting = ai + .greet(&greeting.name, &greeting.message) + .await + .map_err(Error::wrap)?; + format::json(Greeting { + name: greeting.name, + message: greeting.message, + ai_greeting, + }) +} + +pub fn routes() -> Routes { + Routes::at("/api/greeting").get("/", show) +} diff --git a/server/src/controllers/mod.rs b/server/src/controllers/mod.rs new file mode 100644 index 0000000..f62f325 --- /dev/null +++ b/server/src/controllers/mod.rs @@ -0,0 +1 @@ +pub mod greetings; diff --git a/server/src/key_vault.rs b/server/src/key_vault.rs new file mode 100644 index 0000000..d617ffa --- /dev/null +++ b/server/src/key_vault.rs @@ -0,0 +1,54 @@ +use anyhow::{Context, ensure}; +use azure_identity::WorkloadIdentityCredential; +use azure_security_keyvault_secrets::SecretClient; +use loco_rs::config::Config; +use url::Url; + +use crate::settings::Settings; + +pub async fn configure(config: &mut Config) -> anyhow::Result<()> { + let endpoint = + std::env::var("AZURE_KEYVAULT_ENDPOINT").context("AZURE_KEYVAULT_ENDPOINT is required")?; + let client = SecretClient::new(&endpoint, WorkloadIdentityCredential::new(None)?, None)?; + config.database.uri = database_uri( + &secret(&client, "db-url").await?, + &secret(&client, "db-username").await?, + &secret(&client, "db-password").await?, + )?; + let mut settings: Settings = config.settings()?; + settings.oidc.issuer = format!( + "https://login.microsoftonline.com/{}/v2.0", + secret(&client, "tenant-id").await? + ); + settings.oidc.audience = secret(&client, "api-client-id").await?; + settings.anthropic.api_key = secret(&client, "claude-api-key").await?; + config.settings = Some(serde_json::to_value(settings)?); + Ok(()) +} + +async fn secret(client: &SecretClient, name: &str) -> anyhow::Result { + let value = client + .get_secret(name, None) + .await? + .into_model()? + .value + .with_context(|| format!("Key Vault secret {name} is empty"))?; + ensure!(!value.trim().is_empty(), "Key Vault secret {name} is empty"); + Ok(value) +} + +pub fn database_uri(value: &str, username: &str, password: &str) -> anyhow::Result { + // Key Vault owns the connection contract, including separate credentials. + let mut url = Url::parse(value.strip_prefix("jdbc:").unwrap_or(value))?; + ensure!( + matches!(url.scheme(), "postgres" | "postgresql"), + "PostgreSQL URL required" + ); + // URL setters encode delimiters but preserve percent signs; escape those + // first so literal percent-encoded-looking credentials round-trip intact. + url.set_username(&username.replace('%', "%25")) + .map_err(|_| anyhow::anyhow!("Invalid database username"))?; + url.set_password(Some(&password.replace('%', "%25"))) + .map_err(|_| anyhow::anyhow!("Invalid database password"))?; + Ok(url.into()) +} diff --git a/server/src/lib.rs b/server/src/lib.rs new file mode 100644 index 0000000..be8bba8 --- /dev/null +++ b/server/src/lib.rs @@ -0,0 +1,7 @@ +pub mod app; +pub mod controllers; +pub mod key_vault; +pub mod middleware; +pub mod models; +pub mod services; +pub mod settings; diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 0000000..c1aac71 --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,27 @@ +use std::time::Duration; + +use migration::Migrator; +use skeleton_server::app::App; + +#[tokio::main] +async fn main() -> loco_rs::Result<()> { + rustls::crypto::ring::default_provider() + .install_default() + .expect("install TLS provider"); + // Native Podman probe: distroless images have neither curl nor a shell. + if std::env::args().any(|arg| arg == "--healthcheck") { + let port = std::env::var("PORT").unwrap_or_else(|_| "8080".into()); + reqwest::Client::builder() + .timeout(Duration::from_secs(5)) + .build() + .map_err(loco_rs::Error::wrap)? + .get(format!("http://127.0.0.1:{port}/healthz")) + .send() + .await + .map_err(loco_rs::Error::wrap)? + .error_for_status() + .map_err(loco_rs::Error::wrap)?; + return Ok(()); + } + loco_rs::cli::main::().await +} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/SkeletonApplication.java b/server/src/main/java/io/github/mucsi96/skeleton/SkeletonApplication.java deleted file mode 100644 index ab915a8..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/SkeletonApplication.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.mucsi96.skeleton; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.github.mucsi96.skeleton.config.DatabaseStartupInitializer; - -@SpringBootApplication -public class SkeletonApplication { - - public static void main(String[] args) { - final SpringApplication app = new SpringApplication(SkeletonApplication.class); - app.addInitializers(new DatabaseStartupInitializer()); - app.run(args); - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/AIConfiguration.java b/server/src/main/java/io/github/mucsi96/skeleton/config/AIConfiguration.java deleted file mode 100644 index 78866f4..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/AIConfiguration.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import org.springframework.context.annotation.Configuration; - -@Configuration -public class AIConfiguration { -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/AnthropicNativeHints.java b/server/src/main/java/io/github/mucsi96/skeleton/config/AnthropicNativeHints.java deleted file mode 100644 index dad0180..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/AnthropicNativeHints.java +++ /dev/null @@ -1,95 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import java.util.regex.Pattern; - -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportRuntimeHints; - -/** - * Reachability metadata for the Anthropic SDK's request and response models. - * - * The SDK is written in Kotlin, and Spring AI hands its parameter objects to - * the SDK's own Jackson {@code ObjectMapper}, which has - * {@code jackson-module-kotlin} registered. For a Kotlin class that module does - * not read the constructor with plain Java reflection: it asks - * {@code ReflectJvmMapping} to map the Kotlin constructor back to a - * {@code java.lang.reflect.Constructor}. In a native image without metadata - * that mapping finds nothing, and rather than a missing-reflection error it - * fails as - * - *
- * KotlinReflectionInternalError: Could not compute caller for function:
- *     fun <init>(JsonField<Long>, JsonField<List<MessageParam>>, ...)
- * 
- * - * thrown while serializing the request body - so the symptom is every call to - * the model failing at request time, with a stack trace naming Kotlin's - * reflection internals rather than anything that is missing. - * - * Neither the Anthropic SDK nor spring-ai-anthropic ships native-image metadata - * (2.40.1 / 2.0.0), so an application that wants a native image has to register - * it. Whole packages are registered rather than the classes that fail today, - * for the reason given in {@link AzureNativeHints}: the next model the SDK - * reaches for fails the same way, pointing nowhere near its cause. - * {@code com.anthropic.models.beta} is left out deliberately - two thirds of - * the SDK's 10k classes, and nothing here calls the beta API. - * - * The scan reads bytecode rather than loading classes, and skips anonymous and - * lambda classes. Both matter: Spring AI's own - * {@code AiRuntimeHints.findJsonAnnotatedClassesInPackage} helper loads every - * candidate, and loading one of those synthetic classes here - * ({@code SseHandler$mapJson$1$handle$1}) throws - * "This function has a reified type parameter and thus can only be inlined at - * compilation time", which fails the build outright. - * - * Only the native image needs any of this. The AOT-on-JVM run described in - * AGENTS.md cannot show the failure - reflection always works there. - */ -@Configuration(proxyBeanMethods = false) -@ImportRuntimeHints(AnthropicNativeHints.Registrar.class) -public class AnthropicNativeHints { - - static class Registrar implements RuntimeHintsRegistrar { - - private static final String[] PACKAGES = { - "com.anthropic.models.messages", - "com.anthropic.core" - }; - - /** Anonymous and lambda classes: a {@code $} followed by a digit. */ - private static final Pattern SYNTHETIC = Pattern.compile("\\$\\d"); - - @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - final ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider( - false) { - @Override - protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { - // The default rejects abstract types, which is where the SDK puts its - // unions - ContentBlock and friends are needed just as much. - return true; - } - }; - scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> true); - - for (String pkg : PACKAGES) { - for (BeanDefinition definition : scanner.findCandidateComponents(pkg)) { - final String name = definition.getBeanClassName(); - if (name == null || SYNTHETIC.matcher(name).find()) { - continue; - } - hints.reflection().registerTypeIfPresent(classLoader, name, - MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, - MemberCategory.INVOKE_DECLARED_METHODS, - MemberCategory.ACCESS_DECLARED_FIELDS); - } - } - } - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/AzureGlobalPropertiesConfiguration.java b/server/src/main/java/io/github/mucsi96/skeleton/config/AzureGlobalPropertiesConfiguration.java deleted file mode 100644 index 5e0d56f..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/AzureGlobalPropertiesConfiguration.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; - -import com.azure.spring.cloud.autoconfigure.implementation.context.properties.AzureGlobalProperties; - -/** - * Spring Cloud Azure registers its {@code springCloudAzureGlobalProperties} bean - * from an {@code ImportBeanDefinitionRegistrar} that binds the properties in a - * lambda instance supplier. Ahead-of-time processing cannot turn such a supplier - * into generated code, so it drops the bean, and the AOT-processed application - * fails to start with "required a bean of type AzureGlobalProperties that could - * not be found". - * - * This declares the same properties as a plain configuration-properties bean, - * which AOT can generate, under its own name: the registrar reserves - * {@code springCloudAzureGlobalProperties} before AOT processing reaches this - * class, and a bean method losing that race is skipped silently. Everything - * injects {@link AzureGlobalProperties} by type, so with AOT this is the only - * candidate, and without it {@link Primary} picks it over the registrar's. - */ -@Configuration(proxyBeanMethods = false) -public class AzureGlobalPropertiesConfiguration { - - @Bean - @Primary - @ConfigurationProperties(prefix = AzureGlobalProperties.PREFIX) - AzureGlobalProperties appSpringCloudAzureGlobalProperties() { - return new AzureGlobalProperties(); - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/AzureNativeHints.java b/server/src/main/java/io/github/mucsi96/skeleton/config/AzureNativeHints.java deleted file mode 100644 index 71991a9..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/AzureNativeHints.java +++ /dev/null @@ -1,77 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import org.springframework.aot.hint.MemberCategory; -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportRuntimeHints; -import org.springframework.core.type.filter.AssignableTypeFilter; - -import com.azure.core.exception.HttpResponseException; -import com.azure.core.util.ExpandableStringEnum; -import com.azure.json.JsonSerializable; -import com.azure.xml.XmlSerializable; - -/** - * Reachability metadata for the parts of the Azure SDK that its own metadata - * misses. - * - * {@code ExpandableStringEnum} constants are created by - * {@code ExpandableStringEnum.fromString}, which instantiates the subclass - * reflectively and returns {@code null} when it cannot. In a native image - * without a hint that turns every constant of the class into {@code null}, and - * the first use fails with a {@link NullPointerException} far from the cause. - * Two of azure-identity's subclasses ship no metadata, and without them - * building any Azure client fails at startup - but naming those two would - * leave the next one to be rediscovered the same painful way, so they are - * scanned for like everything else here. - * - * The scan covers a second, quieter gap. azure-core picks how to read a - * response body by asking the model class whether it declares the - * {@code fromXml} / {@code fromJson} pair that azure-xml and azure-json - * generate, and it asks with {@code Class.getDeclaredMethods()}. In a native - * image that returns nothing for a class with no reachability metadata, so the - * answer is silently "no" and azure-core falls back to Jackson - which for XML - * means an {@code XmlMapper}, and jackson-dataformat-xml is not on the - * classpath, so the call dies with a {@code NoClassDefFoundError} far from the - * model that caused it. The SDK ships metadata for most of its models but not - * all of them, and the error models carried by exceptions are among the ones it - * misses. Registering every model rather than the handful missing today keeps - * this from having to be rediscovered on the next SDK upgrade. - * - * None of this can be reproduced by the AOT-on-JVM run described in AGENTS.md - - * reflection always works there. It only shows up in the native image. - */ -@Configuration(proxyBeanMethods = false) -@ImportRuntimeHints(AzureNativeHints.Registrar.class) -public class AzureNativeHints { - - static class Registrar implements RuntimeHintsRegistrar { - - private static final String AZURE_PACKAGE = "com.azure"; - - private static final Class[] REFLECTED_TYPES = { - ExpandableStringEnum.class, - XmlSerializable.class, - JsonSerializable.class, - HttpResponseException.class - }; - - @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - final ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider( - false); - - for (Class type : REFLECTED_TYPES) { - scanner.addIncludeFilter(new AssignableTypeFilter(type)); - } - - for (BeanDefinition definition : scanner.findCandidateComponents(AZURE_PACKAGE)) { - hints.reflection().registerTypeIfPresent(classLoader, definition.getBeanClassName(), - MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS); - } - } - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/DatabaseStartupInitializer.java b/server/src/main/java/io/github/mucsi96/skeleton/config/DatabaseStartupInitializer.java deleted file mode 100644 index f316061..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/DatabaseStartupInitializer.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.Arrays; - -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.env.ConfigurableEnvironment; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class DatabaseStartupInitializer implements ApplicationContextInitializer { - - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - final ConfigurableEnvironment environment = applicationContext.getEnvironment(); - - if (Arrays.asList(environment.getActiveProfiles()).contains("local")) { - startDatabase(); - } - } - - private void startDatabase() { - final Path scriptPath = Path.of(System.getProperty("user.dir"), "..", "scripts", "dev_db_up.sh") - .toAbsolutePath().normalize(); - log.info("Starting development database using {}", scriptPath); - - try { - final ProcessBuilder pb = new ProcessBuilder("bash", scriptPath.toString()); - pb.inheritIO(); - final int exitCode = pb.start().waitFor(); - if (exitCode != 0) { - throw new IllegalStateException("dev_db_up.sh failed with exit code " + exitCode); - } - } catch (IOException | InterruptedException e) { - throw new IllegalStateException("Failed to start development database", e); - } - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/KeyVaultPropertySourceNativeHints.java b/server/src/main/java/io/github/mucsi96/skeleton/config/KeyVaultPropertySourceNativeHints.java deleted file mode 100644 index ce91cd5..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/KeyVaultPropertySourceNativeHints.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.RuntimeHintsRegistrar; -import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrar; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportRuntimeHints; - -import com.azure.spring.cloud.autoconfigure.implementation.keyvault.secrets.properties.AzureKeyVaultPropertySourceProperties; -import com.azure.spring.cloud.autoconfigure.implementation.keyvault.secrets.properties.AzureKeyVaultSecretProperties; - -/** - * Binding metadata for the properties behind the Key Vault property source. - * - * {@code KeyVaultEnvironmentPostProcessor} runs before there is an application - * context and reads its own configuration with a plain {@code Binder} over - * {@link AzureKeyVaultSecretProperties}. Nothing in the framework can infer - * that, and the auto-configuration that would otherwise contribute the binding - * metadata for the same type never matches here: it is conditional on - * {@code spring.cloud.azure.keyvault[.secret].endpoint}, while this application - * only configures an endpoint under {@code ...secret.property-sources[0]}. - * - * Without members, {@code JavaBeanBinder} binds nothing, and because an absent - * binding is indistinguishable from an empty configuration the post-processor - * quietly decides there are no property sources to add. The failure surfaces - * only much later, and only in the prod profile, as every secret-backed - * placeholder being unresolvable - {@code ${db-url}} and - * {@code ${claude-api-key}} among them. - * - * Only the prod profile reads secrets from Key Vault, so no test covers this. - * After changing anything about the Key Vault configuration, check that the - * generated - * {@code target/spring-aot/main/resources/META-INF/native-image/**}{@code /reachability-metadata.json} - * still carries both property types with their accessors. To check the hints by - * hand, build the native image and start it with {@code AZURE_KEYVAULT_ENDPOINT} - * pointing at an unreachable host: with the metadata in place the - * post-processor binds the property source and fails on the connection, which - * is the proof it did not skip. Silently reaching the first unresolvable - * placeholder instead means the binding is gone again. The AOT-on-JVM run - * cannot show this - reflection always works there. - */ -@Configuration(proxyBeanMethods = false) -@ImportRuntimeHints(KeyVaultPropertySourceNativeHints.Registrar.class) -public class KeyVaultPropertySourceNativeHints { - - static class Registrar implements RuntimeHintsRegistrar { - - @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { - BindableRuntimeHintsRegistrar - .forTypes(AzureKeyVaultSecretProperties.class, - AzureKeyVaultPropertySourceProperties.class) - .registerHints(hints, classLoader); - } - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/config/SecurityConfiguration.java b/server/src/main/java/io/github/mucsi96/skeleton/config/SecurityConfiguration.java deleted file mode 100644 index 794ce2e..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/config/SecurityConfiguration.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.github.mucsi96.skeleton.config; - -import java.util.Collection; -import java.util.Optional; -import java.util.stream.Stream; - -import jakarta.servlet.DispatcherType; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.ObjectPostProcessor; - -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; -import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.csrf.CookieCsrfTokenRepository; -import org.springframework.security.web.csrf.CsrfFilter; - -@Configuration -@EnableMethodSecurity(prePostEnabled = true) -public class SecurityConfiguration { - - @Bean - SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - - var csrfTokens = CookieCsrfTokenRepository.withHttpOnlyFalse(); - csrfTokens.setCookieName("__Host-XSRF-TOKEN"); - csrfTokens.setCookieCustomizer(cookie -> cookie.path("/").secure(true).sameSite("Lax")); - http.csrf(csrf -> { - csrf.spa().csrfTokenRepository(csrfTokens); - csrf.addObjectPostProcessor(new ObjectPostProcessor() { - @Override - public O postProcess(O filter) { - // Resource-server defaults exempt bearer requests, but our proxy - // derives those credentials from a browser cookie. Protect them too. - filter.setRequireCsrfProtectionMatcher(CsrfFilter.DEFAULT_CSRF_MATCHER); - return filter; - } - }); - }); - http.oauth2ResourceServer(oauth2 -> oauth2 - .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))); - - http.authorizeHttpRequests(requests -> requests - .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() - .requestMatchers("/actuator/**").permitAll() - .anyRequest().hasAuthority("SCOPE_api-access")); - - return http.build(); - } - - private JwtAuthenticationConverter jwtAuthenticationConverter() { - JwtGrantedAuthoritiesConverter scopeConverter = new JwtGrantedAuthoritiesConverter(); - - JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); - converter.setJwtGrantedAuthoritiesConverter(jwt -> Stream.concat( - scopeConverter.convert(jwt).stream(), - Optional.ofNullable(jwt.getClaimAsStringList("roles")) - .stream() - .flatMap(Collection::stream) - .map(role -> new SimpleGrantedAuthority("APPROLE_" + role))) - .toList()); - return converter; - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/controller/GreetingController.java b/server/src/main/java/io/github/mucsi96/skeleton/controller/GreetingController.java deleted file mode 100644 index 2b06de7..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/controller/GreetingController.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.github.mucsi96.skeleton.controller; - -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import io.github.mucsi96.skeleton.model.GreetingResponse; -import io.github.mucsi96.skeleton.service.GreetingService; -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -public class GreetingController { - private final GreetingService greetingService; - - @GetMapping("/greeting") - @PreAuthorize("hasAuthority('APPROLE_readGreetings')") - public GreetingResponse getGreeting() { - return greetingService.getGreeting(); - } -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/entity/Greeting.java b/server/src/main/java/io/github/mucsi96/skeleton/entity/Greeting.java deleted file mode 100644 index 3440b59..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/entity/Greeting.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.github.mucsi96.skeleton.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "greetings", schema = "hello") -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class Greeting { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false) - private String name; - - @Column(nullable = false) - private String message; -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/model/GreetingResponse.java b/server/src/main/java/io/github/mucsi96/skeleton/model/GreetingResponse.java deleted file mode 100644 index 74c9c80..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/model/GreetingResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.github.mucsi96.skeleton.model; - -public record GreetingResponse( - String name, - String message, - String aiGreeting) { -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/repository/GreetingRepository.java b/server/src/main/java/io/github/mucsi96/skeleton/repository/GreetingRepository.java deleted file mode 100644 index a56c710..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/repository/GreetingRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.github.mucsi96.skeleton.repository; - -import org.springframework.data.jpa.repository.JpaRepository; - -import io.github.mucsi96.skeleton.entity.Greeting; - -public interface GreetingRepository extends JpaRepository { -} diff --git a/server/src/main/java/io/github/mucsi96/skeleton/service/GreetingService.java b/server/src/main/java/io/github/mucsi96/skeleton/service/GreetingService.java deleted file mode 100644 index 7802cd4..0000000 --- a/server/src/main/java/io/github/mucsi96/skeleton/service/GreetingService.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.github.mucsi96.skeleton.service; - -import java.util.List; - -import org.springframework.ai.anthropic.AnthropicChatModel; -import org.springframework.ai.chat.messages.SystemMessage; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.stereotype.Service; - -import io.github.mucsi96.skeleton.entity.Greeting; -import io.github.mucsi96.skeleton.model.GreetingResponse; -import io.github.mucsi96.skeleton.repository.GreetingRepository; -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class GreetingService { - private final GreetingRepository greetingRepository; - private final AnthropicChatModel chatModel; - - public GreetingResponse getGreeting() { - Greeting greeting = greetingRepository.findAll().stream() - .findFirst() - .orElseThrow(() -> new RuntimeException("No greeting found in database")); - - String aiGreeting = generateAiGreeting(greeting.getName(), greeting.getMessage()); - - return new GreetingResponse(greeting.getName(), greeting.getMessage(), aiGreeting); - } - - private String generateAiGreeting(String name, String message) { - Prompt prompt = new Prompt(List.of( - new SystemMessage("You are a friendly assistant. Generate a short, warm greeting."), - new UserMessage("Greet " + name + " with the following context: " + message))); - - return chatModel.call(prompt).getResult().getOutput().getText(); - } -} diff --git a/server/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/server/src/main/resources/META-INF/additional-spring-configuration-metadata.json deleted file mode 100644 index 223476a..0000000 --- a/server/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "properties": [] -} diff --git a/server/src/main/resources/application-local.yml b/server/src/main/resources/application-local.yml deleted file mode 100644 index 5050d9c..0000000 --- a/server/src/main/resources/application-local.yml +++ /dev/null @@ -1,10 +0,0 @@ -spring: - datasource: - url: jdbc:postgresql://localhost:5450/skeleton - username: postgres - password: postgres -server: - port: 8053 -management: - server: - port: 8152 diff --git a/server/src/main/resources/application-test.yml b/server/src/main/resources/application-test.yml deleted file mode 100644 index 04e4233..0000000 --- a/server/src/main/resources/application-test.yml +++ /dev/null @@ -1,17 +0,0 @@ -spring: - cloud: - azure: - keyvault: - secret: - property-sources: - - enabled: false - security: - oauth2: - resourceserver: - jwt: - issuer-uri: http://localhost:8050/default - audiences: mock-api-client-id - ai: - anthropic: - api-key: ${ANTHROPIC_API_KEY} - base-url: ${ANTHROPIC_BASE_URL} diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml deleted file mode 100644 index 04a90d1..0000000 --- a/server/src/main/resources/application.yml +++ /dev/null @@ -1,53 +0,0 @@ -spring: - datasource: - url: ${db-url} - username: ${db-username} - password: ${db-password} - driver-class-name: org.postgresql.Driver - hikari: - connection-init-sql: CREATE SCHEMA IF NOT EXISTS hello - jpa: - hibernate: - ddl-auto: none - properties: - hibernate: - show-sql: true - liquibase: - change-log: classpath:db/changelog/db.changelog-master.yaml - default-schema: hello - liquibase-schema: hello - cloud: - azure: - keyvault: - secret: - property-sources: - - endpoint: ${AZURE_KEYVAULT_ENDPOINT} - enabled: true - security: - oauth2: - resourceserver: - jwt: - issuer-uri: https://login.microsoftonline.com/${tenant-id:}/v2.0 - audiences: ${api-client-id:} - ai: - anthropic: - api-key: ${claude-api-key} - chat: - options: - model: claude-sonnet-4-6 -server: - forward-headers-strategy: framework - servlet: - context-path: /api -management: - server: - port: ${SPRING_ACTUATOR_PORT} - endpoints: - web: - exposure: - include: "*" - endpoint: - health: - show-details: always - probes: - enabled: true diff --git a/server/src/main/resources/db/changelog/db.changelog-master.yaml b/server/src/main/resources/db/changelog/db.changelog-master.yaml deleted file mode 100644 index 39a75c0..0000000 --- a/server/src/main/resources/db/changelog/db.changelog-master.yaml +++ /dev/null @@ -1,37 +0,0 @@ -databaseChangeLog: - - changeSet: - id: 1-create-greetings-table - author: mucsi96 - changes: - - createTable: - tableName: greetings - columns: - - column: - name: id - type: bigint - autoIncrement: true - constraints: - primaryKey: true - - column: - name: name - type: text - constraints: - nullable: false - - column: - name: message - type: text - constraints: - nullable: false - - changeSet: - id: 2-seed-initial-greeting - author: mucsi96 - changes: - - insert: - tableName: greetings - columns: - - column: - name: name - value: Igor - - column: - name: message - value: Welcome to the skeleton app! diff --git a/server/src/middleware/auth.rs b/server/src/middleware/auth.rs new file mode 100644 index 0000000..bab1dc9 --- /dev/null +++ b/server/src/middleware/auth.rs @@ -0,0 +1,150 @@ +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; + +use anyhow::ensure; +use axum::{ + extract::{Request, State}, + http::{StatusCode, header}, + middleware::Next, + response::Response, +}; +use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode, decode_header, jwk::JwkSet}; +use serde::Deserialize; +use tokio::sync::Mutex; + +#[derive(Clone)] +pub struct Auth(Arc); + +struct Inner { + issuer: String, + audience: String, + jwks_url: String, + client: reqwest::Client, + keys: Mutex<(Instant, JwkSet)>, +} + +#[derive(Deserialize)] +struct Discovery { + issuer: String, + jwks_uri: String, +} + +#[derive(Clone, Deserialize)] +struct Claims { + #[serde(default)] + scp: String, + #[serde(default)] + roles: Vec, +} + +pub fn validate_endpoint(value: &str) -> anyhow::Result<()> { + let url = url::Url::parse(value)?; + let local = matches!(url.host_str(), Some("127.0.0.1" | "localhost" | "[::1]")); + ensure!( + url.scheme() == "https" || (url.scheme() == "http" && local), + "OIDC requires HTTPS or loopback HTTP" + ); + ensure!( + url.username().is_empty() + && url.password().is_none() + && url.fragment().is_none() + && url.query().is_none(), + "invalid OIDC endpoint" + ); + Ok(()) +} + +impl Auth { + pub async fn new(issuer: String, audience: String) -> anyhow::Result { + validate_endpoint(&issuer)?; + ensure!(!audience.trim().is_empty(), "API audience is required"); + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .redirect(reqwest::redirect::Policy::none()) + .build()?; + let discovery: Discovery = client + .get(format!("{issuer}/.well-known/openid-configuration")) + .send() + .await? + .error_for_status()? + .json() + .await?; + ensure!(discovery.issuer == issuer, "OIDC issuer mismatch"); + validate_endpoint(&discovery.jwks_uri)?; + let keys = client + .get(&discovery.jwks_uri) + .send() + .await? + .error_for_status()? + .json() + .await?; + Ok(Self(Arc::new(Inner { + issuer, + audience, + jwks_url: discovery.jwks_uri, + client, + keys: Mutex::new((Instant::now(), keys)), + }))) + } + + async fn verify(&self, token: &str) -> Result<(), StatusCode> { + let header = decode_header(token).map_err(|_| StatusCode::UNAUTHORIZED)?; + if header.alg != Algorithm::RS256 { + return Err(StatusCode::UNAUTHORIZED); + } + let kid = header.kid.ok_or(StatusCode::UNAUTHORIZED)?; + let mut cache = self.0.keys.lock().await; + // Refresh at a bounded rate, including for unknown signing key IDs. + if cache.0.elapsed() >= Duration::from_secs(300) { + let keys = self + .0 + .client + .get(&self.0.jwks_url) + .send() + .await + .map_err(|_| StatusCode::SERVICE_UNAVAILABLE)? + .error_for_status() + .map_err(|_| StatusCode::SERVICE_UNAVAILABLE)? + .json() + .await + .map_err(|_| StatusCode::SERVICE_UNAVAILABLE)?; + *cache = (Instant::now(), keys); + } + let jwk = cache.1.find(&kid).ok_or(StatusCode::UNAUTHORIZED)?; + let key = DecodingKey::from_jwk(jwk).map_err(|_| StatusCode::UNAUTHORIZED)?; + drop(cache); + let mut validation = Validation::new(Algorithm::RS256); + validation.set_issuer(&[&self.0.issuer]); + validation.set_audience(&[&self.0.audience]); + validation.validate_nbf = true; + let claims = decode::(token, &key, &validation) + .map_err(|_| StatusCode::UNAUTHORIZED)? + .claims; + if !claims.scp.split_whitespace().any(|s| s == "api-access") + || !claims.roles.iter().any(|r| r == "readGreetings") + { + return Err(StatusCode::FORBIDDEN); + } + Ok(()) + } +} + +pub async fn authorize( + State(auth): State, + request: Request, + next: Next, +) -> Result { + if request.uri().path() == "/healthz" { + return Ok(next.run(request).await); + } + let token = request + .headers() + .get(header::AUTHORIZATION) + .and_then(|v| v.to_str().ok()) + .and_then(|v| v.strip_prefix("Bearer ")) + .ok_or(StatusCode::UNAUTHORIZED)?; + auth.verify(token).await?; + Ok(next.run(request).await) +} diff --git a/server/src/middleware/csrf.rs b/server/src/middleware/csrf.rs new file mode 100644 index 0000000..1aae2aa --- /dev/null +++ b/server/src/middleware/csrf.rs @@ -0,0 +1,47 @@ +use axum::{ + extract::Request, + http::{Method, StatusCode, header}, + middleware::Next, + response::Response, +}; + +// Host-only Secure cookies cannot be planted by sibling subdomains. Require +// double-submit proof even when the gateway supplies a bearer access token. +pub async fn protect(request: Request, next: Next) -> Result { + let cookie = request + .headers() + .get_all(header::COOKIE) + .iter() + .filter_map(|v| v.to_str().ok()) + .flat_map(|v| v.split(';')) + .find_map(|v| v.trim().strip_prefix("__Host-XSRF-TOKEN=")) + .filter(|v| uuid::Uuid::parse_str(v).is_ok()) + .map(str::to_owned); + let safe = matches!( + *request.method(), + Method::GET | Method::HEAD | Method::OPTIONS | Method::TRACE + ); + if !safe + && !cookie.as_ref().is_some_and(|value| { + request + .headers() + .get("X-XSRF-TOKEN") + .is_some_and(|header| header.as_bytes() == value.as_bytes()) + }) + { + return Err(StatusCode::FORBIDDEN); + } + let mut response = next.run(request).await; + if cookie.is_none() { + response.headers_mut().append( + header::SET_COOKIE, + format!( + "__Host-XSRF-TOKEN={}; Path=/; Secure; SameSite=Lax", + uuid::Uuid::new_v4() + ) + .parse() + .expect("UUID cookie is a valid header"), + ); + } + Ok(response) +} diff --git a/server/src/middleware/mod.rs b/server/src/middleware/mod.rs new file mode 100644 index 0000000..3909958 --- /dev/null +++ b/server/src/middleware/mod.rs @@ -0,0 +1,2 @@ +pub mod auth; +pub mod csrf; diff --git a/server/src/models/greetings.rs b/server/src/models/greetings.rs new file mode 100644 index 0000000..1e3dd0c --- /dev/null +++ b/server/src/models/greetings.rs @@ -0,0 +1,15 @@ +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(schema_name = "hello", table_name = "greetings")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i64, + pub name: String, + pub message: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/server/src/models/mod.rs b/server/src/models/mod.rs new file mode 100644 index 0000000..f62f325 --- /dev/null +++ b/server/src/models/mod.rs @@ -0,0 +1 @@ +pub mod greetings; diff --git a/server/src/services/anthropic.rs b/server/src/services/anthropic.rs new file mode 100644 index 0000000..4099891 --- /dev/null +++ b/server/src/services/anthropic.rs @@ -0,0 +1,71 @@ +use std::time::Duration; + +use serde::Deserialize; + +use crate::settings::Anthropic as Settings; + +#[derive(Clone)] +pub struct Anthropic { + client: reqwest::Client, + settings: Settings, +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Anthropic request failed")] + Request(#[from] reqwest::Error), + #[error("Anthropic response has no text")] + EmptyResponse, +} + +#[derive(Deserialize)] +struct Message { + content: Vec, +} + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +enum Content { + Text { + text: String, + }, + #[serde(other)] + Other, +} + +impl Anthropic { + pub fn new(settings: Settings) -> Result { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(settings.timeout_seconds)) + .redirect(reqwest::redirect::Policy::none()) + .build()?; + Ok(Self { client, settings }) + } + + pub async fn greet(&self, name: &str, message: &str) -> Result { + let response: Message = self.client + .post(format!("{}/v1/messages", self.settings.base_url.trim_end_matches('/'))) + .header("x-api-key", &self.settings.api_key) + .header("anthropic-version", "2023-06-01") + .json(&serde_json::json!({ + "model": self.settings.model, + "max_tokens": self.settings.max_tokens, + "system": "You are a friendly assistant. Generate a short, warm greeting.", + "messages": [{"role": "user", "content": format!("Greet {name} with the following context: {message}")}] + })) + .send().await?.error_for_status()?.json().await?; + let text = response + .content + .into_iter() + .filter_map(|block| match block { + Content::Text { text } => Some(text), + Content::Other => None, + }) + .collect::>() + .join(""); + if text.trim().is_empty() { + return Err(Error::EmptyResponse); + } + Ok(text) + } +} diff --git a/server/src/services/mod.rs b/server/src/services/mod.rs new file mode 100644 index 0000000..e529997 --- /dev/null +++ b/server/src/services/mod.rs @@ -0,0 +1 @@ +pub mod anthropic; diff --git a/server/src/settings.rs b/server/src/settings.rs new file mode 100644 index 0000000..caacfb1 --- /dev/null +++ b/server/src/settings.rs @@ -0,0 +1,48 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Settings { + pub oidc: Oidc, + pub anthropic: Anthropic, +} + +#[derive(Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Oidc { + pub issuer: String, + pub audience: String, +} + +#[derive(Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Anthropic { + pub base_url: String, + pub api_key: String, + pub model: String, + pub max_tokens: u32, + pub timeout_seconds: u64, +} + +impl Settings { + pub fn validate(&self) -> anyhow::Result<()> { + anyhow::ensure!( + [ + &self.oidc.issuer, + &self.oidc.audience, + &self.anthropic.api_key, + &self.anthropic.model + ] + .iter() + .all(|value| !value.trim().is_empty()), + "OIDC issuer/audience and Anthropic key/model must not be empty" + ); + anyhow::ensure!( + self.anthropic.max_tokens > 0 && self.anthropic.timeout_seconds > 0, + "Anthropic limits must be positive" + ); + crate::middleware::auth::validate_endpoint(&self.oidc.issuer)?; + crate::middleware::auth::validate_endpoint(&self.anthropic.base_url)?; + Ok(()) + } +} diff --git a/test/fixtures.ts b/test/fixtures.ts index ef2b0a1..343d21a 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -3,8 +3,7 @@ import { writeFileSync, mkdirSync } from 'fs'; import { join } from 'path'; import { cleanupDbRecords, insertGreeting } from './utils'; -export const test = base.extend<{ apiHeaders: Record; clientLogUrl: string }>({ - clientLogUrl: ['', { option: true }], +export const test = base.extend<{ apiHeaders: Record }>({ apiHeaders: async ({ request }, use) => { const issuer = process.env.TEST_OAUTH2_URL ?? 'http://localhost:8050'; const redirect = 'http://localhost/test'; @@ -19,26 +18,14 @@ export const test = base.extend<{ apiHeaders: Record; clientLogU if (!tokens.ok()) throw new Error(`Mock token request failed: ${tokens.status()}`); await use({ Authorization: `Bearer ${(await tokens.json()).access_token}` }); }, - page: async ({ page, apiHeaders, clientLogUrl }, use, testInfo: TestInfo) => { + page: async ({ page, apiHeaders }, use, testInfo: TestInfo) => { await cleanupDbRecords(); await insertGreeting('World', 'Welcome to the skeleton app!'); // Stand in for the gateway's verified identity; no proxy/session stack in app tests. await page.route('**/api/**', route => route.continue({ headers: { ...route.request().headers(), ...apiHeaders } })); await page.route('**/oauth2/userinfo', route => route.fulfill({ json: { email: 'owner@example.test', additionalClaims: { name: 'Owner' } } })); - await page.route('https://fonts.googleapis.com/**', route => route.abort()); - await page.route('https://fonts.gstatic.com/**', route => route.abort()); - await page.route('**/*', async route => { - if (!route.request().isNavigationRequest()) return route.fallback(); - const response = await route.fetch(); - const body = (await response.text()).replace(/["']__APP_CONFIG_JSON__["']/, JSON.stringify({ - clientLogUrl, clientAppName: 'hello-client', - })); - const headers = { ...response.headers() }; - delete headers['content-length']; - delete headers['content-encoding']; - await route.fulfill({ response, headers, body }); - }); + await page.route('**/_telemetry/collect', route => route.fulfill({ status: 202, body: 'ok' })); // Reset mock AI server try { diff --git a/test/package-lock.json b/test/package-lock.json index 1a67f77..a8daf0e 100644 --- a/test/package-lock.json +++ b/test/package-lock.json @@ -8,21 +8,21 @@ "name": "skeleton-app-tests", "version": "1.0.0", "devDependencies": { - "@playwright/test": "1.64.0", - "@types/node": "26.6.5", + "@playwright/test": "1.64.1", + "@types/node": "26.6.6", "@types/pg": "8.23.1", "pg": "8.23.1", "typescript": "7.0.2" } }, "node_modules/@playwright/test": { - "version": "1.64.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.0.tgz", - "integrity": "sha512-oTN9FNYuN6bqQMwiho6jJKLCG2/QOYCixGXuCjRmzOq23eODeukuY2XiAVoVpAECbuezMt1MHQjAiQxK8F+Y+g==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.1.tgz", + "integrity": "sha512-IaYGml/nSOiZWROfPtuIL7neuu9qDOZ3TNvNljUIrhDMxiGTgPjzj/g9p9RxpS2tSepPDRY+UwAaEeiKtUvIAg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.64.0" + "playwright": "1.64.1" }, "bin": { "playwright": "cli.js" @@ -32,9 +32,9 @@ } }, "node_modules/@types/node": { - "version": "26.6.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", - "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "version": "26.6.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz", + "integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==", "dev": true, "license": "MIT", "dependencies": { @@ -491,13 +491,13 @@ } }, "node_modules/playwright": { - "version": "1.64.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.0.tgz", - "integrity": "sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.1.tgz", + "integrity": "sha512-HCrVhHr5QQuwYoswEUGTb7gGp522yflbv/ST8nF4sFWGuLjQCt17Q/EubpGGSNKYn1tsTCPZxqHhHCfVURu7UA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.64.0" + "playwright-core": "1.64.1" }, "bin": { "playwright": "cli.js" @@ -507,9 +507,9 @@ } }, "node_modules/playwright-core": { - "version": "1.64.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.0.tgz", - "integrity": "sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==", + "version": "1.64.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.1.tgz", + "integrity": "sha512-BC4s8y6SEVA6Q1rSxZTto8hI1KUI3xXlHGZgvGqP4IqPdI/a6FX9H29IDNz7vKo9l21b6LfYosScPL6M3xxyDQ==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/test/package.json b/test/package.json index 7d412fb..914f453 100644 --- a/test/package.json +++ b/test/package.json @@ -10,8 +10,8 @@ "test:debug": "playwright test --debug" }, "devDependencies": { - "@playwright/test": "1.64.0", - "@types/node": "26.6.5", + "@playwright/test": "1.64.1", + "@types/node": "26.6.6", "@types/pg": "8.23.1", "pg": "8.23.1", "typescript": "7.0.2" diff --git a/test/static-assets.mjs b/test/static-assets.mjs new file mode 100644 index 0000000..756662a --- /dev/null +++ b/test/static-assets.mjs @@ -0,0 +1,64 @@ +import assert from 'node:assert/strict'; +import { chromium, expect } from '@playwright/test'; + +const [appOrigin, assetBaseUrl] = process.argv.slice(2); +const browser = await chromium.launch(); +try { + const context = await browser.newContext(); + await context.addCookies([{ name: 'fixture-session', value: 'private', url: appOrigin }]); + const page = await context.newPage(); + const assets = []; + const errors = []; + page.on('pageerror', error => errors.push(error.message)); + page.on('request', request => { + if (['script', 'stylesheet', 'font', 'image', 'manifest'].includes(request.resourceType())) { + assets.push(request.url()); + } + }); + await page.route('**/_telemetry/collect', route => route.fulfill({ status: 202, json: {} })); + const telemetry = page.waitForRequest(request => request.url() === `${appOrigin}/_telemetry/collect` && request.method() === 'POST'); + await page.goto(`${appOrigin}/?source=bookmark`); + assert.equal((await telemetry).postDataJSON().meta.app.name, 'hello-client'); + assert.equal(await page.evaluate(() => '__APP_CONFIG__' in window), false); + await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); + await page.evaluate(() => document.fonts.ready); + await page.evaluate(async () => { + for (const font of ['400 16px Roboto']) { + if (!(await document.fonts.load(font)).length) throw new Error(`Missing bundled font: ${font}`); + } + }); + await page.reload(); + await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); + assert.equal(await page.evaluate(() => document.baseURI), `${appOrigin}/`); + assert.deepEqual(errors, []); + + const manifest = await page.evaluate(async () => { + const url = document.querySelector('link[rel="manifest"]').href; + return (await fetch(url, { credentials: 'omit' })).json(); + }); + for (const field of ['id', 'scope', 'start_url']) assert.equal(manifest[field], `${appOrigin}/`); + await page.evaluate(url => new Promise((resolve, reject) => { + const image = new Image(); + image.onload = resolve; + image.onerror = reject; + image.src = url; + }), new URL(manifest.icons[0].src, `${assetBaseUrl}manifest.webmanifest`).href); + + for (const suffix of ['.js', '.css', '.woff2', '.png']) { + assert(assets.some(url => url.endsWith(suffix)), `No ${suffix} request was exercised`); + } + assert(assets.some(url => /\/chunk-.*\.js$/.test(url)), 'Lazy/ES module chunks must load from storage'); + assert(assets.every(url => url.startsWith(assetBaseUrl)), `Assets escaped the storage origin: ${assets}`); + + const deepLink = await page.request.get(`${appOrigin}/teams/acme/settings?tab=profile`, { headers: { Accept: 'text/html' } }); + assert.equal(deepLink.status(), 200); + assert((await deepLink.text()).includes(assetBaseUrl)); + const missing = await page.evaluate(async url => (await fetch(url)).status, `${assetBaseUrl}missing.js`); + assert.equal(missing, 404); + const corsBlocked = await page.evaluate(async url => { + try { await fetch(url); return false; } catch { return true; } + }, `${assets.find(url => url.endsWith('.js'))}?no-cors`); + assert(corsBlocked, 'The browser must enforce CORS for cross-origin assets'); +} finally { + await browser.close(); +} diff --git a/test/test-pod.yaml b/test/test-pod.yaml index d9b489f..5460c77 100644 --- a/test/test-pod.yaml +++ b/test/test-pod.yaml @@ -95,36 +95,37 @@ spec: - name: server image: localhost/skeleton-app-server:test env: - - name: SERVER_PORT + - name: LOCO_ENV + value: test + - name: PORT value: "8054" - - name: SPRING_ACTUATOR_PORT - value: "8152" - - name: DB_URL - value: jdbc:postgresql://localhost:5432/test - - name: DB_USERNAME - value: postgres - - name: DB_PASSWORD - value: postgres + - name: DATABASE_URL + value: postgres://postgres:postgres@localhost:5432/test - name: ANTHROPIC_API_KEY value: mock-anthropic-key - name: ANTHROPIC_BASE_URL value: http://localhost:3050 - - name: MOCK_OAUTH2_SERVER_URI - value: http://localhost:8050 + - name: OIDC_ISSUER + value: http://localhost:8050/default + - name: API_CLIENT_ID + value: mock-api-client-id livenessProbe: - httpGet: - path: /actuator/health/readiness - port: 8152 - # The native executable is serving within a second of the container - # starting, so there is nothing to wait for before the first probe. The - # window stays generous because readiness still waits for the db - # container and the Liquibase migration. + exec: + command: ["/app/skeleton-server", "--healthcheck"] + # Readiness waits for the database migration and OIDC discovery. initialDelaySeconds: 2 periodSeconds: 2 failureThreshold: 30 - name: client - image: localhost/skeleton-app-client:test + image: docker.io/library/nginx:1.31.7 + volumeMounts: + - name: client-dist + mountPath: /usr/share/nginx/html + readOnly: true + - name: client-nginx-config + mountPath: /etc/nginx/conf.d/default.conf + readOnly: true livenessProbe: httpGet: path: /index.html @@ -134,6 +135,14 @@ spec: failureThreshold: 10 volumes: + - name: client-dist + hostPath: + path: client/dist + type: Directory + - name: client-nginx-config + hostPath: + path: client/nginx.conf + type: File - name: traefik-config hostPath: path: test/traefik.yaml diff --git a/test/tests/bootstrap.spec.ts b/test/tests/bootstrap.spec.ts index 4be07c9..d1eccf8 100644 --- a/test/tests/bootstrap.spec.ts +++ b/test/tests/bootstrap.spec.ts @@ -13,11 +13,13 @@ test('document authentication redirects before any SPA scripts are loaded', asyn test('API validates bearer tokens', async ({ page, request, apiHeaders }) => { expect((await request.get('/api/greeting')).status()).toBe(401); expect((await request.get('/api/greeting', { headers: { Authorization: 'Bearer forged' } })).status()).toBe(401); - expect((await request.get('/api/greeting', { headers: apiHeaders })).status()).toBe(200); + const greeting = await request.get('/api/greeting', { headers: apiHeaders }); + expect(greeting.status()).toBe(200); + expect(greeting.headers()['cache-control']).toContain('no-store'); expect((await request.get('/api/environment', { headers: apiHeaders })).status()).toBe(404); }); -test('Spring CSRF protection requires the cookie and matching header even with a bearer token', async ({ page, context, request, apiHeaders }) => { +test('CSRF protection requires the cookie and matching header even with a bearer token', async ({ page, context, request, apiHeaders }) => { await page.goto('/'); await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); const cookie = (await context.cookies()).find(value => value.name === '__Host-XSRF-TOKEN'); diff --git a/test/tests/caching.spec.ts b/test/tests/caching.spec.ts index 6c06b97..4505f0b 100644 --- a/test/tests/caching.spec.ts +++ b/test/tests/caching.spec.ts @@ -27,7 +27,7 @@ test('serves hashed bundles with long-lived immutable caching', async ({ request ); expect(bundlePaths.length).toBeGreaterThan(0); - const responses = await Promise.all(bundlePaths.map((path) => request.get(`/${path}`))); + const responses = await Promise.all(bundlePaths.map((path) => request.get(new URL(path, 'http://localhost:8150/').href))); responses.forEach((response) => { expect(response.headers()['cache-control']).toContain('immutable'); }); diff --git a/test/tests/faro.spec.ts b/test/tests/faro.spec.ts index e24e6b2..c0060a4 100644 --- a/test/tests/faro.spec.ts +++ b/test/tests/faro.spec.ts @@ -1,7 +1,5 @@ import { test, expect } from '../fixtures'; -test.use({ clientLogUrl: `${process.env.TEST_BASE_URL ?? 'http://localhost:8150'}/_telemetry/collect` }); - test('sends Faro telemetry on the app origin without a CORS preflight', async ({ page }) => { const methods: string[] = []; await page.route('**/_telemetry/collect', async route => { @@ -13,6 +11,7 @@ test('sends Faro telemetry on the app origin without a CORS preflight', async ({ await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); const response = await delivered; expect(response.status()).toBe(202); + expect(response.request().postDataJSON().meta.app.name).toBe('hello-client'); expect(new URL(response.url()).origin).toBe(new URL(page.url()).origin); expect(methods).not.toContain('OPTIONS'); }); diff --git a/test/tests/home-page.spec.ts b/test/tests/home-page.spec.ts index d5f2a50..4f56c0a 100644 --- a/test/tests/home-page.spec.ts +++ b/test/tests/home-page.spec.ts @@ -34,5 +34,24 @@ test('displays greeting message from database', async ({ page }) => { test('displays AI-generated greeting', async ({ page }) => { await page.goto('/'); - await expect(page.getByText('Hello World!')).toBeVisible(); + await expect(page.getByText('Hello World!', { exact: false })).toBeVisible(); +}); + +test('shows a skeleton while greeting loads', async ({ page }) => { + let release!: () => void; + const held = new Promise(resolve => { release = resolve; }); + await page.route('**/api/greeting', async route => { await held; await route.fallback(); }); + await page.goto('/'); + await expect(page.getByRole('status', { name: 'Loading greeting' })).toBeVisible(); + release(); + await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); +}); + +test('shows a recoverable error instead of an empty greeting', async ({ page }) => { + await page.route('**/api/greeting', route => route.fulfill({ status: 503, json: {} })); + await page.goto('/'); + await expect(page.getByText('Unable to load greeting.')).toBeVisible(); + await page.unroute('**/api/greeting'); + await page.getByRole('button', { name: 'Try again' }).click(); + await expect(page.getByRole('heading', { name: 'Welcome, World' })).toBeVisible(); });