From 7454a59ec45bf60b989da06e74542be2ec75da7f Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 15:28:33 +0200 Subject: [PATCH 01/22] feat(web): add environment management workflow --- .github/workflows/ci.yml | 5 + .github/workflows/setup-smoke.yml | 11 +- DEVELOPMENT.md | 35 + package.json | 10 +- pnpm-lock.yaml | 1828 +++++++++++++++++++++++++- scripts/lint-all.sh | 2 +- scripts/typecheck-all.sh | 3 +- scripts/web-env/adapters.test.ts | 210 +++ scripts/web-env/apply.test.ts | 116 ++ scripts/web-env/apply.ts | 82 ++ scripts/web-env/backfill-report.ts | 38 + scripts/web-env/backfill.test.ts | 22 + scripts/web-env/backfill.ts | 199 +++ scripts/web-env/command.ts | 72 + scripts/web-env/dotenv-files.test.ts | 131 ++ scripts/web-env/dotenv-files.ts | 289 ++++ scripts/web-env/index.ts | 314 +++++ scripts/web-env/json.ts | 43 + scripts/web-env/onepassword.ts | 180 +++ scripts/web-env/plan.test.ts | 56 + scripts/web-env/plan.ts | 84 ++ scripts/web-env/prompts.test.ts | 47 + scripts/web-env/prompts.ts | 177 +++ scripts/web-env/resume.test.ts | 30 + scripts/web-env/resume.ts | 80 ++ scripts/web-env/tsconfig.json | 12 + scripts/web-env/vercel.ts | 233 ++++ 27 files changed, 4250 insertions(+), 59 deletions(-) create mode 100644 scripts/web-env/adapters.test.ts create mode 100644 scripts/web-env/apply.test.ts create mode 100644 scripts/web-env/apply.ts create mode 100644 scripts/web-env/backfill-report.ts create mode 100644 scripts/web-env/backfill.test.ts create mode 100644 scripts/web-env/backfill.ts create mode 100644 scripts/web-env/command.ts create mode 100644 scripts/web-env/dotenv-files.test.ts create mode 100644 scripts/web-env/dotenv-files.ts create mode 100644 scripts/web-env/index.ts create mode 100644 scripts/web-env/json.ts create mode 100644 scripts/web-env/onepassword.ts create mode 100644 scripts/web-env/plan.test.ts create mode 100644 scripts/web-env/plan.ts create mode 100644 scripts/web-env/prompts.test.ts create mode 100644 scripts/web-env/prompts.ts create mode 100644 scripts/web-env/resume.test.ts create mode 100644 scripts/web-env/resume.ts create mode 100644 scripts/web-env/tsconfig.json create mode 100644 scripts/web-env/vercel.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e284c7cd4..aa42df7f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,10 @@ jobs: filters: | kilocode_backend: - 'apps/web/src/**' + - 'apps/web/.env' + - 'apps/web/.env.test' + - 'apps/web/.env.development.local.example' + - '.env.local.example' - 'apps/web/package.json' - 'apps/web/tsconfig.json' - 'apps/web/tsconfig.*.json' @@ -59,6 +63,7 @@ jobs: - 'packages/trpc/**' - 'packages/worker-utils/**' - 'services/deploy-infra/builder/**' + - 'scripts/web-env/**' - 'package.json' - 'pnpm-lock.yaml' cloud_agent: diff --git a/.github/workflows/setup-smoke.yml b/.github/workflows/setup-smoke.yml index 2f46dd0d0..8d9b115f2 100644 --- a/.github/workflows/setup-smoke.yml +++ b/.github/workflows/setup-smoke.yml @@ -4,6 +4,15 @@ on: schedule: - cron: '17 * * * *' workflow_dispatch: + pull_request: + branches: [main] + paths: + - '.env.local.example' + - 'apps/web/.env' + - 'apps/web/.env.development.local.example' + - 'dev/local/**' + - 'scripts/dev.sh' + - '.github/workflows/setup-smoke.yml' permissions: contents: read @@ -147,7 +156,7 @@ jobs: retention-days: 7 - name: Notify setup smoke failure - if: failure() + if: failure() && github.event_name != 'pull_request' env: GH_TOKEN: ${{ github.token }} ISSUE_NUMBER: '3791' diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 9dff2cebc..f39b0b717 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -150,6 +150,41 @@ The setup covers: `NEXTAUTH_SECRET`, `NEXTAUTH_URL`, `POSTGRES_URL`, `CALLBACK_T These changes will allow you to do local testing with a fake account. +#### c. Add or rotate shared web environment variables + +Use the repository workflow instead of editing Vercel projects independently. It updates `kilocode-app` and `kilocode-global-app` together for Development, Staging, and Production: + +```bash +pnpm web:env add EXAMPLE_API_TOKEN +pnpm web:env update EXAMPLE_API_TOKEN +``` + +Prerequisites: + +- Sign in with `vercel login` and have access to both projects in the `kilocode` scope. +- Sign in with `op signin` and have write access to the `Kilo Web ENV Production` vault. +- Run `pnpm install` so the repository-pinned Vercel CLI is available. + +Variables are sensitive by default. Production and Staging become Vercel-sensitive, while the separate Development value remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. + +For public or otherwise non-secret configuration, opt out explicitly: + +```bash +pnpm web:env add EXAMPLE_FEATURE_FLAG --no-sensitive +``` + +`NEXT_PUBLIC_*` variables require `--no-sensitive` because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. + +The command prompts for all three values using hidden input, then asks for an explicit safe default or skip decision for every tracked root and `apps/web` dotenv file. Real environment values are never written to tracked files. Use `--dry-run` to perform preflight and preview the redacted plan without retaining changes. + +Remote updates are not transactional. If a provider write fails, the command stops and writes a value-free resume journal under `.tmp/web-env/`. Re-enter all three values with the printed command: + +```bash +pnpm web:env resume .tmp/web-env/.json +``` + +The workflow does not deploy. Trigger the appropriate Staging or Production deployment separately when the new values should take effect. + ### 4. Start the database The project uses PostgreSQL 18 with pgvector, running via Docker. The compose file is at `dev/docker-compose.yml`: diff --git a/package.json b/package.json index 0f5f615dc..7bda98632 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "preinstall": "npx only-allow pnpm", "typecheck": "scripts/typecheck-all.sh", "build": "pnpm --filter web build", - "test": "pnpm --filter web test", + "test": "pnpm run test:web-env && pnpm --filter web test", + "test:web-env": "tsgo --noEmit -p scripts/web-env/tsconfig.json && tsx --test scripts/web-env/*.test.ts", "test:setup-smoke": "pnpm --filter web run test:setup-smoke", "lint": "scripts/lint-all.sh", "format": "oxfmt", @@ -33,10 +34,12 @@ "dev:setup-env": "tsx dev/local/setup-env.ts", "dev:seed": "tsx dev/seed/index.ts", "dev:discord-gateway-cron": "tsx dev/discord-gateway-cron.ts", - "dev:kiloclaw-fly-instances": "tsx services/kiloclaw/scripts/dev-fly-instances.ts" + "dev:kiloclaw-fly-instances": "tsx services/kiloclaw/scripts/dev-fly-instances.ts", + "web:env": "tsx scripts/web-env/index.ts" }, "packageManager": "pnpm@11.1.2", "devDependencies": { + "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "husky": "9.1.7", "ink": "6.8.0", @@ -46,6 +49,7 @@ "oxlint-tsgolint": "0.17.4", "react": "19.2.6", "tsx": "catalog:", - "typescript": "catalog:" + "typescript": "catalog:", + "vercel": "53.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0b3aecd4d..881f70de7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,6 +129,9 @@ importers: .: devDependencies: + '@types/node': + specifier: 'catalog:' + version: 24.12.4 '@typescript/native-preview': specifier: 'catalog:' version: 7.0.0-dev.20260514.1 @@ -159,6 +162,9 @@ importers: typescript: specifier: 'catalog:' version: 5.9.3 + vercel: + specifier: 53.3.1 + version: 53.3.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) apps/mobile: dependencies: @@ -381,7 +387,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) apps/storybook: dependencies: @@ -1008,7 +1014,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/cloud-agent-profile: dependencies: @@ -1039,7 +1045,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/db: dependencies: @@ -1088,7 +1094,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/event-service: dependencies: @@ -1104,7 +1110,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kilo-chat: dependencies: @@ -1126,7 +1132,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kilo-chat-hooks: dependencies: @@ -1154,7 +1160,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kiloclaw-instance-tiers: dependencies: @@ -1170,7 +1176,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kiloclaw-secret-catalog: dependencies: @@ -1186,7 +1192,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/mcp-gateway: dependencies: @@ -1202,7 +1208,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/notifications: dependencies: @@ -1227,7 +1233,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/session-ingest-contracts: dependencies: @@ -1311,7 +1317,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/worker-utils: dependencies: @@ -1345,7 +1351,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/ai-attribution: dependencies: @@ -1440,7 +1446,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1468,7 +1474,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1505,7 +1511,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1551,7 +1557,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1582,7 +1588,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1646,7 +1652,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1737,7 +1743,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1811,7 +1817,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1967,7 +1973,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2010,7 +2016,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2083,7 +2089,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2111,7 +2117,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/git-token-service: dependencies: @@ -2148,7 +2154,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2176,7 +2182,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2219,7 +2225,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2292,7 +2298,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2378,7 +2384,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2421,7 +2427,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2449,7 +2455,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2487,7 +2493,7 @@ importers: version: 2026.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/kiloclaw/plugins/kiloclaw-customizer: devDependencies: @@ -2496,7 +2502,7 @@ importers: version: 0.27.4 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/kiloclaw/plugins/kiloclaw-morning-briefing: devDependencies: @@ -2511,7 +2517,7 @@ importers: version: 2026.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/mcp-gateway: dependencies: @@ -2554,7 +2560,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2585,7 +2591,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2637,7 +2643,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2674,7 +2680,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2708,7 +2714,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2739,7 +2745,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2791,7 +2797,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2849,7 +2855,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2904,7 +2910,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -3887,6 +3893,9 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@bytecodealliance/preview2-shim@0.17.6': + resolution: {integrity: sha512-n3cM88gTen5980UOBAD6xDcNNL3ocTK8keab21bpx1ONdA+ARj7uD1qoFxOWCyKlkpSi195FH+GeAut7Oc6zZw==} + '@chat-adapter/github@4.27.0': resolution: {integrity: sha512-3/lz5oo/z18H90c89FAXomHnmbXx+E55Nl4jfjtgq4FEUcEI9BU+tbkVANpkQ54tHTEPmhxfg/qJ3mJPctk5hg==} @@ -4184,6 +4193,26 @@ packages: resolution: {integrity: sha512-3a705FnsVVUhAyceShNB3kS2rpxcxLcx+hqB0u6MMMpHwQGbW+m++MqA6r7eOzq/8FLx5e3vDh38h/SVTk2qzw==} engines: {node: '>=22.19.0'} + '@edge-runtime/format@2.2.1': + resolution: {integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==} + engines: {node: '>=16'} + + '@edge-runtime/node-utils@2.3.0': + resolution: {integrity: sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==} + engines: {node: '>=16'} + + '@edge-runtime/ponyfill@2.4.2': + resolution: {integrity: sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==} + engines: {node: '>=16'} + + '@edge-runtime/primitives@4.1.0': + resolution: {integrity: sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==} + engines: {node: '>=16'} + + '@edge-runtime/vm@3.2.0': + resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} + engines: {node: '>=16'} + '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} @@ -4568,6 +4597,10 @@ packages: resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + '@fastify/otel@0.16.0': resolution: {integrity: sha512-2304BdM5Q/kUvQC9qJO1KZq3Zn1WWsw+WWkVmFEaj1UE2hEIiuFqrPeglQOwEtw/ftngisqfQ3v70TWMmwhhHA==} peerDependencies: @@ -4799,6 +4832,14 @@ packages: cpu: [x64] os: [win32] + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.1': + resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} + engines: {node: 20 || >=22} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -5204,6 +5245,11 @@ packages: '@lydell/node-pty@1.2.0-beta.12': resolution: {integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==} + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} @@ -5938,6 +5984,9 @@ packages: cpu: [x64] os: [win32] + '@oxc-project/types@0.110.0': + resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} + '@oxc-project/types@0.120.0': resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} @@ -6052,6 +6101,133 @@ packages: cpu: [x64] os: [win32] + '@oxc-transform/binding-android-arm-eabi@0.111.0': + resolution: {integrity: sha512-NdFLicvorfHYu0g2ftjVJaH7+Dz27AQUNJOq8t/ofRUoWmczOodgUCHx8C1M1htCN4ZmhS/FzfSy6yd/UngJGg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-transform/binding-android-arm64@0.111.0': + resolution: {integrity: sha512-J2v9ajarD2FYlhHtjbgZUFsS2Kvi27pPxDWLGCy7i8tO60xBoozX9/ktSgbiE/QsxKaUhfv4zVKppKWUo71PmQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-transform/binding-darwin-arm64@0.111.0': + resolution: {integrity: sha512-2UYmExxpXzmiHTldhNlosWqG9Nc4US51K0GB9RLcGlTE23WO33vVo1NVAKwxPE+KYuhffwDnRYTovTMUjzwvZA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-transform/binding-darwin-x64@0.111.0': + resolution: {integrity: sha512-c4YRwfLV8Pj/ToiTCbndZaHxM2BD4W3bltr/fjXZcGypEK+U2RZFDL7tIZYT/tyneAC9hCORZKDaKhLLNuzPtA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-transform/binding-freebsd-x64@0.111.0': + resolution: {integrity: sha512-prvf32IcEuLnLZbNVomFosBu0CaZpyj3YsZ6epbOgJy8iJjfLsXBb+PrkO/NBKzjuJoJa2+u7jFKRE0KT7gSOw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': + resolution: {integrity: sha512-+se3579Wp7VOk8TnTZCpT+obTAyzOw2b/UuoM0+51LtbzCSfjKxd4A+o7zRl7GyPrPZvx57KdbMOC9rWB1xNrw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': + resolution: {integrity: sha512-8faC99pStqaSDPK/vBgaagAHUeL0LcIzfeSjSiDTtvPGc3AwZIeqC1tx3CP15a6tWXjdgS/IUw4IjfD5HweBlg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-transform/binding-linux-arm64-gnu@0.111.0': + resolution: {integrity: sha512-HtfQv8j796gzI5WR/RaP6IMwFpiL0vYeDrUA1hYhlPzTHKYan/B+NlhJkKOI1v24yAl/yEnFmb0pxIxLNqBqBA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-arm64-musl@0.111.0': + resolution: {integrity: sha512-ARyfcMCIxVLDgLf6FQ8Oo1/TFySpnquV+vuSb4SFQZfYDqgMklzwv0NYXxWD0aB6enElyMDs6pQJBzusEKCkOg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': + resolution: {integrity: sha512-PKpVRrSvBNK3tv9vwxn7Fay+QWZmprPGlEqJcseBJllQc5mFMD4Q/w44chu5iR9ZLsDeSHzmNWrgMLo4J0sP2A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': + resolution: {integrity: sha512-9bUml6rMgk+8GF5rvNMweFspkzSiCjqpV6HduwiUyexqfGKrmjq9IZOxxvnzkE2RGdQzP507NNDoVNYIoGQYuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-riscv64-musl@0.111.0': + resolution: {integrity: sha512-tzGCohGxaeH6KRJjfYZd4mHCoGjCai6N+zZi1Oj+tSDMAAdyvs1dRzYb8PNUGnybCg3Te4M0jLPzWZaSmnKraQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-linux-s390x-gnu@0.111.0': + resolution: {integrity: sha512-sRG1KIfZ0ML9ToEygm5aM/5GJeBA05uHlgW3M0Rx/DNWMJhuahLmqWuB02aWSmijndLfEKXLLXIWhvWupRG8lg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-x64-gnu@0.111.0': + resolution: {integrity: sha512-T0Kmvk+OdlUdABdXlDIf3MQReMzFfC75NEI9x8jxy5pKooACEFg0k0V8gyR3gq4DzbDCfucqFQDWNvSgIopAbQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxc-transform/binding-linux-x64-musl@0.111.0': + resolution: {integrity: sha512-EgoutsP3YfqzN8a9vpc9+XLr0bmBl0dA3uOMiP77+exATCPxJBkJErGmQkqk6RtTp5XqX6q6mB45qWQyKk6+pA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxc-transform/binding-openharmony-arm64@0.111.0': + resolution: {integrity: sha512-d8J+ejc0j5WODbVwR/QxFaI65YMwvG0W53vcVCHwa6ja1QI5lpe7sislrefG2EFYgnY47voMRzlXab5d4gEcDw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-transform/binding-wasm32-wasi@0.111.0': + resolution: {integrity: sha512-HtyIZO8IwuZgXkyb56rysLz1OLbfLhEu8A3BeuyJXzUseAj96yuxgGt3cu3QYX9AXb9pfRfA3c/fvlhsDugyTQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-transform/binding-win32-arm64-msvc@0.111.0': + resolution: {integrity: sha512-YeP80Riptc0MkVVBnzbmoFuHVLUq278+MbwNo9sTLALmzTIJxJqN029xRZbG+Bun7aLsoZhmRnm3J5JZ1NcP5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-transform/binding-win32-ia32-msvc@0.111.0': + resolution: {integrity: sha512-A6ztCXpoSHt6PbvGAFqB0MLOcGG7ZJrrPXY1iB0zfOB1atLgI8oNePGxPl03XSbwpiTsFJ1oo8rj9DXcBzgT9g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-transform/binding-win32-x64-msvc@0.111.0': + resolution: {integrity: sha512-QddKW4kBH0Wof6Y65eYCNHM4iOGmCTWLLcNYY1FGswhzmTYOUVXajNROR+iCXAOFnOF0ldtsR79SyqgyHH1Bgg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@oxfmt/binding-android-arm-eabi@0.40.0': resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7142,6 +7318,10 @@ packages: react-redux: optional: true + '@renovatebot/pep440@4.2.1': + resolution: {integrity: sha512-2FK1hF93Fuf1laSdfiEmJvSJPVIDHEUTz68D3Fi9s0IZrrpaEcj6pTFBTbYvsgC5du4ogrtf5re7yMMvrKNgkw==} + engines: {node: ^20.9.0 || ^22.11.0 || ^24, pnpm: ^10.0.0} + '@rn-primitives/portal@1.3.0': resolution: {integrity: sha512-a2DSce7TcSfcs0cCngLadAJOvx/+mdH9NRu+GxkX8NPRsGGhJvDEOqouMgDqLwx7z9mjXoUaZcwaVcemUSW9/A==} peerDependencies: @@ -7171,36 +7351,73 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} deprecated: Use Promise.withResolvers instead + '@rolldown/binding-android-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-android-arm64@1.0.0-rc.17': resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.1': + resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.17': resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': + resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': + resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7208,6 +7425,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7229,6 +7453,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': + resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7236,6 +7467,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': + resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7243,29 +7481,55 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': + resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': + resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': + resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/pluginutils@1.0.0-rc.1': + resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==} + '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} @@ -7822,6 +8086,9 @@ packages: '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + '@sinclair/typebox@0.25.24': + resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + '@sinclair/typebox@0.27.10': resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} @@ -8579,6 +8846,13 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@trpc/client@11.17.0': resolution: {integrity: sha512-KpJBFrbKTDeVCFv/3ckL1XBBH5Yssn8hethI/rUy7GIpTj+VzjtPjykDqJpzobuVOz+d26cXCSu1t4I6MYI5Zg==} hasBin: true @@ -8618,6 +8892,9 @@ packages: resolution: {integrity: sha512-w071DSzP94YfN6XiWhOxnLpYT3uqtxJBDYdh6Jdjzt+Ce6DNspJsPQgpC7rbts/B8tEkq0LHoYuIF/O5Jh5rPg==} engines: {node: '>=18'} + '@ts-morph/common@0.11.1': + resolution: {integrity: sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -8761,6 +9038,9 @@ packages: '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + '@types/node@20.11.0': + resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} + '@types/node@20.19.41': resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==} @@ -9063,10 +9343,47 @@ packages: '@upstash/redis@1.38.0': resolution: {integrity: sha512-wu+dZBptlLy0+MCUEoHmzrY/TnmgDey3+c7EbIGwrLqAvkP8yi5MWZHYGIFtAygmL4Bkz2TdFu+eU0vFPncIcg==} + '@vercel/backends@0.4.0': + resolution: {integrity: sha512-hjoXd64KBnS2dT3U3x1ABd3u9VqRTIflM5Pxszwv/7Defy/rN9KjElOeCvu3T3z8qr02nnqus8S4nfWOhwsY/w==} + + '@vercel/blob@2.3.0': + resolution: {integrity: sha512-oYWiJbWRQ7gz9Mj0X/NHFJ3OcLMOBzq/2b3j6zeNrQmtFo6dHwU8FAwNpxVIYddVMd+g8eqEi7iRueYx8FtM0Q==} + engines: {node: '>=20.0.0'} + + '@vercel/build-utils@13.22.0': + resolution: {integrity: sha512-4DWbevInIV7ZqrPWZR58s6S9FtfpOBEJFKqXEm7bwiC8Hq8hKOk/igkDei3taja1bC6mfps44OEGlCH0cARSHw==} + + '@vercel/cervel@0.1.1': + resolution: {integrity: sha512-2gCMYw7lPPP571X4ojdhueoF1qHqD5JyQuQ/hsRgcEyilV+2v2lNCdb5ptGah4pDeEWcvg3g9wTomR8dLC1SaQ==} + hasBin: true + + '@vercel/cli-config@0.1.1': + resolution: {integrity: sha512-7bYfDRq6EYYbpkDTrbWCHowX3kVQWXluZBIRtqnPoaXcL9jNpwe3ps5qAaEYq24kICLxGDKu1Rmy1U7rBlUr9w==} + + '@vercel/detect-agent@1.2.3': + resolution: {integrity: sha512-VYNCgUc0nOmC4WJmWw9GkrKdfr8Zl4/rxhC5SvgacBgxiW9W/9NRttUoHHXV8xdII3MaRgkZZVX8Ikzc/Jmjag==} + engines: {node: '>=14'} + + '@vercel/elysia@0.1.74': + resolution: {integrity: sha512-O9EpMBfvD+xkkmEliV0BHPbkVO4j/vDWAiNCJdvdFWu11QLqWtZRi2hC+dtw4iNKzXVLzKLo2481BSwBaopDtA==} + + '@vercel/error-utils@2.1.0': + resolution: {integrity: sha512-DiJcXBOB9N6QM4d7hYPM9Ck/AUjzBl58XNQPxS74o7CuvIanjzrGgygP/70VsyEASeIJMazk1LrhwcNTR/eZGQ==} + + '@vercel/express@0.1.84': + resolution: {integrity: sha512-rQqbVgBIkB0OE068i6m225eGk2QsEXy48WcnczIiqYGPDKjtglh03Wq7x8ED/9KrkTkiojGJkLYdAcNumQpSBA==} + + '@vercel/fastify@0.1.77': + resolution: {integrity: sha512-Yd5kzpPbBYdVQ5JcGcr10B6BQSb20urfz8fHEvJv4x+lWUBBkoSogW/GiBcFF1rhqPFAIpVHMWYCc3Q7IR/oPA==} + '@vercel/firewall@1.2.1': resolution: {integrity: sha512-WlxjEPpf+GWYMontNNZqZjvLL40ziGwy9swwI9da/L1fB/syAO1S2fMtlBXkp4EGVF6nlXSKmwvkUd6YPWJbbg==} engines: {node: '>= 20'} + '@vercel/fun@1.3.0': + resolution: {integrity: sha512-8erw9uPe0dFg45THkNxmjtvMX143SkZebmjgSVbcM3XCkXu3RIiBaJMcMNG8aaS+rnTuw8+d4De9HVT0M/r3wg==} + engines: {node: '>= 18'} + '@vercel/functions@3.4.6': resolution: {integrity: sha512-ljfB7SceggUOFjagEmw3PBLSAGQK1NmBln4FV/Cg9cewfbdfJZS88LgC7LRfZ9GgG1kWimkwS/8SLHVtx6lhLA==} engines: {node: '>= 20'} @@ -9076,6 +9393,41 @@ packages: '@aws-sdk/credential-provider-web-identity': optional: true + '@vercel/gatsby-plugin-vercel-analytics@1.0.11': + resolution: {integrity: sha512-iTEA0vY6RBPuEzkwUTVzSHDATo1aF6bdLLspI68mQ/BTbi5UQEGjpjyzdKOVcSYApDtFU6M6vypZ1t4vIEnHvw==} + + '@vercel/gatsby-plugin-vercel-builder@2.2.1': + resolution: {integrity: sha512-ej6b6H+zr0SXgIP1NXt5PD68dRwwNlD6afpBZc+ZxlkVu7qUjtovAW062OHMIpTSvnEcBSbcBtA9OPz4E3Ixug==} + + '@vercel/go@3.6.0': + resolution: {integrity: sha512-60gQxuQBfuGQCPdp1zmG3bfWncj+MRDm9KNogKeu4cA1uC2kGwUoCI6vr8kpGTv62v3gwSLbcnJ3RsqOqxb3KA==} + + '@vercel/h3@0.1.83': + resolution: {integrity: sha512-Q/ssscXDQX6/TCEcKlIUB8i5n67z1uzQiBC7advTVkM45HKid0mMWsQEl0unGhEsPzUsizss4Kow9eUTvnX+qQ==} + + '@vercel/hono@0.2.77': + resolution: {integrity: sha512-N8UsEbP+2jdhU1YZyGQ56btW5SPMgg1uZC4Cr+NzpsbsizBXTLz7BWnJoQM+Eea/p4v2N+FLZ2Lenz2Mk8lagA==} + + '@vercel/hydrogen@1.3.7': + resolution: {integrity: sha512-nh8hZ76Ipf9FRmMmQGd4SjkE0zxdjt+TUpZcuCIUG7yaHEh9STQV655I8rxKCB3hEWaKB3HALGgxZ0htIjQtZQ==} + + '@vercel/koa@0.1.57': + resolution: {integrity: sha512-1mCqpyVsQPMupJdSQ1h9PO5GDiUFo1QhaGFFAlsLUuM1oTUhc2bklg85FroCbncs1MOtoR2a30kywJoe8S8e0A==} + + '@vercel/nestjs@0.2.78': + resolution: {integrity: sha512-8jFlHsy9M9Q+9/qPQ8zJfpVBEM+aklIZFxaclKVli33seovLKTX54yyiNM2aYb6b1Q3E44NQBsgz14fnFLxYEQ==} + + '@vercel/next@4.17.1': + resolution: {integrity: sha512-nEQRgGyU8+VU/zeKsBF89aKmL0Yu5VWWhTbaltp2V+1q6kHUo6Ho4+YS/COAgOrIwoe2nWr9liLVPltrftqG+Q==} + + '@vercel/nft@1.5.0': + resolution: {integrity: sha512-IWTDeIoWhQ7ZtRO/JRKH+jhmeQvZYhtGPmzw/QGDY+wDCQqfm25P9yIdoAFagu4fWsK4IwZXDFIjrmp5rRm/sA==} + engines: {node: '>=20'} + hasBin: true + + '@vercel/node@5.7.16': + resolution: {integrity: sha512-BBnkw/ubZkb87G//+lz+ZRweA+Yj+YAtsSbSuNAUigxvQJZiMvEAZgI5EcuL85ex69KPTjwHPcYPLWxU3xXTLg==} + '@vercel/oidc@3.2.0': resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} @@ -9096,6 +9448,36 @@ packages: '@opentelemetry/sdk-metrics': '>=2.0.0 <3.0.0' '@opentelemetry/sdk-trace-base': '>=2.0.0 <3.0.0' + '@vercel/prepare-flags-definitions@0.2.1': + resolution: {integrity: sha512-ouXTsqn7I9xZ1KKezgvn/w3tZeQHL/tc52j9GHiOYi6kT8xgdbT8s2x8C9BQr44iceX0hfhtZwk9q7NuI2Tqbw==} + + '@vercel/python-analysis@0.11.1': + resolution: {integrity: sha512-EPPLuXJQhIDUx08H9nG76AR2HSgBquwe3OAX5s2w20M923iaWeGGVkhX/4yZ89CJfXEZgE1Aj/mX7lVHOVIcYA==} + + '@vercel/python@6.39.0': + resolution: {integrity: sha512-BIp793WI9TL/N85r22WhSo9n99TPjqI1xXEm8RAqZNJaXcFLHfjF5Hfg14Y4uPHGKfALfEzH3gbUndD8MTA8Hw==} + + '@vercel/redwood@2.4.13': + resolution: {integrity: sha512-pXWzVctZea/J7WMQstjsYUDiMc6oJF72p8J5YZnLSCJWg7m+/dLzYGfaUSEo6Q0JpiO/NOcDmG3WENpn7kHwzg==} + + '@vercel/remix-builder@5.8.1': + resolution: {integrity: sha512-DDuT8NbIUoc1Fso2er0GyHxQR77au+BJr8wToDJcyoKjsypOHMcPwV8Vak9XsOfSUlQHLt1x9XnfTVj5O48Ssw==} + + '@vercel/ruby@2.3.2': + resolution: {integrity: sha512-okIgMmPEePyDR9TZYaKM4oftcxVHM5Dbdl7V/tIdh3lq8MGLi7HR5vvQglmZUwZOeovE6MVtezxl960EOzeIiQ==} + + '@vercel/rust@1.2.0': + resolution: {integrity: sha512-JryMtBa0sFuqxfHpjrNgMks06XDKa8DVhGljTsoo26dIKqsoqeYhJHuepEAEXT+b5N+tUmxIOUcRq5//ewvytQ==} + + '@vercel/sandbox@1.9.0': + resolution: {integrity: sha512-zgr1ad0tkT1xZn/8Vxo60wOUOLqMAVGo4WqJQ8/UDcUtWynNJsBjI2tiMdWZrAo9EKH1MIqEzJNkcclF0UT1EQ==} + + '@vercel/static-build@2.9.23': + resolution: {integrity: sha512-u6uzY3+4BYpf9brVLrhvq08iv6BkQQOz782DbnerQfD8PZZ3uPK4dsksN2XfZO0zaWfUR3Lv6gkx6RGEQkJvqA==} + + '@vercel/static-config@3.3.0': + resolution: {integrity: sha512-GpS3tPwUeDJCkrKbMNtS2XLRFgfxTlN7YNUL+Bo23+fGolrDw6Oq79R3yvxTYgqRaJMGSEqC7iMw6mj6I5loxg==} + '@vitest/coverage-v8@4.1.6': resolution: {integrity: sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==} peerDependencies: @@ -9255,6 +9637,14 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@yarnpkg/parsers@3.0.3': + resolution: {integrity: sha512-mQZgUSgFurUtA07ceMjxrWkYz8QtDuYkvPlu0ZqncgjopQ0t6CNEo/OSealkmnagSUx8ZD5ewvezUwUuMqutQg==} + engines: {node: '>=18.12.0'} + + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -9346,6 +9736,9 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ajv@8.6.3: + resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} + anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -9427,6 +9820,9 @@ packages: archy@1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + arg@4.1.0: + resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -9467,6 +9863,10 @@ packages: resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} engines: {node: '>=18'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -9478,6 +9878,23 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + async-listen@1.2.0: + resolution: {integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==} + + async-listen@3.0.0: + resolution: {integrity: sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==} + engines: {node: '>= 14'} + + async-listen@3.0.1: + resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} + engines: {node: '>= 14'} + + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -9674,6 +10091,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + basic-ftp@5.3.1: + resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} + engines: {node: '>=10.0.0'} + before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -9695,6 +10116,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -9777,6 +10201,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} @@ -9810,6 +10237,10 @@ packages: bun-types@1.3.14: resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} + bytes@3.1.0: + resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} + engines: {node: '>= 0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -9909,6 +10340,10 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.0: + resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==} + engines: {node: '>= 14.16.0'} + chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} @@ -10054,6 +10489,9 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + code-block-writer@10.1.1: + resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==} + code-excerpt@4.0.0: resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10151,6 +10589,10 @@ packages: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + console-browserify@1.2.0: resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} @@ -10165,10 +10607,18 @@ packages: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} + content-type@1.0.4: + resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} + engines: {node: '>= 0.6'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + convert-hrtime@3.0.0: + resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} + engines: {node: '>=8'} + convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -10179,6 +10629,9 @@ packages: resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cookie-es@2.0.1: + resolution: {integrity: sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -10360,6 +10813,10 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} @@ -10385,6 +10842,15 @@ packages: supports-color: optional: true + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -10454,10 +10920,18 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -10767,6 +11241,11 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + edge-runtime@2.5.9: + resolution: {integrity: sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==} + engines: {node: '>=16'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -10807,6 +11286,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.1.0: + resolution: {integrity: sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -10863,6 +11345,12 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-module-lexer@1.4.1: + resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + + es-module-lexer@1.5.0: + resolution: {integrity: sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -11023,6 +11511,9 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + events-intercept@2.0.0: + resolution: {integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==} + events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} @@ -11045,6 +11536,10 @@ packages: evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + execa@3.2.0: + resolution: {integrity: sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==} + engines: {node: ^8.12.0 || >=9.7.0} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -11452,6 +11947,9 @@ packages: fd-package-json@2.0.0: resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -11481,6 +11979,9 @@ packages: resolution: {integrity: sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA==} engines: {node: '>=22'} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + filesize@10.1.6: resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} engines: {node: '>= 10.4.0'} @@ -11646,6 +12147,14 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-extra@11.1.0: + resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==} + engines: {node: '>=14.14'} + + fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + fs-monkey@1.1.0: resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} @@ -11680,6 +12189,10 @@ packages: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} + generic-pool@3.4.2: + resolution: {integrity: sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==} + engines: {node: '>= 4'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -11719,6 +12232,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -11726,6 +12243,10 @@ packages: get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} + get-uri@6.0.5: + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} + getenv@2.0.0: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} @@ -11938,10 +12459,18 @@ packages: htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + http-errors@1.7.3: + resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} + engines: {node: '>= 0.6'} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + http_ece@1.2.0: resolution: {integrity: sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==} engines: {node: '>=16'} @@ -11957,6 +12486,10 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -11966,6 +12499,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -12106,6 +12643,10 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -12173,6 +12714,9 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -12594,6 +13138,9 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} @@ -12658,6 +13205,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-ts@1.6.4: + resolution: {integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==} + json-schema-to-ts@3.1.1: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} @@ -12688,6 +13238,9 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonlines@0.1.1: + resolution: {integrity: sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==} + jsonwebtoken@9.0.3: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} @@ -12954,6 +13507,10 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lucide-react-native@1.7.0: resolution: {integrity: sha512-wGJY5nosSawh028jg8r1ZKqnGPDIVfIL9xvKOs4wPYFQHeJMHsADYm/lmuFYXMXXatSkHhpsCjeqIRgeFGzf8g==} peerDependencies: @@ -12966,6 +13523,10 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -13185,6 +13746,11 @@ packages: engines: {node: '>=20.19.4'} hasBin: true + micro@9.3.5-canary.3: + resolution: {integrity: sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==} + engines: {node: '>= 8.0.0'} + hasBin: true + micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -13355,6 +13921,10 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} @@ -13436,6 +14006,12 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.1: + resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -13487,6 +14063,10 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + netmask@2.1.1: + resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} + engines: {node: '>= 0.4.0'} + next-auth@4.24.14: resolution: {integrity: sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==} peerDependencies: @@ -13557,6 +14137,15 @@ packages: encoding: optional: true + node-fetch@2.6.9: + resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -13609,6 +14198,11 @@ packages: resolution: {integrity: sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==} engines: {node: '>=18'} + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -13685,6 +14279,9 @@ packages: resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} engines: {node: '>= 0.8'} + once@1.3.3: + resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -13755,6 +14352,10 @@ packages: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} + os-paths@4.4.0: + resolution: {integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==} + engines: {node: '>= 6.0'} + outvariant@1.4.0: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} @@ -13765,6 +14366,10 @@ packages: oxc-resolver@11.19.1: resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} + oxc-transform@0.111.0: + resolution: {integrity: sha512-oa5KKSDNLHZGaiqIGAbCWXeN9IJUAz9MElWcQX90epDxdKc9Hrt/BsLj3K4gDqfAYa5dwdH+ZCFJG9hR74fiGg==} + engines: {node: ^20.19.0 || >=22.12.0} + oxfmt@0.40.0: resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -13793,6 +14398,10 @@ packages: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} + p-finally@2.0.1: + resolution: {integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==} + engines: {node: '>=8'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -13841,6 +14450,14 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-hash@4.0.0: resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} engines: {node: '>=8'} @@ -13921,6 +14538,9 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} @@ -13939,6 +14559,9 @@ packages: resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} engines: {node: '>= 0.10'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -13973,6 +14596,9 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -14191,6 +14817,9 @@ packages: promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + promisepipe@3.0.0: + resolution: {integrity: sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -14212,6 +14841,10 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -14291,6 +14924,10 @@ packages: resolution: {integrity: sha512-CX4nij6+ZLHYIaojJNfLTr7W+AiH/IPJi6E9Aw1br2///1KZL2KBOHd68rkcLedc47MPvb4hhH+fzYeGFa4A/Q==} engines: {node: '>=22'} + raw-body@2.4.1: + resolution: {integrity: sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==} + engines: {node: '>= 0.8'} + raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -14538,6 +15175,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} @@ -14764,6 +15405,11 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} + rolldown@1.0.0-rc.1: + resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rolldown@1.0.0-rc.17: resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -14819,6 +15465,10 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sandbox@2.5.6: + resolution: {integrity: sha512-tnFr7nyiuEhsAGb+xy60SDbij0790X+FgDljh3J/2HaRM6yQgNJkQKHbDH8ld7mR+PozXGgEfJ2Dc/5OyFnwsg==} + hasBin: true + sass-loader@16.0.7: resolution: {integrity: sha512-w6q+fRHourZ+e+xA1kcsF27iGM6jdB8teexYCfdUw0sYgcDNeZESnDNT9sUmmPm3ooziwUJXGwZJSTF3kOdBfA==} engines: {node: '>= 18.12.0'} @@ -14871,6 +15521,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -14919,6 +15574,9 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.1.1: + resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -14972,6 +15630,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.0.2: + resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} + engines: {node: '>=14'} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -15019,10 +15681,26 @@ packages: resolution: {integrity: sha512-HVk9X1E0gz3mSpoi60h/saazLKXKaZThMLU3u/aNwoYn8/xQyX2MGxL0ui2eaokkD7tF+Zo+cKTHUbe1mmmGzA==} engines: {node: '>=8.0.0'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + smol-toml@1.5.2: + resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==} + engines: {node: '>= 18'} + smol-toml@1.6.0: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonner-native@0.23.1: resolution: {integrity: sha512-p4WRxVoTjLTeuLcvuyMNzgd81tEUS0ayoqXEFhi5GNU1okbvBpqU5GiUjv14DgiLUYXPUQ0qq+OdrFJM2j4j+w==} peerDependencies: @@ -15111,6 +15789,11 @@ packages: sqlite-vec@0.1.9: resolution: {integrity: sha512-L7XJWRIBNvR9O5+vh1FQ+IGkh/3D2AzVksW5gdtk28m78Hy8skFD0pqReKH1Yp0/BUKRGcffgKvyO/EON5JXpA==} + srvx@0.8.9: + resolution: {integrity: sha512-wYc3VLZHRzwYrWJhkEqkhLb31TI0SOkfYZDkUhXdp3NoCnNS0FqajiQszZZjfow/VYEuc6Q5sZh9nM6kPy2NBQ==} + engines: {node: '>=20.16.0'} + hasBin: true + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -15128,6 +15811,9 @@ packages: standardwebhooks@1.0.0: resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} + stat-mode@0.3.0: + resolution: {integrity: sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==} + state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} @@ -15167,6 +15853,9 @@ packages: stream-to-array@2.3.0: resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} + stream-to-promise@2.2.0: + resolution: {integrity: sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==} + streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -15383,6 +16072,9 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + tar-stream@3.1.8: resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} @@ -15397,6 +16089,11 @@ packages: resolution: {integrity: sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==} engines: {node: '>=18'} + tar@7.5.7: + resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} + engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + teex@1.0.1: resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} @@ -15442,6 +16139,14 @@ packages: throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + throttleit@2.1.0: + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} + + time-span@4.0.0: + resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} + engines: {node: '>=10'} + timers-browserify@2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} engines: {node: '>=0.6.0'} @@ -15452,6 +16157,9 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.4: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} @@ -15498,6 +16206,10 @@ packages: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} + toidentifier@1.0.0: + resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} + engines: {node: '>=0.6'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -15595,6 +16307,12 @@ packages: ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} + ts-morph@12.0.0: + resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==} + + ts-toolbelt@6.15.5: + resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==} + tsconfig-paths-webpack-plugin@4.2.0: resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} engines: {node: '>=10.13.0'} @@ -15687,6 +16405,9 @@ packages: uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} + uid-promise@1.0.0: + resolution: {integrity: sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==} + uint8array-extras@1.5.0: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} @@ -15702,6 +16423,9 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -15711,6 +16435,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} + undici@6.24.1: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} @@ -15904,6 +16632,11 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + vercel@53.3.1: + resolution: {integrity: sha512-egwINWuSoVm+8FPO7bIY+egSnIpVRy43QtukVa5QYzPgP0fwT2KaHDokPW9v6/VrgA/whAXdZSBn2Icg08WyCQ==} + engines: {node: '>= 18'} + hasBin: true + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -16053,6 +16786,9 @@ packages: web-tree-sitter@0.26.9: resolution: {integrity: sha512-YJwSHANl6XFgeEjB8nitgj0qZYt5gkIesJ4w2srS2wcLB4GUa4xcOkM0YaMsU6WNR53YVIkDSY7Ej4pf3IXtCA==} + web-vitals@0.2.4: + resolution: {integrity: sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==} + web-vitals@5.1.0: resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} @@ -16234,6 +16970,18 @@ packages: resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} engines: {node: '>=10.0.0'} + xdg-app-paths@5.1.0: + resolution: {integrity: sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==} + engines: {node: '>=6'} + + xdg-app-paths@5.5.1: + resolution: {integrity: sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==} + engines: {node: '>= 6.0'} + + xdg-portable@7.3.0: + resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} + engines: {node: '>= 6.0'} + xml2js@0.6.0: resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} engines: {node: '>=4.0.0'} @@ -16295,6 +17043,17 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl-clone@1.0.4: + resolution: {integrity: sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==} + engines: {node: '>=6'} + + yauzl-promise@2.1.3: + resolution: {integrity: sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==} + engines: {node: '>=6'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -16321,9 +17080,18 @@ packages: peerDependencies: zod: ^3.25 || ^4 + zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + + zod@3.24.4: + resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} + zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.11: + resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} + zod@4.1.8: resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==} @@ -17829,6 +18597,8 @@ snapshots: '@borewit/text-codec@0.2.2': {} + '@bytecodealliance/preview2-shim@0.17.6': {} + '@chat-adapter/github@4.27.0': dependencies: '@chat-adapter/shared': 4.27.0 @@ -18007,7 +18777,7 @@ snapshots: cjs-module-lexer: 1.2.3 esbuild: 0.27.4 miniflare: 4.20260603.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) zod: 3.25.76 transitivePeerDependencies: @@ -18396,6 +19166,18 @@ snapshots: get-east-asian-width: 1.6.0 marked: 15.0.12 + '@edge-runtime/format@2.2.1': {} + + '@edge-runtime/node-utils@2.3.0': {} + + '@edge-runtime/ponyfill@2.4.2': {} + + '@edge-runtime/primitives@4.1.0': {} + + '@edge-runtime/vm@3.2.0': + dependencies: + '@edge-runtime/primitives': 4.1.0 + '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 @@ -18891,6 +19673,8 @@ snapshots: '@faker-js/faker@10.3.0': {} + '@fastify/busboy@2.1.1': {} + '@fastify/otel@0.16.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -19073,6 +19857,12 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.1': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -19782,6 +20572,19 @@ snapshots: '@lydell/node-pty-win32-arm64': 1.2.0-beta.12 '@lydell/node-pty-win32-x64': 1.2.0-beta.12 + '@mapbox/node-pre-gyp@2.0.3': + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.4 + tar: 7.5.15 + transitivePeerDependencies: + - encoding + - supports-color + '@marijn/find-cluster-break@1.0.2': {} '@mdx-js/loader@3.1.1(webpack@5.105.4(@swc/core@1.15.18)(esbuild@0.27.4))': @@ -20671,6 +21474,8 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.120.0': optional: true + '@oxc-project/types@0.110.0': {} + '@oxc-project/types@0.120.0': {} '@oxc-project/types@0.127.0': {} @@ -20737,6 +21542,71 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.19.1': optional: true + '@oxc-transform/binding-android-arm-eabi@0.111.0': + optional: true + + '@oxc-transform/binding-android-arm64@0.111.0': + optional: true + + '@oxc-transform/binding-darwin-arm64@0.111.0': + optional: true + + '@oxc-transform/binding-darwin-x64@0.111.0': + optional: true + + '@oxc-transform/binding-freebsd-x64@0.111.0': + optional: true + + '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': + optional: true + + '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': + optional: true + + '@oxc-transform/binding-linux-arm64-gnu@0.111.0': + optional: true + + '@oxc-transform/binding-linux-arm64-musl@0.111.0': + optional: true + + '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': + optional: true + + '@oxc-transform/binding-linux-riscv64-musl@0.111.0': + optional: true + + '@oxc-transform/binding-linux-s390x-gnu@0.111.0': + optional: true + + '@oxc-transform/binding-linux-x64-gnu@0.111.0': + optional: true + + '@oxc-transform/binding-linux-x64-musl@0.111.0': + optional: true + + '@oxc-transform/binding-openharmony-arm64@0.111.0': + optional: true + + '@oxc-transform/binding-wasm32-wasi@0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@oxc-transform/binding-win32-arm64-msvc@0.111.0': + optional: true + + '@oxc-transform/binding-win32-ia32-msvc@0.111.0': + optional: true + + '@oxc-transform/binding-win32-x64-msvc@0.111.0': + optional: true + '@oxfmt/binding-android-arm-eabi@0.40.0': optional: true @@ -21933,6 +22803,8 @@ snapshots: react: 19.2.6 react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) + '@renovatebot/pep440@4.2.1': {} + '@rn-primitives/portal@1.3.0(@types/react@19.2.14)(immer@11.1.4)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))': dependencies: react: 19.2.0 @@ -21952,24 +22824,45 @@ snapshots: '@rocicorp/resolver@1.0.2': {} + '@rolldown/binding-android-arm64@1.0.0-rc.1': + optional: true + '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.1': + optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.1': + optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.1': + optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true @@ -21979,15 +22872,32 @@ snapshots: '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': + optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: '@emnapi/core': 1.10.0 @@ -21995,12 +22905,20 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': + optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true + '@rolldown/pluginutils@1.0.0-rc.1': {} + '@rolldown/pluginutils@1.0.0-rc.17': {} '@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)': @@ -22023,6 +22941,14 @@ snapshots: optionalDependencies: rollup: 4.59.0 + '@rollup/pluginutils@5.3.0(rollup@4.59.1)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.59.1 + '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -22530,6 +23456,8 @@ snapshots: '@silvia-odwyer/photon-node@0.3.4': {} + '@sinclair/typebox@0.25.24': {} + '@sinclair/typebox@0.27.10': {} '@sinclair/typebox@0.34.41': {} @@ -22563,7 +23491,7 @@ snapshots: '@slack/logger': 4.0.1 '@slack/web-api': 7.15.0 '@types/jsonwebtoken': 9.0.10 - '@types/node': 25.5.2 + '@types/node': 24.12.4 jsonwebtoken: 9.0.3 transitivePeerDependencies: - debug @@ -22609,7 +23537,7 @@ snapshots: dependencies: '@slack/logger': 4.0.1 '@slack/types': 2.21.1 - '@types/node': 25.5.2 + '@types/node': 24.12.4 '@types/retry': 0.12.0 axios: 1.16.1 eventemitter3: 5.0.4 @@ -23632,6 +24560,10 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tootallnate/once@2.0.0': {} + + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@trpc/server': 11.17.0(typescript@5.9.3) @@ -23672,6 +24604,13 @@ snapshots: '@ts-graphviz/ast': 2.0.7 '@ts-graphviz/common': 2.1.5 + '@ts-morph/common@0.11.1': + dependencies: + fast-glob: 3.3.3 + minimatch: 3.1.5 + mkdirp: 1.0.4 + path-browserify: 1.0.1 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -23811,7 +24750,7 @@ snapshots: '@types/jsonwebtoken@9.0.10': dependencies: '@types/ms': 2.1.0 - '@types/node': 25.5.2 + '@types/node': 24.12.4 '@types/jsrsasign@10.5.15': {} @@ -23834,6 +24773,10 @@ snapshots: '@types/node': 24.12.4 form-data: 4.0.5 + '@types/node@20.11.0': + dependencies: + undici-types: 5.26.5 + '@types/node@20.19.41': dependencies: undici-types: 6.21.0 @@ -24083,14 +25026,244 @@ snapshots: dependencies: uncrypto: 0.1.3 + '@vercel/backends@0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': + dependencies: + '@vercel/build-utils': 13.22.0 + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@yarnpkg/parsers': 3.0.3 + execa: 3.2.0 + fs-extra: 11.1.0 + js-yaml: 3.14.2 + oxc-transform: 0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + path-to-regexp: 8.4.2 + resolve.exports: 2.0.3 + rolldown: 1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + srvx: 0.8.9 + tsx: 4.21.0 + zod: 3.22.4 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - encoding + - rollup + - supports-color + + '@vercel/blob@2.3.0': + dependencies: + async-retry: 1.3.3 + is-buffer: 2.0.5 + is-node-process: 1.2.0 + throttleit: 2.1.0 + undici: 6.24.1 + + '@vercel/build-utils@13.22.0': + dependencies: + '@vercel/python-analysis': 0.11.1 + cjs-module-lexer: 1.2.3 + es-module-lexer: 1.5.0 + + '@vercel/cervel@0.1.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': + dependencies: + '@vercel/backends': 0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - encoding + - rollup + - supports-color + + '@vercel/cli-config@0.1.1': + dependencies: + xdg-app-paths: 5.5.1 + zod: 4.1.11 + + '@vercel/detect-agent@1.2.3': {} + + '@vercel/elysia@0.1.74(rollup@4.59.1)': + dependencies: + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/error-utils@2.1.0': {} + + '@vercel/express@0.1.84(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': + dependencies: + '@vercel/cervel': 0.1.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + fs-extra: 11.1.0 + path-to-regexp: 8.4.2 + ts-morph: 12.0.0 + zod: 3.22.4 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - encoding + - rollup + - supports-color + + '@vercel/fastify@0.1.77(rollup@4.59.1)': + dependencies: + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + '@vercel/firewall@1.2.1': {} + '@vercel/fun@1.3.0': + dependencies: + '@tootallnate/once': 2.0.0 + async-listen: 1.2.0 + debug: 4.3.4 + generic-pool: 3.4.2 + micro: 9.3.5-canary.3 + ms: 2.1.1 + node-fetch: 2.6.7 + path-to-regexp: 8.4.2 + promisepipe: 3.0.0 + semver: 7.5.4 + stat-mode: 0.3.0 + stream-to-promise: 2.2.0 + tar: 7.5.7 + tinyexec: 0.3.2 + tree-kill: 1.2.2 + uid-promise: 1.0.0 + xdg-app-paths: 5.1.0 + yauzl-promise: 2.1.3 + transitivePeerDependencies: + - encoding + - supports-color + '@vercel/functions@3.4.6(@aws-sdk/credential-provider-web-identity@3.972.20)': dependencies: '@vercel/oidc': 3.3.1 optionalDependencies: '@aws-sdk/credential-provider-web-identity': 3.972.20 + '@vercel/gatsby-plugin-vercel-analytics@1.0.11': + dependencies: + web-vitals: 0.2.4 + + '@vercel/gatsby-plugin-vercel-builder@2.2.1': + dependencies: + '@sinclair/typebox': 0.25.24 + '@vercel/build-utils': 13.22.0 + esbuild: 0.27.4 + etag: 1.8.1 + fs-extra: 11.1.0 + + '@vercel/go@3.6.0': {} + + '@vercel/h3@0.1.83(rollup@4.59.1)': + dependencies: + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/hono@0.2.77(rollup@4.59.1)': + dependencies: + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + fs-extra: 11.1.0 + path-to-regexp: 8.4.2 + ts-morph: 12.0.0 + zod: 3.22.4 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/hydrogen@1.3.7': + dependencies: + '@vercel/static-config': 3.3.0 + ts-morph: 12.0.0 + + '@vercel/koa@0.1.57(rollup@4.59.1)': + dependencies: + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/nestjs@0.2.78(rollup@4.59.1)': + dependencies: + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/next@4.17.1(rollup@4.59.1)': + dependencies: + '@vercel/nft': 1.5.0(rollup@4.59.1) + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/nft@1.5.0(rollup@4.59.1)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.59.1) + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 13.0.6 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.4 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/node@5.7.16(rollup@4.59.1)': + dependencies: + '@edge-runtime/node-utils': 2.3.0 + '@edge-runtime/primitives': 4.1.0 + '@edge-runtime/vm': 3.2.0 + '@types/node': 20.11.0 + '@vercel/build-utils': 13.22.0 + '@vercel/error-utils': 2.1.0 + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + async-listen: 3.0.0 + cjs-module-lexer: 1.2.3 + edge-runtime: 2.5.9 + es-module-lexer: 1.4.1 + esbuild: 0.27.4 + etag: 1.8.1 + mime-types: 2.1.35 + node-fetch: 2.6.9 + path-to-regexp: 8.4.2 + path-to-regexp-updated: path-to-regexp@6.3.0 + ts-morph: 12.0.0 + tsx: 4.21.0 + typescript: 5.9.3 + undici: 5.28.4 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + '@vercel/oidc@3.2.0': {} '@vercel/oidc@3.3.1': {} @@ -24105,6 +25278,81 @@ snapshots: '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.1) + '@vercel/prepare-flags-definitions@0.2.1': {} + + '@vercel/python-analysis@0.11.1': + dependencies: + '@bytecodealliance/preview2-shim': 0.17.6 + '@renovatebot/pep440': 4.2.1 + fs-extra: 11.1.1 + js-yaml: 4.1.1 + minimatch: 10.1.1 + smol-toml: 1.5.2 + zod: 3.22.4 + + '@vercel/python@6.39.0': + dependencies: + '@vercel/python-analysis': 0.11.1 + + '@vercel/redwood@2.4.13(rollup@4.59.1)': + dependencies: + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + semver: 6.3.1 + ts-morph: 12.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/remix-builder@5.8.1(rollup@4.59.1)': + dependencies: + '@vercel/error-utils': 2.1.0 + '@vercel/nft': 1.5.0(rollup@4.59.1) + '@vercel/static-config': 3.3.0 + path-to-regexp: 8.4.2 + path-to-regexp-updated: path-to-regexp@6.3.0 + ts-morph: 12.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/ruby@2.3.2': {} + + '@vercel/rust@1.2.0': + dependencies: + execa: 5.1.1 + smol-toml: 1.5.2 + + '@vercel/sandbox@1.9.0': + dependencies: + '@vercel/oidc': 3.2.0 + async-retry: 1.3.3 + jsonlines: 0.1.1 + ms: 2.1.3 + picocolors: 1.1.1 + tar-stream: 3.1.7 + undici: 7.25.0 + xdg-app-paths: 5.1.0 + zod: 3.24.4 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + + '@vercel/static-build@2.9.23': + dependencies: + '@vercel/gatsby-plugin-vercel-analytics': 1.0.11 + '@vercel/gatsby-plugin-vercel-builder': 2.2.1 + '@vercel/static-config': 3.3.0 + ts-morph: 12.0.0 + + '@vercel/static-config@3.3.0': + dependencies: + ajv: 8.6.3 + json-schema-to-ts: 1.6.4 + ts-morph: 12.0.0 + '@vitest/coverage-v8@4.1.6(vitest@4.1.6)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -24117,7 +25365,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/expect@3.2.4': dependencies: @@ -24203,7 +25451,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/utils@3.2.4': dependencies: @@ -24349,6 +25597,13 @@ snapshots: '@xtuc/long@4.2.2': {} + '@yarnpkg/parsers@3.0.3': + dependencies: + js-yaml: 3.14.2 + tslib: 2.8.1 + + abbrev@3.0.1: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -24451,6 +25706,13 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ajv@8.6.3: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + anser@1.4.10: {} anser@2.3.5: {} @@ -24526,6 +25788,8 @@ snapshots: archy@1.0.0: {} + arg@4.1.0: {} + arg@5.0.2: {} argparse@1.0.10: @@ -24569,6 +25833,10 @@ snapshots: ast-module-types@6.0.1: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -24581,6 +25849,18 @@ snapshots: astring@1.9.0: {} + async-listen@1.2.0: {} + + async-listen@3.0.0: {} + + async-listen@3.0.1: {} + + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + + async-sema@3.1.1: {} + async@3.2.6: {} asynckit@0.4.0: {} @@ -24836,6 +26116,8 @@ snapshots: baseline-browser-mapping@2.10.8: {} + basic-ftp@5.3.1: {} + before-after-hook@4.0.0: {} better-opn@3.0.2: @@ -24850,6 +26132,10 @@ snapshots: binary-extensions@2.3.0: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -24966,6 +26252,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + buffer-crc32@1.0.0: {} buffer-equal-constant-time@1.0.1: {} @@ -24996,6 +26284,8 @@ snapshots: dependencies: '@types/node': 24.12.4 + bytes@3.1.0: {} + bytes@3.1.2: {} caching-transform@4.0.0: @@ -25102,6 +26392,10 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.0: + dependencies: + readdirp: 4.1.2 + chokidar@5.0.0: dependencies: readdirp: 5.0.0 @@ -25232,6 +26526,8 @@ snapshots: co@4.6.0: {} + code-block-writer@10.1.1: {} + code-excerpt@4.0.0: dependencies: convert-to-spaces: 2.0.1 @@ -25338,6 +26634,8 @@ snapshots: transitivePeerDependencies: - supports-color + consola@3.4.2: {} + console-browserify@1.2.0: {} constants-browserify@1.0.0: {} @@ -25348,14 +26646,20 @@ snapshots: content-disposition@1.0.1: {} + content-type@1.0.4: {} + content-type@1.0.5: {} + convert-hrtime@3.0.0: {} + convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} convert-to-spaces@2.0.1: {} + cookie-es@2.0.1: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -25589,6 +26893,8 @@ snapshots: data-uri-to-buffer@4.0.1: {} + data-uri-to-buffer@6.0.2: {} + date-fns@4.1.0: {} dayjs@1.11.20: {} @@ -25603,6 +26909,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.4: + dependencies: + ms: 2.1.2 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -25653,8 +26963,16 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} + depd@1.1.2: {} + depd@2.0.0: {} dependency-cruiser@17.3.10: @@ -25930,6 +27248,18 @@ snapshots: dependencies: safe-buffer: 5.2.1 + edge-runtime@2.5.9: + dependencies: + '@edge-runtime/format': 2.2.1 + '@edge-runtime/ponyfill': 2.4.2 + '@edge-runtime/vm': 3.2.0 + async-listen: 3.0.1 + mri: 1.2.0 + picocolors: 1.0.0 + pretty-ms: 7.0.1 + signal-exit: 4.0.2 + time-span: 4.0.0 + ee-first@1.1.1: {} effect@4.0.0-beta.57: @@ -25973,6 +27303,10 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.1.0: + dependencies: + once: 1.3.3 + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -26021,6 +27355,10 @@ snapshots: es-errors@1.3.0: {} + es-module-lexer@1.4.1: {} + + es-module-lexer@1.5.0: {} + es-module-lexer@1.7.0: {} es-module-lexer@2.0.0: {} @@ -26221,6 +27559,8 @@ snapshots: eventemitter3@5.0.4: {} + events-intercept@2.0.0: {} + events-universal@1.0.1: dependencies: bare-events: 2.8.2 @@ -26242,6 +27582,19 @@ snapshots: md5.js: 1.3.5 safe-buffer: 5.2.1 + execa@3.2.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + p-finally: 2.0.1 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -26742,6 +28095,10 @@ snapshots: dependencies: walk-up-path: 4.0.0 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -26768,6 +28125,8 @@ snapshots: transitivePeerDependencies: - supports-color + file-uri-to-path@1.0.0: {} + filesize@10.1.6: {} filing-cabinet@5.2.0: @@ -26969,6 +28328,18 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 + fs-extra@11.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-extra@11.1.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-monkey@1.1.0: {} fsevents@2.3.2: @@ -27001,6 +28372,8 @@ snapshots: generator-function@2.0.1: {} + generic-pool@3.4.2: {} + gensync@1.0.0-beta.2: {} get-amd-module-type@6.0.1: @@ -27038,12 +28411,24 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + get-stream@6.0.1: {} get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.5: + dependencies: + basic-ftp: 5.3.1 + data-uri-to-buffer: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + getenv@2.0.0: {} github-slugger@2.0.0: {} @@ -27320,6 +28705,14 @@ snapshots: domutils: 2.8.0 entities: 2.2.0 + http-errors@1.7.3: + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.1.1 + statuses: 1.5.0 + toidentifier: 1.0.0 + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -27328,6 +28721,13 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + http_ece@1.2.0: {} https-browserify@1.0.0: {} @@ -27346,10 +28746,16 @@ snapshots: transitivePeerDependencies: - supports-color + human-signals@1.1.1: {} + human-signals@2.1.0: {} husky@9.1.7: {} + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -27480,6 +28886,8 @@ snapshots: dependencies: binary-extensions: 2.3.0 + is-buffer@2.0.5: {} + is-callable@1.2.7: {} is-core-module@2.16.1: @@ -27532,6 +28940,8 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 + is-node-process@1.2.0: {} + is-number@7.0.0: {} is-obj@1.0.1: {} @@ -28482,6 +29892,8 @@ snapshots: jose@5.10.0: {} + jose@5.9.6: {} + jose@6.2.3: {} jotai-minidb@0.0.8(jotai@2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.6)): @@ -28533,6 +29945,11 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-to-ts@1.6.4: + dependencies: + '@types/json-schema': 7.0.15 + ts-toolbelt: 6.15.5 + json-schema-to-ts@3.1.1: dependencies: '@babel/runtime': 7.29.2 @@ -28558,6 +29975,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonlines@0.1.1: {} + jsonwebtoken@9.0.3: dependencies: jws: 4.0.1 @@ -28810,6 +30229,8 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + lucide-react-native@1.7.0(react-native-svg@15.15.3(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0): dependencies: react: 19.2.0 @@ -28820,6 +30241,8 @@ snapshots: dependencies: react: 19.2.6 + luxon@3.7.2: {} + lz-string@1.5.0: {} madge@8.0.0(typescript@5.9.3): @@ -29284,6 +30707,12 @@ snapshots: - supports-color - utf-8-validate + micro@9.3.5-canary.3: + dependencies: + arg: 4.1.0 + content-type: 1.0.4 + raw-body: 2.4.1 + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -29622,6 +31051,10 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.1 + minimatch@10.2.4: dependencies: brace-expansion: 5.0.6 @@ -29691,6 +31124,10 @@ snapshots: ms@2.0.0: {} + ms@2.1.1: {} + + ms@2.1.2: {} + ms@2.1.3: {} msgpackr-extract@3.0.3: @@ -29733,6 +31170,8 @@ snapshots: neo-async@2.6.2: {} + netmask@2.1.1: {} + next-auth@4.24.14(next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 @@ -29809,6 +31248,10 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-fetch@2.6.9: + dependencies: + whatwg-url: 5.0.0 + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -29878,6 +31321,10 @@ snapshots: dependencies: '@babel/parser': 7.29.0 + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + normalize-path@3.0.0: {} npm-package-arg@11.0.3: @@ -29973,6 +31420,10 @@ snapshots: on-headers@1.1.0: {} + once@1.3.3: + dependencies: + wrappy: 1.0.2 + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -30108,6 +31559,8 @@ snapshots: os-homedir@1.0.2: {} + os-paths@4.4.0: {} + outvariant@1.4.0: {} oxc-parser@0.120.0: @@ -30158,6 +31611,32 @@ snapshots: '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 + oxc-transform@0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): + optionalDependencies: + '@oxc-transform/binding-android-arm-eabi': 0.111.0 + '@oxc-transform/binding-android-arm64': 0.111.0 + '@oxc-transform/binding-darwin-arm64': 0.111.0 + '@oxc-transform/binding-darwin-x64': 0.111.0 + '@oxc-transform/binding-freebsd-x64': 0.111.0 + '@oxc-transform/binding-linux-arm-gnueabihf': 0.111.0 + '@oxc-transform/binding-linux-arm-musleabihf': 0.111.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.111.0 + '@oxc-transform/binding-linux-arm64-musl': 0.111.0 + '@oxc-transform/binding-linux-ppc64-gnu': 0.111.0 + '@oxc-transform/binding-linux-riscv64-gnu': 0.111.0 + '@oxc-transform/binding-linux-riscv64-musl': 0.111.0 + '@oxc-transform/binding-linux-s390x-gnu': 0.111.0 + '@oxc-transform/binding-linux-x64-gnu': 0.111.0 + '@oxc-transform/binding-linux-x64-musl': 0.111.0 + '@oxc-transform/binding-openharmony-arm64': 0.111.0 + '@oxc-transform/binding-wasm32-wasi': 0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@oxc-transform/binding-win32-arm64-msvc': 0.111.0 + '@oxc-transform/binding-win32-ia32-msvc': 0.111.0 + '@oxc-transform/binding-win32-x64-msvc': 0.111.0 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + oxfmt@0.40.0: dependencies: tinypool: 2.1.0 @@ -30221,6 +31700,8 @@ snapshots: p-finally@1.0.0: {} + p-finally@2.0.1: {} + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -30269,6 +31750,24 @@ snapshots: p-try@2.2.0: {} + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.4 + debug: 4.4.3 + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.1.1 + package-hash@4.0.0: dependencies: graceful-fs: 4.2.11 @@ -30350,6 +31849,8 @@ snapshots: lru-cache: 11.2.7 minipass: 7.1.3 + path-to-regexp@6.3.0: {} + path-to-regexp@8.4.2: {} path-type@4.0.0: {} @@ -30367,6 +31868,8 @@ snapshots: sha.js: 2.4.12 to-buffer: 1.2.2 + pend@1.2.0: {} + pg-cloudflare@1.3.0: optional: true @@ -30402,6 +31905,8 @@ snapshots: dependencies: split2: 4.2.0 + picocolors@1.0.0: {} + picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -30614,6 +32119,8 @@ snapshots: dependencies: asap: 2.0.6 + promisepipe@3.0.0: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -30643,6 +32150,19 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.4.0: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + proxy-from-env@1.1.0: {} proxy-from-env@2.1.0: {} @@ -30722,6 +32242,13 @@ snapshots: dependencies: '@silvia-odwyer/photon-node': 0.3.4 + raw-body@2.4.1: + dependencies: + bytes: 3.1.0 + http-errors: 1.7.3 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -31086,6 +32613,8 @@ snapshots: dependencies: picomatch: 2.3.2 + readdirp@4.1.2: {} + readdirp@5.0.0: {} recast@0.23.11: @@ -31365,6 +32894,28 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 + rolldown@1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): + dependencies: + '@oxc-project/types': 0.110.0 + '@rolldown/pluginutils': 1.0.0-rc.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.1 + '@rolldown/binding-darwin-x64': 1.0.0-rc.1 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.1 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.1 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.1 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + rolldown@1.0.0-rc.17: dependencies: '@oxc-project/types': 0.127.0 @@ -31499,6 +33050,16 @@ snapshots: safer-buffer@2.1.2: {} + sandbox@2.5.6: + dependencies: + '@vercel/sandbox': 1.9.0 + debug: 4.4.3 + zod: 4.4.3 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + - supports-color + sass-loader@16.0.7(webpack@5.105.4(esbuild@0.27.4)): dependencies: neo-async: 2.6.2 @@ -31537,6 +33098,10 @@ snapshots: semver@6.3.1: {} + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + semver@7.6.3: {} semver@7.7.3: {} @@ -31612,6 +33177,8 @@ snapshots: setimmediate@1.0.5: {} + setprototypeof@1.1.1: {} + setprototypeof@1.2.0: {} sf-symbols-typescript@2.2.0: {} @@ -31695,6 +33262,8 @@ snapshots: signal-exit@3.0.7: {} + signal-exit@4.0.2: {} + signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -31744,8 +33313,25 @@ snapshots: slugify@1.6.8: {} + smart-buffer@4.2.0: {} + + smol-toml@1.5.2: {} + smol-toml@1.6.0: {} + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.9 + transitivePeerDependencies: + - supports-color + + socks@2.8.9: + dependencies: + ip-address: 10.2.0 + smart-buffer: 4.2.0 + sonner-native@0.23.1(87a488248bd28430641b1320077ef29b): dependencies: react: 19.2.0 @@ -31829,6 +33415,10 @@ snapshots: sqlite-vec-windows-x64: 0.1.9 optional: true + srvx@0.8.9: + dependencies: + cookie-es: 2.0.1 + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -31846,6 +33436,8 @@ snapshots: '@stablelib/base64': 1.0.1 fast-sha256: 1.3.0 + stat-mode@0.3.0: {} + state-local@1.0.7: {} static-browser-server@1.0.3: @@ -31901,6 +33493,12 @@ snapshots: dependencies: any-promise: 1.3.0 + stream-to-promise@2.2.0: + dependencies: + any-promise: 1.3.0 + end-of-stream: 1.1.0 + stream-to-array: 2.3.0 + streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -32096,6 +33694,15 @@ snapshots: tapable@2.3.0: {} + tar-stream@3.1.7: + dependencies: + b4a: 1.8.0 + fast-fifo: 1.3.2 + streamx: 2.23.0 + transitivePeerDependencies: + - bare-abort-controller + - react-native-b4a + tar-stream@3.1.8: dependencies: b4a: 1.8.0 @@ -32134,6 +33741,14 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 + tar@7.5.7: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + teex@1.0.1: dependencies: streamx: 2.23.0 @@ -32200,6 +33815,12 @@ snapshots: throat@5.0.0: {} + throttleit@2.1.0: {} + + time-span@4.0.0: + dependencies: + convert-hrtime: 3.0.0 + timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 @@ -32208,6 +33829,8 @@ snapshots: tinybench@2.9.0: {} + tinyexec@0.3.2: {} + tinyexec@1.0.4: {} tinyglobby@0.2.16: @@ -32243,6 +33866,8 @@ snapshots: toad-cache@3.7.0: {} + toidentifier@1.0.0: {} + toidentifier@1.0.1: {} token-types@6.1.2: @@ -32336,6 +33961,13 @@ snapshots: ts-mixer@6.0.4: {} + ts-morph@12.0.0: + dependencies: + '@ts-morph/common': 0.11.1 + code-block-writer: 10.1.1 + + ts-toolbelt@6.15.5: {} + tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 @@ -32411,6 +34043,8 @@ snapshots: uhyphen@0.2.0: {} + uid-promise@1.0.0: {} + uint8array-extras@1.5.0: {} ulid@3.0.2: {} @@ -32419,12 +34053,18 @@ snapshots: uncrypto@0.1.3: {} + undici-types@5.26.5: {} + undici-types@6.21.0: {} undici-types@7.16.0: {} undici-types@7.18.2: {} + undici@5.28.4: + dependencies: + '@fastify/busboy': 2.1.1 + undici@6.24.1: {} undici@7.25.0: {} @@ -32650,6 +34290,50 @@ snapshots: - '@types/react' - '@types/react-dom' + vercel@53.3.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1): + dependencies: + '@vercel/backends': 0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) + '@vercel/blob': 2.3.0 + '@vercel/build-utils': 13.22.0 + '@vercel/cli-config': 0.1.1 + '@vercel/detect-agent': 1.2.3 + '@vercel/elysia': 0.1.74(rollup@4.59.1) + '@vercel/express': 0.1.84(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) + '@vercel/fastify': 0.1.77(rollup@4.59.1) + '@vercel/fun': 1.3.0 + '@vercel/go': 3.6.0 + '@vercel/h3': 0.1.83(rollup@4.59.1) + '@vercel/hono': 0.2.77(rollup@4.59.1) + '@vercel/hydrogen': 1.3.7 + '@vercel/koa': 0.1.57(rollup@4.59.1) + '@vercel/nestjs': 0.2.78(rollup@4.59.1) + '@vercel/next': 4.17.1(rollup@4.59.1) + '@vercel/node': 5.7.16(rollup@4.59.1) + '@vercel/prepare-flags-definitions': 0.2.1 + '@vercel/python': 6.39.0 + '@vercel/redwood': 2.4.13(rollup@4.59.1) + '@vercel/remix-builder': 5.8.1(rollup@4.59.1) + '@vercel/ruby': 2.3.2 + '@vercel/rust': 1.2.0 + '@vercel/static-build': 2.9.23 + chokidar: 4.0.0 + esbuild: 0.27.4 + form-data: 4.0.5 + jose: 5.9.6 + luxon: 3.7.2 + proxy-agent: 6.4.0 + sandbox: 2.5.6 + smol-toml: 1.5.2 + zod: 4.1.11 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - bare-abort-controller + - encoding + - react-native-b4a + - rollup + - supports-color + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 @@ -32725,7 +34409,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.4 - vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@22.19.19)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -32748,6 +34432,7 @@ snapshots: vite: 8.0.10(@types/node@22.19.19)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: + '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 22.19.19 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -32766,7 +34451,7 @@ snapshots: - tsx - yaml - vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -32789,6 +34474,7 @@ snapshots: vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: + '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 24.12.4 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -32807,7 +34493,7 @@ snapshots: - tsx - yaml - vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -32830,6 +34516,7 @@ snapshots: vite: 8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: + '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 25.5.2 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -32908,6 +34595,8 @@ snapshots: web-tree-sitter@0.26.9: {} + web-vitals@0.2.4: {} + web-vitals@5.1.0: {} webidl-conversions@3.0.1: {} @@ -33197,6 +34886,19 @@ snapshots: simple-plist: 1.3.1 uuid: 7.0.3 + xdg-app-paths@5.1.0: + dependencies: + xdg-portable: 7.3.0 + + xdg-app-paths@5.5.1: + dependencies: + os-paths: 4.4.0 + xdg-portable: 7.3.0 + + xdg-portable@7.3.0: + dependencies: + os-paths: 4.4.0 + xml2js@0.6.0: dependencies: sax: 1.6.0 @@ -33259,6 +34961,20 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl-clone@1.0.4: + dependencies: + events-intercept: 2.0.0 + + yauzl-promise@2.1.3: + dependencies: + yauzl: 2.10.0 + yauzl-clone: 1.0.4 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} yocto-queue@1.2.2: {} @@ -33292,8 +35008,14 @@ snapshots: dependencies: zod: 4.4.3 + zod@3.22.4: {} + + zod@3.24.4: {} + zod@3.25.76: {} + zod@4.1.11: {} + zod@4.1.8: {} zod@4.3.6: {} diff --git a/scripts/lint-all.sh b/scripts/lint-all.sh index 88c85a31d..a2b65908f 100755 --- a/scripts/lint-all.sh +++ b/scripts/lint-all.sh @@ -6,7 +6,7 @@ set -euo pipefail PATH="node_modules/.bin:$PATH" -lint_dirs=(apps/web/src) +lint_dirs=(apps/web/src scripts/web-env) mobile_lint_dirs=() # Resolve workspace directories using pnpm (handles glob expansion) diff --git a/scripts/typecheck-all.sh b/scripts/typecheck-all.sh index f9d8da334..412881e6a 100755 --- a/scripts/typecheck-all.sh +++ b/scripts/typecheck-all.sh @@ -42,8 +42,9 @@ else pnpm --filter @kilocode/trpc run build fi -# 2. Root typecheck (always — it's fast with incremental tsgo) +# 2. Root typechecks (always — they are fast with incremental tsgo) tsgo --noEmit -p apps/web/tsconfig.json +tsgo --noEmit -p scripts/web-env/tsconfig.json # 3. Workspace typecheck if ! $changes_only; then diff --git a/scripts/web-env/adapters.test.ts b/scripts/web-env/adapters.test.ts new file mode 100644 index 000000000..994b3789d --- /dev/null +++ b/scripts/web-env/adapters.test.ts @@ -0,0 +1,210 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import type { CommandExecutor, CommandRequest, CommandResult } from './command.js'; +import { OnePasswordAdapter } from './onepassword.js'; +import { VercelAdapter } from './vercel.js'; + +function success(stdout: string): CommandResult { + return { status: 0, stdout, stderr: '' }; +} + +void test('Vercel adapter uses isolated project IDs and passes values only through stdin', async () => { + const requests: CommandRequest[] = []; + const execute: CommandExecutor = async request => { + requests.push(request); + const args = request.args; + if (args.includes('--version')) return success('Vercel CLI 53.3.1'); + if (args.includes('whoami')) { + return success(JSON.stringify({ team: { id: 'team_test', slug: 'kilocode' } })); + } + if (args.includes('project') && args.includes('list')) { + const filterIndex = args.indexOf('--filter'); + const name = args[filterIndex + 1]; + return success(JSON.stringify({ projects: [{ id: `id-${name}`, name }] })); + } + if (args.includes('target') && args.includes('list')) { + return success(JSON.stringify({ targets: [{ id: 'env_staging', slug: 'staging' }] })); + } + if (args.includes('api')) { + return success( + JSON.stringify({ env: { API_TOKEN: 'literal\\nsequence {"key":"value"} C:\\temp' } }) + ); + } + if (args.includes('env') && args.includes('add')) return success('{}'); + if (args.includes('env') && args.includes('list')) { + return success(JSON.stringify({ envs: [{ key: 'API_TOKEN', type: 'sensitive' }] })); + } + throw new Error(`Unexpected fake command: ${args.join(' ')}`); + }; + + const adapter = new VercelAdapter(execute, '/private/temp'); + await adapter.initialize(); + await adapter.writeVariable({ + mode: 'add', + project: 'kilocode-app', + environment: 'production', + key: 'API_TOKEN', + value: 'super-secret-value', + sensitive: true, + expectedType: 'sensitive', + }); + await adapter.writeVariable({ + mode: 'add', + project: 'kilocode-app', + environment: 'staging', + key: 'API_TOKEN', + value: 'staging-secret-value', + sensitive: true, + expectedType: 'sensitive', + }); + + const write = requests.find( + request => request.args.includes('add') && request.args.includes('production') + ); + assert.ok(write); + assert.equal(write.stdin, 'super-secret-value'); + assert.equal(write.args.includes('super-secret-value'), false); + assert.equal(write.cwd, '/private/temp'); + assert.equal(write.env?.VERCEL_ORG_ID, 'team_test'); + assert.equal(write.env?.VERCEL_PROJECT_ID, 'id-kilocode-app'); + const stagingWrite = requests.find( + request => request.args.includes('add') && request.args.includes('env_staging') + ); + assert.ok(stagingWrite); + assert.equal(stagingWrite.args.includes('staging'), false); + assert.equal( + await adapter.pullReadableValue('kilocode-app', 'production', 'API_TOKEN'), + 'literal\\nsequence {"key":"value"} C:\\temp' + ); + const pull = requests.find(request => + request.args.includes('/v3/env/pull/id-kilocode-app/production?source=vercel-cli%3Aenv%3Apull') + ); + assert.ok(pull); + assert.ok( + requests.every(request => request.cwd === undefined || request.cwd === '/private/temp') + ); +}); + +void test('Vercel adapter keeps sensitive development values exportable', async () => { + const requests: CommandRequest[] = []; + const execute: CommandExecutor = async request => { + requests.push(request); + if (request.args.includes('--version')) return success('53.3.1'); + if (request.args.includes('whoami')) { + return success(JSON.stringify({ team: { id: 'team_test', slug: 'kilocode' } })); + } + if (request.args.includes('project')) { + const name = request.args[request.args.indexOf('--filter') + 1]; + return success(JSON.stringify({ projects: [{ id: `id-${name}`, name }] })); + } + if (request.args.includes('target')) { + return success(JSON.stringify({ targets: [{ id: 'env_staging', slug: 'staging' }] })); + } + if (request.args.includes('add')) return success('{}'); + if (request.args.includes('list')) { + return success(JSON.stringify({ envs: [{ key: 'TOKEN', type: 'encrypted' }] })); + } + throw new Error('Unexpected fake command'); + }; + const adapter = new VercelAdapter(execute, '/private/temp'); + await adapter.initialize(); + await adapter.writeVariable({ + mode: 'add', + project: 'kilocode-app', + environment: 'development', + key: 'TOKEN', + value: 'development-secret', + sensitive: false, + expectedType: 'encrypted', + }); + const write = requests.find(request => request.args.includes('add')); + assert.ok(write?.args.includes('--no-sensitive')); + assert.equal(write?.args.includes('--sensitive'), false); +}); + +void test('1Password preflight rejects duplicate or malformed existing items', async () => { + const duplicates: CommandExecutor = async request => { + if (request.args[0] === '--version') return success('2.32.0'); + if (request.args[0] === 'whoami') return success('{}'); + if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); + if (request.args[0] === 'item' && request.args[1] === 'list') { + return success( + JSON.stringify([ + { id: 'one', title: 'API_TOKEN' }, + { id: 'two', title: 'API_TOKEN' }, + ]) + ); + } + throw new Error('Unexpected fake command'); + }; + const duplicateAdapter = new OnePasswordAdapter(duplicates); + await duplicateAdapter.initialize(); + await assert.rejects( + duplicateAdapter.validateExistingItem('API_TOKEN'), + /Multiple 1Password items/ + ); + + const malformed: CommandExecutor = async request => { + if (request.args[0] === '--version') return success('2.32.0'); + if (request.args[0] === 'whoami') return success('{}'); + if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); + if (request.args[0] === 'item' && request.args[1] === 'list') { + return success(JSON.stringify([{ id: 'one', title: 'API_TOKEN' }])); + } + if (request.args[0] === 'item' && request.args[1] === 'get') { + return success( + JSON.stringify({ + id: 'one', + fields: [{ id: 'password', label: 'password', type: 'STRING', value: '' }], + }) + ); + } + throw new Error('Unexpected fake command'); + }; + const malformedAdapter = new OnePasswordAdapter(malformed); + await malformedAdapter.initialize(); + await assert.rejects(malformedAdapter.validateExistingItem('API_TOKEN'), /password field/); +}); + +void test('1Password adapter creates and verifies an exact-name concealed item', async () => { + const requests: CommandRequest[] = []; + const execute: CommandExecutor = async request => { + requests.push(request); + if (request.args[0] === '--version') return success('2.32.0'); + if (request.args[0] === 'whoami') return success('{}'); + if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); + if (request.args[0] === 'item' && request.args[1] === 'list') return success('[]'); + if (request.args[0] === 'item' && request.args[1] === 'template') { + return success( + JSON.stringify({ + title: '', + category: 'PASSWORD', + fields: [{ id: 'password', label: 'password', type: 'CONCEALED', value: '' }], + }) + ); + } + if (request.args[0] === 'item' && request.args[1] === 'create') { + return success(JSON.stringify({ id: 'item_test' })); + } + if ( + request.args[0] === 'item' && + request.args[1] === 'get' && + request.args.includes('--fields') + ) { + return success( + JSON.stringify({ id: 'password', type: 'CONCEALED', value: 'production-secret' }) + ); + } + throw new Error(`Unexpected fake command: ${request.args.join(' ')}`); + }; + + const adapter = new OnePasswordAdapter(execute); + await adapter.initialize(); + await adapter.writeProductionValue('add', 'API_TOKEN', 'production-secret'); + + const create = requests.find(request => request.args[1] === 'create'); + assert.ok(create?.stdin?.includes('production-secret')); + assert.equal(create?.args.includes('production-secret'), false); + assert.ok(create?.stdin?.includes('API_TOKEN')); + assert.ok(create?.args.includes('vault_test')); +}); diff --git a/scripts/web-env/apply.test.ts b/scripts/web-env/apply.test.ts new file mode 100644 index 000000000..2a474ad87 --- /dev/null +++ b/scripts/web-env/apply.test.ts @@ -0,0 +1,116 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, readFile, rm } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { applyRemoteChanges, PartialRemoteFailureError } from './apply.js'; +import type { OnePasswordAdapter } from './onepassword.js'; +import type { VercelAdapter } from './vercel.js'; + +const values = { + development: 'development-secret-value', + staging: 'staging-secret-value', + production: 'production-secret-value', +}; + +void test('remote apply stops on first failure and writes a value-free resume journal', async () => { + const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-apply-test-')); + const calls: string[] = []; + const vercel = { + writeVariable: async (input: Parameters[0]) => { + const id = `${input.project}/${input.environment}`; + calls.push(id); + if (id === 'kilocode-app/staging') throw new Error('provider included a secret'); + }, + }; + const onePassword = { + writeProductionValue: async () => { + calls.push('1Password'); + }, + }; + + try { + let failure: PartialRemoteFailureError | undefined; + try { + await applyRemoteChanges({ + repoRoot: root, + mode: 'update', + variableName: 'API_TOKEN', + sensitive: true, + values, + vercel, + onePassword, + now: () => new Date('2026-06-16T12:00:00.000Z'), + }); + } catch (error) { + if (error instanceof PartialRemoteFailureError) failure = error; + else throw error; + } + assert.ok(failure); + assert.deepEqual(calls, [ + 'kilocode-app/development', + 'kilocode-global-app/development', + 'kilocode-app/staging', + ]); + assert.deepEqual(failure.journal.completed, [ + 'kilocode-app/development', + 'kilocode-global-app/development', + ]); + assert.equal(failure.journal.failed, 'kilocode-app/staging'); + const journal = await readFile(path.join(root, failure.journalPath), 'utf8'); + assert.equal(journal.includes('secret-value'), false); + assert.equal(journal.includes('provider included a secret'), false); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +void test('non-sensitive apply skips 1Password after writing the full matrix', async () => { + const calls: string[] = []; + const vercel = { + writeVariable: async (input: Parameters[0]) => { + calls.push(`${input.project}/${input.environment}/${input.expectedType}`); + }, + }; + const onePassword = { + writeProductionValue: async () => { + calls.push('1Password'); + }, + }; + await applyRemoteChanges({ + repoRoot: '/unused', + mode: 'add', + variableName: 'FEATURE_FLAG', + sensitive: false, + values, + vercel, + onePassword, + }); + assert.equal(calls.length, 6); + assert.ok(calls.every(call => call.endsWith('/encrypted'))); + assert.equal(calls.includes('1Password'), false); +}); + +void test('sensitive apply sends only the production value to 1Password', async () => { + const received: string[] = []; + const vercel = { + writeVariable: async () => undefined, + }; + const onePassword = { + writeProductionValue: async ( + ...input: Parameters + ) => { + received.push(input[2]); + }, + }; + await applyRemoteChanges({ + repoRoot: '/unused', + mode: 'update', + variableName: 'API_TOKEN', + sensitive: true, + values, + vercel, + onePassword, + }); + assert.deepEqual(received, ['production-secret-value']); +}); diff --git a/scripts/web-env/apply.ts b/scripts/web-env/apply.ts new file mode 100644 index 000000000..73b4e289b --- /dev/null +++ b/scripts/web-env/apply.ts @@ -0,0 +1,82 @@ +import type { OnePasswordAdapter } from './onepassword.js'; +import { buildWriteOperations, type EnvironmentValues, type WebEnvMode } from './plan.js'; +import { operationId, writeResumeJournal, type ResumeJournal } from './resume.js'; +import type { VercelAdapter } from './vercel.js'; + +export class PartialRemoteFailureError extends Error { + readonly journal: ResumeJournal; + readonly journalPath: string; + + constructor(journal: ResumeJournal, journalPath: string) { + super(`Remote update stopped at ${journal.failed}. Provider output was redacted.`); + this.journal = journal; + this.journalPath = journalPath; + } +} + +export async function applyRemoteChanges(options: { + repoRoot: string; + mode: WebEnvMode; + variableName: string; + sensitive: boolean; + values: EnvironmentValues; + vercel: Pick; + onePassword: Pick; + now?: () => Date; +}): Promise { + const now = options.now ?? (() => new Date()); + const operations = buildWriteOperations(options.sensitive); + const completed: string[] = []; + + for (let index = 0; index < operations.length; index += 1) { + const operation = operations[index]; + if (!operation) continue; + try { + await options.vercel.writeVariable({ + mode: options.mode, + project: operation.project, + environment: operation.environment, + key: options.variableName, + value: options.values[operation.environment], + sensitive: operation.sensitive, + expectedType: operation.expectedType, + }); + completed.push(operationId(operation)); + } catch { + const journal: ResumeJournal = { + version: 1, + variableName: options.variableName, + sensitive: options.sensitive, + createdAt: now().toISOString(), + completed, + failed: operationId(operation), + pending: operations.slice(index + 1).map(operationId), + onePassword: options.sensitive ? 'pending' : 'skipped', + }; + const journalPath = await writeResumeJournal(options.repoRoot, journal); + throw new PartialRemoteFailureError(journal, journalPath); + } + } + + if (!options.sensitive) return; + try { + await options.onePassword.writeProductionValue( + options.mode, + options.variableName, + options.values.production + ); + } catch { + const journal: ResumeJournal = { + version: 1, + variableName: options.variableName, + sensitive: true, + createdAt: now().toISOString(), + completed, + failed: '1Password', + pending: [], + onePassword: 'failed', + }; + const journalPath = await writeResumeJournal(options.repoRoot, journal); + throw new PartialRemoteFailureError(journal, journalPath); + } +} diff --git a/scripts/web-env/backfill-report.ts b/scripts/web-env/backfill-report.ts new file mode 100644 index 000000000..414195cba --- /dev/null +++ b/scripts/web-env/backfill-report.ts @@ -0,0 +1,38 @@ +export type BackfillReport = { + migrated: string[]; + alreadySensitive: string[]; + productionMismatches: string[]; + stagingUnresolved: string[]; + skipped: string[]; + failed: string[]; +}; + +export function createBackfillReport(): BackfillReport { + return { + migrated: [], + alreadySensitive: [], + productionMismatches: [], + stagingUnresolved: [], + skipped: [], + failed: [], + }; +} + +export function formatBackfillReport(report: BackfillReport, timestamp: string): string { + const sections: [string, string[]][] = [ + ['Migrated to 1Password and converted to sensitive', report.migrated], + ['Already sensitive and missing from 1Password', report.alreadySensitive], + ['Unresolved cross-project production mismatches', report.productionMismatches], + ['Unresolved staging mismatches or inaccessible state', report.stagingUnresolved], + ['Operator-skipped non-secrets', report.skipped], + ['Failed or partially converted variables', report.failed], + ]; + const lines = [`Web environment backfill report - ${timestamp}`]; + for (const [heading, variables] of sections) { + lines.push('', heading); + lines.push( + ...(variables.length === 0 ? ['- None'] : variables.sort().map(name => `- ${name}`)) + ); + } + return lines.join('\n'); +} diff --git a/scripts/web-env/backfill.test.ts b/scripts/web-env/backfill.test.ts new file mode 100644 index 000000000..c24d78c5d --- /dev/null +++ b/scripts/web-env/backfill.test.ts @@ -0,0 +1,22 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { createBackfillReport, formatBackfillReport } from './backfill-report.js'; + +void test('backfill report is copyable and contains statuses without values', () => { + const report = createBackfillReport(); + report.migrated.push('POSTGRES_URL'); + report.alreadySensitive.push('NEXTAUTH_SECRET'); + report.productionMismatches.push('MISMATCHED_TOKEN'); + report.stagingUnresolved.push('STAGING_TOKEN'); + report.skipped.push('PUBLIC_ID'); + report.failed.push('FAILED_TOKEN'); + + const output = formatBackfillReport(report, '2026-06-16T12:00:00.000Z'); + assert.match(output, /POSTGRES_URL/); + assert.match(output, /NEXTAUTH_SECRET/); + assert.match(output, /MISMATCHED_TOKEN/); + assert.match(output, /STAGING_TOKEN/); + assert.match(output, /PUBLIC_ID/); + assert.match(output, /FAILED_TOKEN/); + assert.equal(output.includes('production-secret-value'), false); +}); diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts new file mode 100644 index 000000000..e212d6859 --- /dev/null +++ b/scripts/web-env/backfill.ts @@ -0,0 +1,199 @@ +import { chmod, mkdtemp, rm } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { createBackfillReport, formatBackfillReport } from './backfill-report.js'; +import { executeCommand } from './command.js'; +import { OnePasswordAdapter } from './onepassword.js'; +import { createTerminalPrompts } from './prompts.js'; +import { WEB_ENV_PROJECTS, type VariableMetadata } from './plan.js'; +import { VercelAdapter } from './vercel.js'; + +function byKey(variables: VariableMetadata[]): Map { + return new Map(variables.map(variable => [variable.key, variable])); +} + +async function main(): Promise { + const confirmed = await createTerminalPrompts().confirm( + 'This temporary migration changes production and staging Vercel metadata. Continue?' + ); + if (!confirmed) { + console.log('Cancelled.'); + return; + } + + const prompts = createTerminalPrompts(); + const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'kilo-web-env-backfill-')); + await chmod(tempRoot, 0o700); + const vercel = new VercelAdapter(executeCommand, tempRoot); + const onePassword = new OnePasswordAdapter(executeCommand); + const report = createBackfillReport(); + + try { + await vercel.initialize(); + await onePassword.initialize(); + + const appProduction = byKey(await vercel.listVariables('kilocode-app', 'production')); + const globalProduction = byKey(await vercel.listVariables('kilocode-global-app', 'production')); + const names = [...new Set([...appProduction.keys(), ...globalProduction.keys()])].sort(); + + for (const variableName of names) { + const appMetadata = appProduction.get(variableName); + const globalMetadata = globalProduction.get(variableName); + if (appMetadata?.type === 'system' || globalMetadata?.type === 'system') continue; + if (!appMetadata || !globalMetadata) { + report.productionMismatches.push(variableName); + continue; + } + if (appMetadata.type === 'sensitive' && globalMetadata.type === 'sensitive') { + report.alreadySensitive.push(variableName); + continue; + } + if (appMetadata.type === 'sensitive' || globalMetadata.type === 'sensitive') { + report.productionMismatches.push(variableName); + continue; + } + + let mutationStarted = false; + let activeOperation = 'read-only discovery'; + const completedOperations: string[] = []; + let plannedOperations: string[] = []; + try { + const appProductionValue = await vercel.pullReadableValue( + 'kilocode-app', + 'production', + variableName + ); + const globalProductionValue = await vercel.pullReadableValue( + 'kilocode-global-app', + 'production', + variableName + ); + if ( + appProductionValue === undefined || + globalProductionValue === undefined || + appProductionValue !== globalProductionValue + ) { + report.productionMismatches.push(variableName); + continue; + } + + const isSecret = await prompts.confirm(`Store ${variableName} as a production secret?`); + if (!isSecret) { + report.skipped.push(variableName); + continue; + } + + const appStaging = await vercel.getVariable('kilocode-app', 'staging', variableName); + const globalStaging = await vercel.getVariable( + 'kilocode-global-app', + 'staging', + variableName + ); + let stagingValue: string | undefined; + const stagingAlreadySensitive = + appStaging?.type === 'sensitive' && globalStaging?.type === 'sensitive'; + if (!stagingAlreadySensitive) { + if ( + !appStaging || + !globalStaging || + appStaging.type === 'sensitive' || + globalStaging.type === 'sensitive' + ) { + report.stagingUnresolved.push(variableName); + continue; + } + const appStagingValue = await vercel.pullReadableValue( + 'kilocode-app', + 'staging', + variableName + ); + const globalStagingValue = await vercel.pullReadableValue( + 'kilocode-global-app', + 'staging', + variableName + ); + if ( + appStagingValue === undefined || + globalStagingValue === undefined || + appStagingValue !== globalStagingValue + ) { + report.stagingUnresolved.push(variableName); + continue; + } + stagingValue = appStagingValue; + } + + if (await onePassword.findItem(variableName)) { + report.failed.push(`${variableName} (1Password item already exists)`); + continue; + } + + plannedOperations = [ + '1Password', + ...WEB_ENV_PROJECTS.map(project => `${project}/production`), + ...(stagingValue === undefined + ? [] + : WEB_ENV_PROJECTS.map(project => `${project}/staging`)), + ]; + activeOperation = '1Password'; + mutationStarted = true; + await onePassword.writeProductionValue('add', variableName, appProductionValue); + completedOperations.push(activeOperation); + + for (const project of WEB_ENV_PROJECTS) { + activeOperation = `${project}/production`; + await vercel.writeVariable({ + mode: 'resume', + project, + environment: 'production', + key: variableName, + value: appProductionValue, + sensitive: true, + expectedType: 'sensitive', + }); + completedOperations.push(activeOperation); + } + if (stagingValue !== undefined) { + for (const project of WEB_ENV_PROJECTS) { + activeOperation = `${project}/staging`; + await vercel.writeVariable({ + mode: 'resume', + project, + environment: 'staging', + key: variableName, + value: stagingValue, + sensitive: true, + expectedType: 'sensitive', + }); + completedOperations.push(activeOperation); + } + } + report.migrated.push(variableName); + } catch { + if (!mutationStarted) { + report.failed.push(variableName); + continue; + } + const pending = plannedOperations.filter( + operation => operation !== activeOperation && !completedOperations.includes(operation) + ); + report.failed.push( + `${variableName} (completed: ${completedOperations.join(', ') || 'none'}; failed: ${activeOperation}; pending: ${pending.join(', ') || 'none'})` + ); + throw new Error( + `Backfill stopped after a partial mutation of ${variableName}. Use the value-free report to reconcile it before retrying.` + ); + } + } + } finally { + await rm(tempRoot, { recursive: true, force: true }); + console.log(`\n${formatBackfillReport(report, new Date().toISOString())}`); + } +} + +main().catch(error => { + console.error( + error instanceof Error ? error.message : 'Backfill failed. Provider output was redacted.' + ); + process.exitCode = 1; +}); diff --git a/scripts/web-env/command.ts b/scripts/web-env/command.ts new file mode 100644 index 000000000..868178cf6 --- /dev/null +++ b/scripts/web-env/command.ts @@ -0,0 +1,72 @@ +import { spawn } from 'node:child_process'; + +export type CommandRequest = { + command: string; + args: string[]; + cwd?: string; + env?: NodeJS.ProcessEnv; + stdin?: string; + timeoutMs?: number; +}; + +export type CommandResult = { + status: number; + stdout: string; + stderr: string; +}; + +export type CommandExecutor = (request: CommandRequest) => Promise; + +export const executeCommand: CommandExecutor = request => + new Promise((resolve, reject) => { + const child = spawn(request.command, request.args, { + cwd: request.cwd, + env: request.env, + stdio: ['pipe', 'pipe', 'pipe'], + shell: false, + }); + + let stdout = ''; + let stderr = ''; + let timedOut = false; + const timeout = request.timeoutMs + ? setTimeout(() => { + timedOut = true; + child.kill('SIGTERM'); + }, request.timeoutMs) + : undefined; + + child.stdout.setEncoding('utf8'); + child.stderr.setEncoding('utf8'); + child.stdout.on('data', chunk => { + stdout += chunk; + }); + child.stderr.on('data', chunk => { + stderr += chunk; + }); + child.on('error', error => { + if (timeout) clearTimeout(timeout); + reject(error); + }); + child.on('close', code => { + if (timeout) clearTimeout(timeout); + resolve({ + status: timedOut ? 124 : (code ?? 1), + stdout, + stderr, + }); + }); + + if (request.stdin !== undefined) { + child.stdin.end(request.stdin); + } else { + child.stdin.end(); + } + }); + +export function requireSuccess(result: CommandResult, operation: string): string { + if (result.status !== 0) { + throw new Error(`${operation} failed (exit ${result.status}). Provider output was redacted.`); + } + return result.stdout; +} diff --git a/scripts/web-env/dotenv-files.test.ts b/scripts/web-env/dotenv-files.test.ts new file mode 100644 index 000000000..2751640f2 --- /dev/null +++ b/scripts/web-env/dotenv-files.test.ts @@ -0,0 +1,131 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import type { CommandExecutor } from './command.js'; +import { + applyDotenvPatches, + assertNoEnvironmentValuesInTrackedFiles, + createDotenvPatch, + discoverTrackedDotenvFiles, + patchDotenvContent, + renderDotenvPatchPreview, + restoreDotenvPatches, +} from './dotenv-files.js'; + +const fakeGit: CommandExecutor = async () => ({ + status: 0, + stdout: [ + '.env.local.example', + '.envrc', + 'apps/web/.env', + 'apps/web/.env.development.local.example', + 'apps/web/.env.test', + 'apps/web/.env.local', + 'apps/mobile/.env', + '', + ].join('\0'), + stderr: '', +}); + +void test('discovers only tracked root and apps/web dotenv defaults', async () => { + assert.deepEqual(await discoverTrackedDotenvFiles('/repo', fakeGit), [ + '.env.local.example', + 'apps/web/.env', + 'apps/web/.env.development.local.example', + 'apps/web/.env.test', + ]); +}); + +void test('patches one assignment without reformatting surrounding content', () => { + const before = "# auth\nTOKEN = 'old value'\nUNCHANGED=x\n"; + const result = patchDotenvContent(before, 'TOKEN', 'safe default'); + assert.equal(result.content, "# auth\nTOKEN = 'safe default'\nUNCHANGED=x\n"); + assert.equal(result.existed, true); +}); + +void test('appends a missing assignment and rejects duplicate keys', () => { + assert.equal( + patchDotenvContent('A=1', 'TOKEN', 'invalid-token').content, + 'A=1\nTOKEN=invalid-token\n' + ); + assert.throws( + () => patchDotenvContent('TOKEN=one\nTOKEN=two\n', 'TOKEN', 'safe'), + /more than once/ + ); +}); + +void test('restores exact pre-command content around existing edits', async () => { + const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-dotenv-test-')); + try { + await mkdir(path.join(root, 'apps', 'web'), { recursive: true }); + const file = path.join(root, 'apps', 'web', '.env.test'); + const before = '# user edit\nTOKEN=old\n'; + await writeFile(file, before); + const patch = await createDotenvPatch(root, 'apps/web/.env.test', 'TOKEN', 'invalid-token'); + await applyDotenvPatches([patch]); + assert.equal(await readFile(file, 'utf8'), '# user edit\nTOKEN=invalid-token\n'); + await restoreDotenvPatches([patch]); + assert.equal(await readFile(file, 'utf8'), before); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +void test('ignores assignment-like lines inside unrelated multiline values', () => { + const content = 'OTHER="begin\nTOKEN=embedded\nend"\nTOKEN=real\n'; + assert.equal( + patchDotenvContent(content, 'TOKEN', 'safe').content, + 'OTHER="begin\nTOKEN=embedded\nend"\nTOKEN=safe\n' + ); +}); + +void test('preserves inline comments and replaces complete multiline values', () => { + assert.equal( + patchDotenvContent('TOKEN=old-value # setup\n', 'TOKEN', 'safe').content, + 'TOKEN=safe # setup\n' + ); + assert.equal( + patchDotenvContent('TOKEN="old\nmultiline" # setup\nNEXT=x\n', 'TOKEN', 'safe default').content, + 'TOKEN="safe default" # setup\nNEXT=x\n' + ); +}); + +void test('rejects raw or escaped real values in patched and skipped tracked files', async () => { + const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-secret-guard-test-')); + try { + await mkdir(path.join(root, 'apps', 'web'), { recursive: true }); + await writeFile(path.join(root, 'apps', 'web', '.env.test'), 'OTHER="line-one\\nline-two"\n'); + await assert.rejects( + assertNoEnvironmentValuesInTrackedFiles(root, ['apps/web/.env.test'], [], { + development: 'development-real-value', + staging: 'line-one\nline-two', + production: 'production-real-value', + }), + /real environment value/ + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +void test('renders only invocation-owned dotenv lines and redacts old values', () => { + const preview = renderDotenvPatchPreview( + [ + { + relativePath: 'apps/web/.env.test', + absolutePath: '/repo/apps/web/.env.test', + before: 'UNRELATED=secret\nTOKEN=old-secret\n', + after: 'UNRELATED=secret\nTOKEN=invalid-token\n', + existed: true, + defaultValue: 'invalid-token', + }, + ], + 'TOKEN' + ); + assert.match(preview, /TOKEN=/); + assert.match(preview, /TOKEN=invalid-token/); + assert.equal(preview.includes('UNRELATED'), false); + assert.equal(preview.includes('old-secret'), false); +}); diff --git a/scripts/web-env/dotenv-files.ts b/scripts/web-env/dotenv-files.ts new file mode 100644 index 000000000..01f62517b --- /dev/null +++ b/scripts/web-env/dotenv-files.ts @@ -0,0 +1,289 @@ +import { readFile, rename, rm, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import type { CommandExecutor } from './command.js'; +import { requireSuccess } from './command.js'; +import type { EnvironmentValues } from './plan.js'; + +export type DotenvPatch = { + relativePath: string; + absolutePath: string; + before: string; + after: string; + existed: boolean; + defaultValue: string; +}; + +type ValueSpan = { + start: number; + end: number; + rawValue: string; +}; + +function isManagedDotenvPath(relativePath: string): boolean { + const normalized = relativePath.split(path.sep).join('/'); + const inScope = !normalized.includes('/') || normalized.startsWith('apps/web/'); + if (!inScope) return false; + + const basename = path.posix.basename(normalized); + if (!basename.startsWith('.env') || basename === '.envrc') return false; + if (basename.includes('.local') && !basename.includes('.example')) return false; + return true; +} + +export async function discoverTrackedDotenvFiles( + repoRoot: string, + execute: CommandExecutor +): Promise { + const result = await execute({ + command: 'git', + args: ['ls-files', '-z', '--', '.env*', 'apps/web/.env*'], + cwd: repoRoot, + }); + const stdout = requireSuccess(result, 'Tracked dotenv discovery'); + return stdout.split('\0').filter(Boolean).filter(isManagedDotenvPath).sort(); +} + +function findClosingQuote(value: string, quote: '"' | "'", start: number): number | undefined { + let escaped = false; + for (let index = start; index < value.length; index += 1) { + const character = value[index]; + if (quote === '"' && character === '\\' && !escaped) { + escaped = true; + continue; + } + if (character === quote && !escaped) return index; + escaped = false; + } + return undefined; +} + +function assignmentValueStarts(content: string, key: string): number[] { + const starts: number[] = []; + const assignmentPattern = new RegExp( + `^([ \\t]*(?:export[ \\t]+)?([A-Za-z_][A-Za-z0-9_]*)[ \\t]*=[ \\t]*)(.*)$` + ); + let openQuote: '"' | "'" | undefined; + let offset = 0; + + while (offset <= content.length) { + const newline = content.indexOf('\n', offset); + const lineEnd = newline === -1 ? content.length : newline; + const line = content.slice(offset, lineEnd); + + if (openQuote) { + if (findClosingQuote(line, openQuote, 0) !== undefined) openQuote = undefined; + } else { + const assignment = assignmentPattern.exec(line); + const prefix = assignment?.[1]; + const assignmentKey = assignment?.[2]; + const rawValue = assignment?.[3]; + if (prefix !== undefined && assignmentKey !== undefined && rawValue !== undefined) { + if (assignmentKey === key) starts.push(offset + prefix.length); + const quote = rawValue[0]; + if ( + (quote === '"' || quote === "'") && + findClosingQuote(rawValue, quote, 1) === undefined + ) { + openQuote = quote; + } + } + } + + if (newline === -1) break; + offset = newline + 1; + } + return starts; +} + +export function countKeyAssignments(content: string, key: string): number { + return assignmentValueStarts(content, key).length; +} + +function findValueSpan(content: string, key: string): ValueSpan { + const starts = assignmentValueStarts(content, key); + const start = starts[0]; + if (start === undefined) throw new Error(`Could not parse the existing ${key} assignment.`); + const quote = content[start]; + + if (quote === '"' || quote === "'") { + let escaped = false; + for (let index = start + 1; index < content.length; index += 1) { + const character = content[index]; + if (quote === '"' && character === '\\' && !escaped) { + escaped = true; + continue; + } + if (character === quote && !escaped) { + return { start, end: index + 1, rawValue: content.slice(start, index + 1) }; + } + escaped = false; + } + throw new Error(`Could not find the closing quote for ${key}.`); + } + + let lineEnd = content.indexOf('\n', start); + if (lineEnd === -1) lineEnd = content.length; + let end = lineEnd; + for (let index = start; index < lineEnd; index += 1) { + if (content[index] === '#' && (index === start || /\s/.test(content[index - 1] ?? ''))) { + end = index; + break; + } + } + while (end > start && /[ \t]/.test(content[end - 1] ?? '')) end -= 1; + return { start, end, rawValue: content.slice(start, end) }; +} + +function preferredQuote(rawValue: string): 'single' | 'double' | undefined { + if (rawValue.startsWith("'") && rawValue.endsWith("'")) return 'single'; + if (rawValue.startsWith('"') && rawValue.endsWith('"')) return 'double'; + return undefined; +} + +export function formatDotenvValue( + value: string, + quote: 'single' | 'double' | undefined = undefined +): string { + if (quote === 'single' && !value.includes("'") && !value.includes('\n')) { + return `'${value}'`; + } + const requiresQuotes = + quote === 'double' || + value.includes('\n') || + value.includes('\r') || + value.includes(' ') || + value.includes('#') || + value.includes('"') || + value.includes("'"); + if (!requiresQuotes) return value; + return `"${value + .replace(/\\/g, '\\\\') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/"/g, '\\"')}"`; +} + +export function patchDotenvContent( + content: string, + key: string, + defaultValue: string +): { content: string; existed: boolean } { + const count = countKeyAssignments(content, key); + if (count > 1) { + throw new Error(`Cannot patch ${key}: it is declared more than once in the same file.`); + } + + if (count === 1) { + const span = findValueSpan(content, key); + const replacement = formatDotenvValue(defaultValue, preferredQuote(span.rawValue)); + return { + content: `${content.slice(0, span.start)}${replacement}${content.slice(span.end)}`, + existed: true, + }; + } + + const separator = content.length === 0 || content.endsWith('\n') ? '' : '\n'; + return { + content: `${content}${separator}${key}=${formatDotenvValue(defaultValue)}\n`, + existed: false, + }; +} + +export async function createDotenvPatch( + repoRoot: string, + relativePath: string, + key: string, + defaultValue: string +): Promise { + const absolutePath = path.join(repoRoot, relativePath); + const before = await readFile(absolutePath, 'utf8'); + const patched = patchDotenvContent(before, key, defaultValue); + return { + relativePath, + absolutePath, + before, + after: patched.content, + existed: patched.existed, + defaultValue, + }; +} + +function secretRepresentations(value: string): string[] { + const representations = new Set([value, formatDotenvValue(value), JSON.stringify(value)]); + if (!value.includes("'") && !value.includes('\n')) representations.add(`'${value}'`); + return [...representations].filter(Boolean); +} + +export async function assertNoEnvironmentValuesInTrackedFiles( + repoRoot: string, + relativePaths: string[], + patches: DotenvPatch[], + values: EnvironmentValues +): Promise { + const patchesByPath = new Map(patches.map(patch => [patch.relativePath, patch])); + for (const relativePath of relativePaths) { + const patch = patchesByPath.get(relativePath); + const content = patch?.after ?? (await readFile(path.join(repoRoot, relativePath), 'utf8')); + for (const value of Object.values(values)) { + if (secretRepresentations(value).some(representation => content.includes(representation))) { + throw new Error( + `Refusing to continue: a real environment value appears in tracked file ${relativePath}.` + ); + } + } + } +} + +export function renderDotenvPatchPreview(patches: DotenvPatch[], key: string): string { + const lines: string[] = []; + for (const patch of patches) { + lines.push(`diff -- ${patch.relativePath}`); + lines.push(`@@ ${key} @@`); + if (patch.existed) lines.push(`-${key}=`); + lines.push(`+${key}=${formatDotenvValue(patch.defaultValue)}`); + } + return lines.join('\n'); +} + +async function atomicWrite(filePath: string, content: string): Promise { + const fileStat = await stat(filePath); + const temporaryPath = `${filePath}.web-env-${process.pid}-${Math.random().toString(16).slice(2)}`; + try { + await writeFile(temporaryPath, content, { mode: fileStat.mode }); + await rename(temporaryPath, filePath); + } finally { + await rm(temporaryPath, { force: true }); + } +} + +export async function applyDotenvPatches(patches: DotenvPatch[]): Promise { + const applied: DotenvPatch[] = []; + try { + for (const patch of patches) { + await atomicWrite(patch.absolutePath, patch.after); + applied.push(patch); + } + } catch (error) { + await restoreDotenvPatches(applied); + throw error; + } +} + +export async function restoreDotenvPatches(patches: DotenvPatch[]): Promise { + for (const patch of patches) { + await atomicWrite(patch.absolutePath, patch.before); + } +} + +export async function verifyDotenvPatches(patches: DotenvPatch[], key: string): Promise { + for (const patch of patches) { + const content = await readFile(patch.absolutePath, 'utf8'); + if (countKeyAssignments(content, key) !== 1) { + throw new Error(`Tracked default verification failed for ${patch.relativePath}.`); + } + const expected = patchDotenvContent(patch.before, key, patch.defaultValue).content; + if (content !== expected) { + throw new Error(`Tracked default verification failed for ${patch.relativePath}.`); + } + } +} diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts new file mode 100644 index 000000000..ed1d80ffc --- /dev/null +++ b/scripts/web-env/index.ts @@ -0,0 +1,314 @@ +import { existsSync, readFileSync } from 'node:fs'; +import { chmod, mkdtemp, readFile, rm } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { applyRemoteChanges, PartialRemoteFailureError } from './apply.js'; +import { executeCommand, requireSuccess } from './command.js'; +import { + applyDotenvPatches, + assertNoEnvironmentValuesInTrackedFiles, + countKeyAssignments, + createDotenvPatch, + discoverTrackedDotenvFiles, + renderDotenvPatchPreview, + restoreDotenvPatches, + verifyDotenvPatches, + type DotenvPatch, +} from './dotenv-files.js'; +import { OnePasswordAdapter } from './onepassword.js'; +import { + assertNonEmptyValues, + buildWriteOperations, + validateTargetPreconditions, + validateVariableName, + WEB_ENVIRONMENTS, + WEB_ENV_PROJECTS, + type EnvironmentValues, + type TargetState, + type WebEnvMode, +} from './plan.js'; +import { createTerminalPrompts, UserAbortError, type PromptDriver } from './prompts.js'; +import { readResumeJournal, type ResumeJournal } from './resume.js'; +import { VercelAdapter } from './vercel.js'; + +type CliOptions = { + mode: WebEnvMode; + variableName: string; + sensitive: boolean; + dryRun: boolean; + resumePath?: string; +}; + +function findRepoRoot(): string { + let directory = process.cwd(); + while (true) { + const packagePath = path.join(directory, 'package.json'); + if (existsSync(packagePath)) { + try { + const parsed: unknown = JSON.parse(readFileSync(packagePath, 'utf8')); + if ( + typeof parsed === 'object' && + parsed !== null && + 'name' in parsed && + parsed.name === 'kilocode-monorepo' + ) { + return directory; + } + } catch { + // Keep walking until the repository root is found. + } + } + const parent = path.dirname(directory); + if (parent === directory) throw new Error('Could not find the kilocode-monorepo root.'); + directory = parent; + } +} + +const REPO_ROOT = findRepoRoot(); + +function usage(): string { + return [ + 'Usage:', + ' pnpm web:env add VARIABLE_NAME [--no-sensitive] [--dry-run]', + ' pnpm web:env update VARIABLE_NAME [--no-sensitive] [--dry-run]', + ' pnpm web:env resume JOURNAL_PATH [--dry-run]', + ].join('\n'); +} + +async function parseArgs(args: string[]): Promise { + const mode = args[0]; + if (mode !== 'add' && mode !== 'update' && mode !== 'resume') { + throw new Error(usage()); + } + + const positional = args.filter(argument => !argument.startsWith('--')); + const flags = args.filter(argument => argument.startsWith('--')); + const unknownFlags = flags.filter(flag => flag !== '--no-sensitive' && flag !== '--dry-run'); + if (unknownFlags.length > 0) throw new Error(`Unknown option: ${unknownFlags[0]}\n\n${usage()}`); + if (positional.length !== 2) throw new Error(usage()); + + if (mode === 'resume') { + if (flags.includes('--no-sensitive')) { + throw new Error('Resume sensitivity is read from the journal; omit --no-sensitive.'); + } + const resumePath = path.resolve(REPO_ROOT, positional[1] ?? ''); + const journal = await readResumeJournal(resumePath); + return { + mode, + variableName: journal.variableName, + sensitive: journal.sensitive, + dryRun: flags.includes('--dry-run'), + resumePath, + }; + } + + return { + mode, + variableName: positional[1] ?? '', + sensitive: !flags.includes('--no-sensitive'), + dryRun: flags.includes('--dry-run'), + }; +} + +function defaultRecommendation(relativePath: string, variableName: string): string { + if (relativePath === 'apps/web/.env') return ''; + return `invalid-${variableName.toLowerCase().replaceAll('_', '-')}`; +} + +async function collectEnvironmentValues(prompts: PromptDriver): Promise { + const values: Partial = {}; + for (const environment of WEB_ENVIRONMENTS) { + const modeAnswer = await prompts.askText( + `Input mode for ${environment} (single-line/multiline)`, + 'single-line' + ); + if (modeAnswer !== 'single-line' && modeAnswer !== 'multiline') { + throw new Error('Input mode must be single-line or multiline.'); + } + values[environment] = await prompts.askSecret(`${environment} value`, modeAnswer); + } + + const development = values.development; + const staging = values.staging; + const production = values.production; + if (development === undefined || staging === undefined || production === undefined) { + throw new Error('All environment values are required.'); + } + const complete = { development, staging, production } satisfies EnvironmentValues; + assertNonEmptyValues(complete); + return complete; +} + +async function collectDotenvPatches( + prompts: PromptDriver, + variableName: string, + values: EnvironmentValues +): Promise<{ files: string[]; patches: DotenvPatch[] }> { + const files = await discoverTrackedDotenvFiles(REPO_ROOT, executeCommand); + const patches: DotenvPatch[] = []; + for (const relativePath of files) { + const content = await readFile(path.join(REPO_ROOT, relativePath), 'utf8'); + const count = countKeyAssignments(content, variableName); + if (count > 1) { + throw new Error(`${relativePath} declares ${variableName} more than once.`); + } + const status = count === 1 ? 'currently declared' : 'not declared'; + const decision = await prompts.askText( + `${relativePath} (${status}): set a safe default or skip? (set/skip)`, + 'set' + ); + if (decision === 'skip') continue; + if (decision !== 'set') throw new Error('Tracked dotenv decisions must be set or skip.'); + + const recommendation = defaultRecommendation(relativePath, variableName); + const defaultValue = await prompts.askText( + `Safe non-secret default for ${relativePath}`, + recommendation + ); + patches.push(await createDotenvPatch(REPO_ROOT, relativePath, variableName, defaultValue)); + } + await assertNoEnvironmentValuesInTrackedFiles(REPO_ROOT, files, patches, values); + return { files, patches }; +} + +function showTrackedDiff(patches: DotenvPatch[], variableName: string): void { + if (patches.length === 0) { + console.log('\nTracked defaults: all files explicitly skipped.'); + return; + } + console.log('\nTracked default diff (invocation changes only):'); + console.log(renderDotenvPatchPreview(patches, variableName)); +} + +async function runFastChecks(): Promise { + const result = await executeCommand({ + command: 'pnpm', + args: ['run', 'test:web-env'], + cwd: REPO_ROOT, + timeoutMs: 120_000, + }); + requireSuccess(result, 'Web environment script checks'); + console.log('Fast checks passed.'); +} + +function printPlan(variableName: string, sensitive: boolean, mode: WebEnvMode): void { + console.log('\nRedacted operation plan'); + console.log(`Variable: ${variableName}`); + console.log(`Mode: ${mode}`); + console.log(`Classification: ${sensitive ? 'sensitive' : 'non-sensitive'}`); + for (const operation of buildWriteOperations(sensitive)) { + console.log(`- ${operation.project}/${operation.environment}: ${operation.expectedType}`); + } + console.log(`- 1Password: ${sensitive ? 'write production value' : 'skipped'}`); + console.log('- Deployment: not triggered'); +} + +function printFailureMatrix(journal: ResumeJournal): void { + console.error('\nPartial operation status (no values):'); + for (const id of journal.completed) console.error(`- completed: ${id}`); + console.error(`- failed: ${journal.failed}`); + for (const id of journal.pending) console.error(`- pending: ${id}`); + console.error(`- 1Password: ${journal.onePassword}`); +} + +async function main(): Promise { + const options = await parseArgs(process.argv.slice(2)); + validateVariableName(options.variableName, options.sensitive); + + const prompts = createTerminalPrompts(); + const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'kilo-web-env-')); + await chmod(tempRoot, 0o700); + const vercel = new VercelAdapter(executeCommand, tempRoot); + const onePassword = new OnePasswordAdapter(executeCommand); + let patches: DotenvPatch[] = []; + let patchesApplied = false; + let remoteStarted = false; + + try { + console.log('Running read-only preflight...'); + await vercel.initialize(!options.sensitive); + if (options.sensitive) await onePassword.initialize(); + + const states: TargetState[] = []; + for (const environment of WEB_ENVIRONMENTS) { + for (const project of WEB_ENV_PROJECTS) { + states.push({ + project, + environment, + variable: await vercel.getVariable(project, environment, options.variableName), + }); + } + } + if (options.mode !== 'resume') validateTargetPreconditions(options.mode, states); + if (options.sensitive) { + const existingItem = await onePassword.validateExistingItem(options.variableName); + if (options.mode === 'add' && existingItem) { + throw new Error(`1Password already contains an item titled ${options.variableName}.`); + } + } + + const values = await collectEnvironmentValues(prompts); + if (options.mode !== 'resume') { + const trackedDefaults = await collectDotenvPatches(prompts, options.variableName, values); + patches = trackedDefaults.patches; + await applyDotenvPatches(patches); + patchesApplied = true; + await verifyDotenvPatches(patches, options.variableName); + showTrackedDiff(patches, options.variableName); + await runFastChecks(); + } + printPlan(options.variableName, options.sensitive, options.mode); + + if (options.dryRun) { + if (patchesApplied) await restoreDotenvPatches(patches); + console.log('\nDry run complete. No local or remote changes were retained.'); + return; + } + + const confirmed = await prompts.confirm('Apply this plan?'); + if (!confirmed) { + if (patchesApplied) await restoreDotenvPatches(patches); + console.log('Cancelled. Tracked files were restored; no remote changes were made.'); + return; + } + + remoteStarted = true; + try { + await applyRemoteChanges({ + repoRoot: REPO_ROOT, + mode: options.mode, + variableName: options.variableName, + sensitive: options.sensitive, + values, + vercel, + onePassword, + }); + } catch (error) { + if (error instanceof PartialRemoteFailureError) { + printFailureMatrix(error.journal); + console.error(`Resume with: pnpm web:env resume ${error.journalPath}`); + } + throw error; + } + + if (options.resumePath) await rm(options.resumePath, { force: true }); + console.log('\nEnvironment variable update completed.'); + console.log('New deployments are required before staging or production uses the new value.'); + } catch (error) { + if (patchesApplied && !remoteStarted) await restoreDotenvPatches(patches); + throw error; + } finally { + await rm(tempRoot, { recursive: true, force: true }); + } +} + +main().catch(error => { + if (error instanceof UserAbortError) { + console.error('Cancelled.'); + } else if (error instanceof Error) { + console.error(error.message); + } else { + console.error('Unexpected failure. Provider output was redacted.'); + } + process.exitCode = 1; +}); diff --git a/scripts/web-env/json.ts b/scripts/web-env/json.ts new file mode 100644 index 000000000..075cdba8d --- /dev/null +++ b/scripts/web-env/json.ts @@ -0,0 +1,43 @@ +export function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +export function parseJsonObject(json: string, operation: string): Record { + let parsed: unknown; + try { + parsed = JSON.parse(json); + } catch { + throw new Error(`${operation} returned invalid JSON. Provider output was redacted.`); + } + if (!isRecord(parsed)) { + throw new Error(`${operation} returned an unexpected response. Provider output was redacted.`); + } + return parsed; +} + +export function parseJsonRecords(json: string, operation: string): Record[] { + let parsed: unknown; + try { + parsed = JSON.parse(json); + } catch { + throw new Error(`${operation} returned invalid JSON. Provider output was redacted.`); + } + if (!Array.isArray(parsed) || !parsed.every(isRecord)) { + throw new Error(`${operation} returned an unexpected response. Provider output was redacted.`); + } + return parsed; +} + +export function readString(record: Record, key: string): string | undefined { + const value = record[key]; + return typeof value === 'string' ? value : undefined; +} + +export function readRecords( + record: Record, + key: string +): Record[] { + const value = record[key]; + if (!Array.isArray(value)) return []; + return value.filter(isRecord); +} diff --git a/scripts/web-env/onepassword.ts b/scripts/web-env/onepassword.ts new file mode 100644 index 000000000..fb4812f5f --- /dev/null +++ b/scripts/web-env/onepassword.ts @@ -0,0 +1,180 @@ +import type { CommandExecutor, CommandResult } from './command.js'; +import { requireSuccess } from './command.js'; +import { isRecord, parseJsonObject, parseJsonRecords, readString } from './json.js'; +import { WEB_ENV_VAULT } from './plan.js'; + +export class OnePasswordAdapter { + readonly #execute: CommandExecutor; + #vaultId = ''; + + constructor(execute: CommandExecutor) { + this.#execute = execute; + } + + async #run(args: string[], stdin?: string): Promise { + return this.#execute({ + command: 'op', + args, + stdin, + timeoutMs: 120_000, + }); + } + + async initialize(): Promise { + requireSuccess(await this.#run(['--version']), '1Password CLI version check'); + requireSuccess( + await this.#run(['whoami', '--format=json']), + '1Password authentication check; run op signin' + ); + const vault = parseJsonObject( + requireSuccess( + await this.#run(['vault', 'get', WEB_ENV_VAULT, '--format=json']), + `Resolve 1Password vault ${WEB_ENV_VAULT}` + ), + `Resolve 1Password vault ${WEB_ENV_VAULT}` + ); + const vaultId = readString(vault, 'id'); + if (!vaultId) throw new Error(`1Password vault ${WEB_ENV_VAULT} did not include an ID.`); + this.#vaultId = vaultId; + await this.listItems(); + } + + async listItems(): Promise<{ id: string; title: string }[]> { + if (!this.#vaultId) throw new Error('1Password vault has not been resolved.'); + const result = await this.#run(['item', 'list', '--vault', this.#vaultId, '--format=json']); + const records = parseJsonRecords( + requireSuccess(result, `List items in ${WEB_ENV_VAULT}`), + `List items in ${WEB_ENV_VAULT}` + ); + const items: { id: string; title: string }[] = []; + for (const record of records) { + const id = readString(record, 'id'); + const title = readString(record, 'title'); + if (id && title) items.push({ id, title }); + } + return items; + } + + async findItem(variableName: string): Promise<{ id: string; title: string } | undefined> { + const matches = (await this.listItems()).filter(item => item.title === variableName); + if (matches.length > 1) { + throw new Error(`Multiple 1Password items are titled ${variableName}.`); + } + return matches[0]; + } + + async #createTemplate(variableName: string, value: string): Promise { + const result = await this.#run(['item', 'template', 'get', 'Password', '--format=json']); + const template = parseJsonObject( + requireSuccess(result, 'Load 1Password Password template'), + 'Load 1Password Password template' + ); + template.title = variableName; + this.#setPasswordField(template, value); + return JSON.stringify(template); + } + + #getPasswordField(item: Record): Record { + const fields = item.fields; + if (!Array.isArray(fields)) { + throw new Error('1Password item did not include fields. Provider output was redacted.'); + } + const passwordFields = fields.filter( + field => isRecord(field) && (field.id === 'password' || field.label === 'password') + ); + if ( + passwordFields.length !== 1 || + !isRecord(passwordFields[0]) || + readString(passwordFields[0], 'type') !== 'CONCEALED' + ) { + throw new Error('1Password item did not include one concealed password field.'); + } + return passwordFields[0]; + } + + #setPasswordField(item: Record, value: string): void { + this.#getPasswordField(item).value = value; + } + + async #readItem(itemId: string, variableName: string): Promise> { + const getResult = await this.#run([ + 'item', + 'get', + itemId, + '--vault', + this.#vaultId, + '--format=json', + ]); + return parseJsonObject( + requireSuccess(getResult, `Read 1Password item ${variableName}`), + `Read 1Password item ${variableName}` + ); + } + + async validateExistingItem( + variableName: string + ): Promise<{ id: string; title: string } | undefined> { + const existing = await this.findItem(variableName); + if (!existing) return undefined; + const item = await this.#readItem(existing.id, variableName); + this.#getPasswordField(item); + return existing; + } + + async writeProductionValue( + mode: 'add' | 'update' | 'resume', + variableName: string, + value: string + ): Promise { + const existing = await this.findItem(variableName); + if (mode === 'add' && existing) { + throw new Error(`1Password already contains an item titled ${variableName}.`); + } + + let itemId: string; + if (!existing) { + const template = await this.#createTemplate(variableName, value); + const result = await this.#run( + ['item', 'create', '--vault', this.#vaultId, '--format=json', '-'], + template + ); + const created = parseJsonObject( + requireSuccess(result, `Create 1Password item ${variableName}`), + `Create 1Password item ${variableName}` + ); + const createdId = readString(created, 'id'); + if (!createdId) throw new Error(`Created 1Password item ${variableName} has no ID.`); + itemId = createdId; + } else { + const item = await this.#readItem(existing.id, variableName); + this.#setPasswordField(item, value); + const editResult = await this.#run( + ['item', 'edit', existing.id, '--vault', this.#vaultId, '--format=json'], + JSON.stringify(item) + ); + requireSuccess(editResult, `Update 1Password item ${variableName}`); + itemId = existing.id; + } + + const verifyResult = await this.#run([ + 'item', + 'get', + itemId, + '--vault', + this.#vaultId, + '--fields', + 'label=password', + '--format=json', + ]); + const passwordField = parseJsonObject( + requireSuccess(verifyResult, `Verify 1Password item ${variableName}`), + `Verify 1Password item ${variableName}` + ); + if ( + readString(passwordField, 'type') !== 'CONCEALED' || + readString(passwordField, 'value') !== value + ) { + throw new Error(`1Password verification failed for ${variableName}.`); + } + } +} diff --git a/scripts/web-env/plan.test.ts b/scripts/web-env/plan.test.ts new file mode 100644 index 000000000..a885696f1 --- /dev/null +++ b/scripts/web-env/plan.test.ts @@ -0,0 +1,56 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { + buildWriteOperations, + validateTargetPreconditions, + validateVariableName, + WEB_ENVIRONMENTS, + WEB_ENV_PROJECTS, + type TargetState, +} from './plan.js'; + +function states(present: boolean): TargetState[] { + return WEB_ENVIRONMENTS.flatMap(environment => + WEB_ENV_PROJECTS.map(project => ({ + project, + environment, + variable: present ? { key: 'API_TOKEN', type: 'encrypted' as const } : undefined, + })) + ); +} + +void test('builds the fixed project and environment matrix in risk order', () => { + const operations = buildWriteOperations(true); + assert.deepEqual( + operations.map(operation => `${operation.project}/${operation.environment}`), + [ + 'kilocode-app/development', + 'kilocode-global-app/development', + 'kilocode-app/staging', + 'kilocode-global-app/staging', + 'kilocode-app/production', + 'kilocode-global-app/production', + ] + ); + assert.deepEqual( + operations.map(operation => operation.expectedType), + ['encrypted', 'encrypted', 'sensitive', 'sensitive', 'sensitive', 'sensitive'] + ); +}); + +void test('keeps every target encrypted for non-sensitive variables', () => { + assert.ok(buildWriteOperations(false).every(operation => operation.expectedType === 'encrypted')); +}); + +void test('enforces strict add and update preconditions', () => { + assert.doesNotThrow(() => validateTargetPreconditions('add', states(false))); + assert.doesNotThrow(() => validateTargetPreconditions('update', states(true))); + assert.throws(() => validateTargetPreconditions('add', states(true)), /already exists/); + assert.throws(() => validateTargetPreconditions('update', states(false)), /missing/); +}); + +void test('requires explicit non-sensitive mode for client-exposed names', () => { + assert.throws(() => validateVariableName('NEXT_PUBLIC_API_TOKEN', true), /--no-sensitive/); + assert.doesNotThrow(() => validateVariableName('NEXT_PUBLIC_API_TOKEN', false)); + assert.throws(() => validateVariableName('bad-name', false), /uppercase/); +}); diff --git a/scripts/web-env/plan.ts b/scripts/web-env/plan.ts new file mode 100644 index 000000000..6e2c9fede --- /dev/null +++ b/scripts/web-env/plan.ts @@ -0,0 +1,84 @@ +export const WEB_ENV_PROJECTS = ['kilocode-app', 'kilocode-global-app'] as const; +export const WEB_ENVIRONMENTS = ['development', 'staging', 'production'] as const; +export const WEB_ENV_VAULT = 'Kilo Web ENV Production'; +export const VERCEL_VERSION = '53.3.1'; + +export type WebEnvProject = (typeof WEB_ENV_PROJECTS)[number]; +export type WebEnvironment = (typeof WEB_ENVIRONMENTS)[number]; +export type WebEnvMode = 'add' | 'update' | 'resume'; +export type VercelVariableType = 'plain' | 'encrypted' | 'sensitive' | 'system'; + +export type VariableMetadata = { + key: string; + type: VercelVariableType; +}; + +export type TargetState = { + project: WebEnvProject; + environment: WebEnvironment; + variable?: VariableMetadata; +}; + +export type EnvironmentValues = Record; + +export type VercelWriteOperation = { + project: WebEnvProject; + environment: WebEnvironment; + sensitive: boolean; + expectedType: 'encrypted' | 'sensitive'; +}; + +const VARIABLE_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/; + +export function validateVariableName(name: string, sensitive: boolean): void { + if (!VARIABLE_NAME_PATTERN.test(name)) { + throw new Error( + 'Variable names must use uppercase letters, digits, and underscores, and cannot start with a digit.' + ); + } + if (sensitive && name.startsWith('NEXT_PUBLIC_')) { + throw new Error('NEXT_PUBLIC_* variables are client-exposed and must use --no-sensitive.'); + } +} + +export function validateTargetPreconditions(mode: 'add' | 'update', states: TargetState[]): void { + const present = states.filter(state => state.variable !== undefined); + if (mode === 'add' && present.length > 0) { + const locations = present + .map(state => `${state.project}/${state.environment}`) + .sort() + .join(', '); + throw new Error(`Cannot add: the variable already exists in ${locations}. Use update instead.`); + } + + if (mode === 'update' && present.length !== states.length) { + const missing = states + .filter(state => state.variable === undefined) + .map(state => `${state.project}/${state.environment}`) + .sort() + .join(', '); + throw new Error(`Cannot update: the variable is missing from ${missing}.`); + } +} + +export function buildWriteOperations(sensitive: boolean): VercelWriteOperation[] { + return WEB_ENVIRONMENTS.flatMap(environment => + WEB_ENV_PROJECTS.map(project => { + const targetIsSensitive = sensitive && environment !== 'development'; + return { + project, + environment, + sensitive: targetIsSensitive, + expectedType: targetIsSensitive ? 'sensitive' : 'encrypted', + } satisfies VercelWriteOperation; + }) + ); +} + +export function assertNonEmptyValues(values: EnvironmentValues): void { + for (const environment of WEB_ENVIRONMENTS) { + if (values[environment].length === 0) { + throw new Error(`${environment} cannot be empty.`); + } + } +} diff --git a/scripts/web-env/prompts.test.ts b/scripts/web-env/prompts.test.ts new file mode 100644 index 000000000..702b58ecf --- /dev/null +++ b/scripts/web-env/prompts.test.ts @@ -0,0 +1,47 @@ +import assert from 'node:assert/strict'; +import { PassThrough } from 'node:stream'; +import test from 'node:test'; +import { createTerminalPrompts, normalizeMultilineInput } from './prompts.js'; + +void test('coalesces pasted CRLF multiline input and never echoes its value', async () => { + const input = new PassThrough() as PassThrough & { + isTTY: boolean; + setRawMode(enabled: boolean): void; + }; + const output = new PassThrough() as PassThrough & { isTTY: boolean }; + const rawModes: boolean[] = []; + let visibleOutput = ''; + input.isTTY = true; + input.setRawMode = enabled => { + rawModes.push(enabled); + }; + output.isTTY = true; + output.setEncoding('utf8'); + output.on('data', chunk => { + visibleOutput += String(chunk); + }); + + const result = createTerminalPrompts(input, output).askSecret('Secret', 'multiline'); + input.write('line-one\r'); + await new Promise(resolve => setImmediate(resolve)); + input.write('\nline-two\r'); + await new Promise(resolve => setImmediate(resolve)); + input.write('\n::end\r'); + await new Promise(resolve => setTimeout(resolve, 30)); + input.write('\n'); + + assert.equal(await result, 'line-one\nline-two'); + assert.equal(input.readableLength, 0); + assert.deepEqual(rawModes, [true, false]); + assert.equal(visibleOutput.includes('line-one'), false); + assert.equal(visibleOutput.includes('line-two'), false); +}); + +void test('normalizes the terminal sentinel newline consistently for both providers', () => { + assert.equal(normalizeMultilineInput('{"key":"value"}\n'), '{"key":"value"}'); + assert.equal( + normalizeMultilineInput('-----BEGIN KEY-----\nvalue\n-----END KEY-----\n'), + '-----BEGIN KEY-----\nvalue\n-----END KEY-----' + ); + assert.equal(normalizeMultilineInput('already-normalized'), 'already-normalized'); +}); diff --git a/scripts/web-env/prompts.ts b/scripts/web-env/prompts.ts new file mode 100644 index 000000000..caa4244f7 --- /dev/null +++ b/scripts/web-env/prompts.ts @@ -0,0 +1,177 @@ +import { createInterface } from 'node:readline/promises'; +import { PassThrough, type Readable, type Writable } from 'node:stream'; + +export class UserAbortError extends Error { + constructor() { + super('Operation cancelled.'); + } +} + +export type SecretInputMode = 'single-line' | 'multiline'; + +export function normalizeMultilineInput(value: string): string { + return value.endsWith('\n') ? value.slice(0, -1) : value; +} + +export type PromptDriver = { + askText(question: string, defaultValue?: string): Promise; + confirm(question: string): Promise; + askSecret(question: string, mode: SecretInputMode): Promise; +}; + +type TtyReadable = Readable & { + isTTY?: boolean; + setRawMode?: (enabled: boolean) => void; +}; + +type TtyWritable = Writable & { + isTTY?: boolean; +}; + +function createNormalizedInput(input: TtyReadable): Readable { + const normalized = new PassThrough(); + let dropLineFeedAfterCarriageReturn = false; + input.on('data', chunk => { + let output = ''; + for (const character of String(chunk)) { + if (character === '\r') { + output += '\n'; + dropLineFeedAfterCarriageReturn = true; + continue; + } + if (character === '\n' && dropLineFeedAfterCarriageReturn) { + dropLineFeedAfterCarriageReturn = false; + continue; + } + dropLineFeedAfterCarriageReturn = false; + output += character; + } + if (output.length > 0) normalized.write(output); + }); + return normalized; +} + +async function askVisible( + input: Readable, + output: Writable, + question: string, + defaultValue?: string +): Promise { + input.resume(); + const prompt = defaultValue === undefined ? question : `${question} [${defaultValue}] `; + const rl = createInterface({ input, output }); + try { + const answer = await rl.question(prompt); + return answer.length === 0 && defaultValue !== undefined ? defaultValue : answer; + } finally { + rl.close(); + } +} + +function readHidden( + input: Readable, + ttyInput: TtyReadable, + output: TtyWritable, + question: string, + mode: SecretInputMode +): Promise { + if (!ttyInput.isTTY || !output.isTTY || !ttyInput.setRawMode) { + throw new Error('Hidden value input requires an interactive TTY.'); + } + + output.write(question); + input.setEncoding('utf8'); + ttyInput.setRawMode(true); + input.resume(); + + return new Promise((resolve, reject) => { + let value = ''; + let currentLine = ''; + let finished = false; + const sentinel = '::end'; + + const cleanup = () => { + input.off('data', onData); + process.off('SIGINT', onSignal); + process.off('SIGTERM', onSignal); + ttyInput.setRawMode?.(false); + input.pause(); + }; + + const finish = (result: string) => { + if (finished) return; + finished = true; + cleanup(); + output.write('\n'); + resolve(result); + }; + + const onSignal = () => { + if (finished) return; + finished = true; + cleanup(); + output.write('\n'); + reject(new UserAbortError()); + }; + + const processNewline = () => { + if (mode === 'single-line') { + finish(value); + return; + } + if (currentLine === sentinel) { + finish(normalizeMultilineInput(value)); + return; + } + value += `${currentLine}\n`; + currentLine = ''; + }; + + const onData = (chunk: string | Buffer) => { + for (const character of String(chunk)) { + if (character === '\u0003') { + onSignal(); + return; + } + if (character === '\u007f' || character === '\b') { + if (mode === 'single-line') { + value = [...value].slice(0, -1).join(''); + } else { + currentLine = [...currentLine].slice(0, -1).join(''); + } + continue; + } + if (character === '\n') { + processNewline(); + if (finished) return; + continue; + } + if (mode === 'single-line') value += character; + else currentLine += character; + } + }; + + input.on('data', onData); + process.once('SIGINT', onSignal); + process.once('SIGTERM', onSignal); + }); +} + +export function createTerminalPrompts( + input: TtyReadable = process.stdin, + output: TtyWritable = process.stdout +): PromptDriver { + const normalizedInput = createNormalizedInput(input); + return { + askText: (question, defaultValue) => + askVisible(normalizedInput, output, question, defaultValue), + confirm: async question => { + const answer = await askVisible(normalizedInput, output, `${question} [y/N] `); + return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes'; + }, + askSecret: (question, mode) => { + const suffix = mode === 'multiline' ? ' (finish with a line containing ::end)' : ''; + return readHidden(normalizedInput, input, output, `${question}${suffix}: `, mode); + }, + }; +} diff --git a/scripts/web-env/resume.test.ts b/scripts/web-env/resume.test.ts new file mode 100644 index 000000000..59ea04bff --- /dev/null +++ b/scripts/web-env/resume.test.ts @@ -0,0 +1,30 @@ +import assert from 'node:assert/strict'; +import { mkdtemp, readFile, rm, stat } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { readResumeJournal, writeResumeJournal, type ResumeJournal } from './resume.js'; + +void test('resume journals are value-free, private, and round-trip safely', async () => { + const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-resume-test-')); + try { + const journal: ResumeJournal = { + version: 1, + variableName: 'API_TOKEN', + sensitive: true, + createdAt: '2026-06-16T12:00:00.000Z', + completed: ['kilocode-app/development'], + failed: 'kilocode-global-app/development', + pending: ['kilocode-app/staging'], + onePassword: 'pending', + }; + const relativePath = await writeResumeJournal(root, journal); + const absolutePath = path.join(root, relativePath); + const content = await readFile(absolutePath, 'utf8'); + assert.equal(content.includes('super-secret-value'), false); + assert.deepEqual(await readResumeJournal(absolutePath), journal); + assert.equal((await stat(absolutePath)).mode & 0o777, 0o600); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); diff --git a/scripts/web-env/resume.ts b/scripts/web-env/resume.ts new file mode 100644 index 000000000..22c01005c --- /dev/null +++ b/scripts/web-env/resume.ts @@ -0,0 +1,80 @@ +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { isRecord, readString } from './json.js'; +import type { VercelWriteOperation } from './plan.js'; + +export type ResumeJournal = { + version: 1; + variableName: string; + sensitive: boolean; + createdAt: string; + completed: string[]; + failed: string; + pending: string[]; + onePassword: 'completed' | 'failed' | 'pending' | 'skipped'; +}; + +export function operationId(operation: VercelWriteOperation): string { + return `${operation.project}/${operation.environment}`; +} + +export async function writeResumeJournal( + repoRoot: string, + journal: ResumeJournal +): Promise { + const directory = path.join(repoRoot, '.tmp', 'web-env'); + await mkdir(directory, { recursive: true, mode: 0o700 }); + const safeTimestamp = journal.createdAt.replace(/[:.]/g, '-'); + const destination = path.join(directory, `${journal.variableName}-${safeTimestamp}.json`); + await writeFile(destination, `${JSON.stringify(journal, null, 2)}\n`, { mode: 0o600 }); + return path.relative(repoRoot, destination); +} + +function readStringArray(record: Record, key: string): string[] | undefined { + const value = record[key]; + if (!Array.isArray(value) || !value.every(item => typeof item === 'string')) return undefined; + return value; +} + +export async function readResumeJournal(filePath: string): Promise { + let parsed: unknown; + try { + parsed = JSON.parse(await readFile(filePath, 'utf8')); + } catch { + throw new Error('The resume journal is missing or invalid.'); + } + if (!isRecord(parsed)) throw new Error('The resume journal has an unexpected format.'); + + const variableName = readString(parsed, 'variableName'); + const createdAt = readString(parsed, 'createdAt'); + const completed = readStringArray(parsed, 'completed'); + const failed = readString(parsed, 'failed'); + const pending = readStringArray(parsed, 'pending'); + const onePassword = readString(parsed, 'onePassword'); + if ( + parsed.version !== 1 || + !variableName || + typeof parsed.sensitive !== 'boolean' || + !createdAt || + !completed || + !failed || + !pending || + (onePassword !== 'completed' && + onePassword !== 'failed' && + onePassword !== 'pending' && + onePassword !== 'skipped') + ) { + throw new Error('The resume journal has an unexpected format.'); + } + + return { + version: 1, + variableName, + sensitive: parsed.sensitive, + createdAt, + completed, + failed, + pending, + onePassword, + }; +} diff --git a/scripts/web-env/tsconfig.json b/scripts/web-env/tsconfig.json new file mode 100644 index 000000000..68212bf40 --- /dev/null +++ b/scripts/web-env/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["./**/*.ts"] +} diff --git a/scripts/web-env/vercel.ts b/scripts/web-env/vercel.ts new file mode 100644 index 000000000..8abdc00ec --- /dev/null +++ b/scripts/web-env/vercel.ts @@ -0,0 +1,233 @@ +import type { CommandExecutor, CommandResult } from './command.js'; +import { requireSuccess } from './command.js'; +import { isRecord, parseJsonObject, readRecords, readString } from './json.js'; +import { + VERCEL_VERSION, + WEB_ENV_PROJECTS, + type VariableMetadata, + type VercelVariableType, + type WebEnvironment, + type WebEnvProject, +} from './plan.js'; + +const VERCEL_SCOPE = 'kilocode'; +const VERCEL_TYPES = new Set(['plain', 'encrypted', 'sensitive', 'system']); + +function parseVariableType(value: unknown): VercelVariableType | undefined { + if (typeof value !== 'string') return undefined; + if (value === 'plain' || value === 'encrypted' || value === 'sensitive' || value === 'system') { + return value; + } + return undefined; +} + +export type ResolvedVercelProject = { + name: WebEnvProject; + id: string; +}; + +export class VercelAdapter { + readonly #execute: CommandExecutor; + readonly #tempRoot: string; + readonly #projectIds = new Map(); + readonly #stagingEnvironmentIds = new Map(); + #orgId = ''; + + constructor(execute: CommandExecutor, tempRoot: string) { + this.#execute = execute; + this.#tempRoot = tempRoot; + } + + async #run(args: string[], project?: WebEnvProject, stdin?: string): Promise { + const env: NodeJS.ProcessEnv = { + ...process.env, + AI_AGENT: 'kilo-web-env-adapter', + }; + if (project) { + env.VERCEL_ORG_ID = this.#orgId; + env.VERCEL_PROJECT_ID = this.#getProjectId(project); + } + return this.#execute({ + command: 'pnpm', + args: [ + 'exec', + 'vercel', + ...args, + '--scope', + VERCEL_SCOPE, + '--cwd', + this.#tempRoot, + '--non-interactive', + '--no-color', + ], + cwd: this.#tempRoot, + env, + stdin, + timeoutMs: 120_000, + }); + } + + #getProjectId(project: WebEnvProject): string { + const id = this.#projectIds.get(project); + if (!id) throw new Error(`Vercel project ${project} has not been resolved.`); + return id; + } + + #getEnvironmentTarget(project: WebEnvProject, environment: WebEnvironment): string { + if (environment !== 'staging') return environment; + const id = this.#stagingEnvironmentIds.get(project); + if (!id) throw new Error(`Vercel staging environment for ${project} has not been resolved.`); + return id; + } + + async initialize(requireNonSensitivePolicy = false): Promise { + const versionResult = await this.#run(['--version']); + const version = requireSuccess(versionResult, 'Vercel CLI version check'); + if (!version.includes(VERCEL_VERSION)) { + throw new Error(`Expected Vercel CLI ${VERCEL_VERSION}. Run pnpm install.`); + } + + const whoamiResult = await this.#run(['whoami', '--format=json']); + const whoami = parseJsonObject( + requireSuccess(whoamiResult, 'Vercel authentication check'), + 'Vercel authentication check' + ); + const team = whoami.team; + if (!isRecord(team) || readString(team, 'slug') !== VERCEL_SCOPE) { + throw new Error(`Vercel CLI is not authenticated to the ${VERCEL_SCOPE} scope.`); + } + const orgId = readString(team, 'id'); + if (!orgId) throw new Error('Vercel authentication response did not include a team ID.'); + this.#orgId = orgId; + + const resolved: ResolvedVercelProject[] = []; + for (const project of WEB_ENV_PROJECTS) { + const listResult = await this.#run(['project', 'list', '--filter', project, '--format=json']); + const response = parseJsonObject( + requireSuccess(listResult, `Resolve Vercel project ${project}`), + `Resolve Vercel project ${project}` + ); + const exactMatches = readRecords(response, 'projects').filter( + candidate => readString(candidate, 'name') === project + ); + if (exactMatches.length !== 1) { + throw new Error(`Expected exactly one Vercel project named ${project}.`); + } + const id = readString(exactMatches[0] ?? {}, 'id'); + if (!id) throw new Error(`Vercel project ${project} did not include an ID.`); + this.#projectIds.set(project, id); + resolved.push({ name: project, id }); + } + + for (const project of WEB_ENV_PROJECTS) { + const targetsResult = await this.#run(['target', 'list', '--format=json'], project); + const targets = parseJsonObject( + requireSuccess(targetsResult, `List Vercel targets for ${project}`), + `List Vercel targets for ${project}` + ); + const stagingTargets = readRecords(targets, 'targets').filter( + target => readString(target, 'slug') === 'staging' + ); + if (stagingTargets.length !== 1) { + throw new Error(`Vercel project ${project} must have one custom staging environment.`); + } + const stagingId = readString(stagingTargets[0] ?? {}, 'id'); + if (!stagingId) throw new Error(`Vercel staging environment for ${project} has no ID.`); + this.#stagingEnvironmentIds.set(project, stagingId); + } + + if (requireNonSensitivePolicy) { + const policyResult = await this.#run(['api', `/teams/${this.#orgId}`, '--raw']); + const policy = parseJsonObject( + requireSuccess(policyResult, 'Vercel sensitive-variable policy check'), + 'Vercel sensitive-variable policy check' + ); + if (readString(policy, 'sensitiveEnvironmentVariablePolicy') === 'on') { + throw new Error( + 'The Vercel team policy forces sensitive deployed variables, so --no-sensitive cannot be honored.' + ); + } + } + + return resolved; + } + + async listVariables( + project: WebEnvProject, + environment: WebEnvironment + ): Promise { + const target = this.#getEnvironmentTarget(project, environment); + const result = await this.#run(['env', 'list', target, '--format=json'], project); + const response = parseJsonObject( + requireSuccess(result, `List ${project}/${environment} variables`), + `List ${project}/${environment} variables` + ); + const variables: VariableMetadata[] = []; + for (const candidate of readRecords(response, 'envs')) { + const key = readString(candidate, 'key'); + const type = parseVariableType(candidate.type); + if (key && type && VERCEL_TYPES.has(type)) variables.push({ key, type }); + } + return variables; + } + + async getVariable( + project: WebEnvProject, + environment: WebEnvironment, + key: string + ): Promise { + const matches = (await this.listVariables(project, environment)).filter( + variable => variable.key === key + ); + if (matches.length > 1) { + throw new Error(`Multiple ${key} definitions exist in ${project}/${environment}.`); + } + return matches[0]; + } + + async writeVariable(options: { + mode: 'add' | 'update' | 'resume'; + project: WebEnvProject; + environment: WebEnvironment; + key: string; + value: string; + sensitive: boolean; + expectedType: 'encrypted' | 'sensitive'; + }): Promise { + const target = this.#getEnvironmentTarget(options.project, options.environment); + const args = ['env', 'add', options.key, target]; + if (options.mode !== 'add') args.push('--force'); + args.push(options.sensitive ? '--sensitive' : '--no-sensitive', '--yes'); + + const result = await this.#run(args, options.project, options.value); + requireSuccess(result, `Write ${options.project}/${options.environment}`); + + const metadata = await this.getVariable(options.project, options.environment, options.key); + if (metadata?.type !== options.expectedType) { + throw new Error( + `Vercel type verification failed for ${options.project}/${options.environment}.` + ); + } + } + + async pullReadableValue( + project: WebEnvProject, + environment: WebEnvironment, + key: string + ): Promise { + const target = encodeURIComponent(this.#getEnvironmentTarget(project, environment)); + const projectId = encodeURIComponent(this.#getProjectId(project)); + const endpoint = `/v3/env/pull/${projectId}/${target}?source=vercel-cli%3Aenv%3Apull`; + const result = await this.#run(['api', endpoint, '--raw'], project); + const response = parseJsonObject( + requireSuccess(result, `Pull ${project}/${environment} variables`), + `Pull ${project}/${environment} variables` + ); + const environmentValues = response.env; + if (!isRecord(environmentValues)) { + throw new Error(`Vercel returned an unexpected ${project}/${environment} response.`); + } + const value = environmentValues[key]; + return typeof value === 'string' ? value : undefined; + } +} From ef0fcba95ca42ac608756731cf68943daf532067 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 17:17:53 +0200 Subject: [PATCH 02/22] refactor(web): simplify environment management tool --- .github/workflows/ci.yml | 1 - package.json | 7 +- pnpm-lock.yaml | 1822 +------------------------- scripts/typecheck-all.sh | 3 +- scripts/web-env/adapters.test.ts | 210 --- scripts/web-env/apply.test.ts | 116 -- scripts/web-env/apply.ts | 82 -- scripts/web-env/backfill-report.ts | 38 - scripts/web-env/backfill.test.ts | 22 - scripts/web-env/backfill.ts | 229 +--- scripts/web-env/command.ts | 72 - scripts/web-env/dotenv-files.test.ts | 131 -- scripts/web-env/dotenv-files.ts | 289 ---- scripts/web-env/index.ts | 394 ++---- scripts/web-env/json.ts | 43 - scripts/web-env/onepassword.ts | 180 --- scripts/web-env/plan.test.ts | 56 - scripts/web-env/plan.ts | 84 -- scripts/web-env/prompts.test.ts | 47 - scripts/web-env/prompts.ts | 177 --- scripts/web-env/resume.test.ts | 30 - scripts/web-env/resume.ts | 80 -- scripts/web-env/shared.ts | 323 +++++ scripts/web-env/tsconfig.json | 12 - scripts/web-env/vercel.ts | 233 ---- 25 files changed, 562 insertions(+), 4119 deletions(-) delete mode 100644 scripts/web-env/adapters.test.ts delete mode 100644 scripts/web-env/apply.test.ts delete mode 100644 scripts/web-env/apply.ts delete mode 100644 scripts/web-env/backfill-report.ts delete mode 100644 scripts/web-env/backfill.test.ts delete mode 100644 scripts/web-env/command.ts delete mode 100644 scripts/web-env/dotenv-files.test.ts delete mode 100644 scripts/web-env/dotenv-files.ts delete mode 100644 scripts/web-env/json.ts delete mode 100644 scripts/web-env/onepassword.ts delete mode 100644 scripts/web-env/plan.test.ts delete mode 100644 scripts/web-env/plan.ts delete mode 100644 scripts/web-env/prompts.test.ts delete mode 100644 scripts/web-env/prompts.ts delete mode 100644 scripts/web-env/resume.test.ts delete mode 100644 scripts/web-env/resume.ts create mode 100644 scripts/web-env/shared.ts delete mode 100644 scripts/web-env/tsconfig.json delete mode 100644 scripts/web-env/vercel.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa42df7f5..e5ba73227 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,6 @@ jobs: - 'packages/trpc/**' - 'packages/worker-utils/**' - 'services/deploy-infra/builder/**' - - 'scripts/web-env/**' - 'package.json' - 'pnpm-lock.yaml' cloud_agent: diff --git a/package.json b/package.json index 7bda98632..a536e9325 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,7 @@ "preinstall": "npx only-allow pnpm", "typecheck": "scripts/typecheck-all.sh", "build": "pnpm --filter web build", - "test": "pnpm run test:web-env && pnpm --filter web test", - "test:web-env": "tsgo --noEmit -p scripts/web-env/tsconfig.json && tsx --test scripts/web-env/*.test.ts", + "test": "pnpm --filter web test", "test:setup-smoke": "pnpm --filter web run test:setup-smoke", "lint": "scripts/lint-all.sh", "format": "oxfmt", @@ -39,7 +38,6 @@ }, "packageManager": "pnpm@11.1.2", "devDependencies": { - "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "husky": "9.1.7", "ink": "6.8.0", @@ -49,7 +47,6 @@ "oxlint-tsgolint": "0.17.4", "react": "19.2.6", "tsx": "catalog:", - "typescript": "catalog:", - "vercel": "53.3.1" + "typescript": "catalog:" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 881f70de7..c6c88eaf6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,9 +129,6 @@ importers: .: devDependencies: - '@types/node': - specifier: 'catalog:' - version: 24.12.4 '@typescript/native-preview': specifier: 'catalog:' version: 7.0.0-dev.20260514.1 @@ -162,9 +159,6 @@ importers: typescript: specifier: 'catalog:' version: 5.9.3 - vercel: - specifier: 53.3.1 - version: 53.3.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) apps/mobile: dependencies: @@ -387,7 +381,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) apps/storybook: dependencies: @@ -1014,7 +1008,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/cloud-agent-profile: dependencies: @@ -1045,7 +1039,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/db: dependencies: @@ -1094,7 +1088,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/event-service: dependencies: @@ -1110,7 +1104,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kilo-chat: dependencies: @@ -1132,7 +1126,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kilo-chat-hooks: dependencies: @@ -1160,7 +1154,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kiloclaw-instance-tiers: dependencies: @@ -1176,7 +1170,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/kiloclaw-secret-catalog: dependencies: @@ -1192,7 +1186,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/mcp-gateway: dependencies: @@ -1208,7 +1202,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/notifications: dependencies: @@ -1233,7 +1227,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/session-ingest-contracts: dependencies: @@ -1317,7 +1311,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) packages/worker-utils: dependencies: @@ -1351,7 +1345,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/ai-attribution: dependencies: @@ -1446,7 +1440,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1474,7 +1468,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1511,7 +1505,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1557,7 +1551,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1588,7 +1582,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1652,7 +1646,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1743,7 +1737,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1817,7 +1811,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -1973,7 +1967,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2016,7 +2010,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2089,7 +2083,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2117,7 +2111,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/git-token-service: dependencies: @@ -2154,7 +2148,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2182,7 +2176,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2225,7 +2219,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2298,7 +2292,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2384,7 +2378,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2427,7 +2421,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2455,7 +2449,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2493,7 +2487,7 @@ importers: version: 2026.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/kiloclaw/plugins/kiloclaw-customizer: devDependencies: @@ -2502,7 +2496,7 @@ importers: version: 0.27.4 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/kiloclaw/plugins/kiloclaw-morning-briefing: devDependencies: @@ -2517,7 +2511,7 @@ importers: version: 2026.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) services/mcp-gateway: dependencies: @@ -2560,7 +2554,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2591,7 +2585,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2643,7 +2637,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2680,7 +2674,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2714,7 +2708,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2745,7 +2739,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2797,7 +2791,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2855,7 +2849,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -2910,7 +2904,7 @@ importers: version: 5.9.3 vitest: specifier: 'catalog:' - version: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: specifier: 'catalog:' version: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) @@ -3893,9 +3887,6 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@bytecodealliance/preview2-shim@0.17.6': - resolution: {integrity: sha512-n3cM88gTen5980UOBAD6xDcNNL3ocTK8keab21bpx1ONdA+ARj7uD1qoFxOWCyKlkpSi195FH+GeAut7Oc6zZw==} - '@chat-adapter/github@4.27.0': resolution: {integrity: sha512-3/lz5oo/z18H90c89FAXomHnmbXx+E55Nl4jfjtgq4FEUcEI9BU+tbkVANpkQ54tHTEPmhxfg/qJ3mJPctk5hg==} @@ -4193,26 +4184,6 @@ packages: resolution: {integrity: sha512-3a705FnsVVUhAyceShNB3kS2rpxcxLcx+hqB0u6MMMpHwQGbW+m++MqA6r7eOzq/8FLx5e3vDh38h/SVTk2qzw==} engines: {node: '>=22.19.0'} - '@edge-runtime/format@2.2.1': - resolution: {integrity: sha512-JQTRVuiusQLNNLe2W9tnzBlV/GvSVcozLl4XZHk5swnRZ/v6jp8TqR8P7sqmJsQqblDZ3EztcWmLDbhRje/+8g==} - engines: {node: '>=16'} - - '@edge-runtime/node-utils@2.3.0': - resolution: {integrity: sha512-uUtx8BFoO1hNxtHjp3eqVPC/mWImGb2exOfGjMLUoipuWgjej+f4o/VP4bUI8U40gu7Teogd5VTeZUkGvJSPOQ==} - engines: {node: '>=16'} - - '@edge-runtime/ponyfill@2.4.2': - resolution: {integrity: sha512-oN17GjFr69chu6sDLvXxdhg0Qe8EZviGSuqzR9qOiKh4MhFYGdBBcqRNzdmYeAdeRzOW2mM9yil4RftUQ7sUOA==} - engines: {node: '>=16'} - - '@edge-runtime/primitives@4.1.0': - resolution: {integrity: sha512-Vw0lbJ2lvRUqc7/soqygUX216Xb8T3WBZ987oywz6aJqRxcwSVWwr9e+Nqo2m9bxobA9mdbWNNoRY6S9eko1EQ==} - engines: {node: '>=16'} - - '@edge-runtime/vm@3.2.0': - resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==} - engines: {node: '>=16'} - '@egjs/hammerjs@2.0.17': resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} engines: {node: '>=0.8.0'} @@ -4597,10 +4568,6 @@ packages: resolution: {integrity: sha512-It0Sne6P3szg7JIi6CgKbvTZoMjxBZhcv91ZrqrNuaZQfB5WoqYYbzCUOq89YR+VY8juY9M1vDWmDDa2TzfXCw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} - '@fastify/busboy@2.1.1': - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - '@fastify/otel@0.16.0': resolution: {integrity: sha512-2304BdM5Q/kUvQC9qJO1KZq3Zn1WWsw+WWkVmFEaj1UE2hEIiuFqrPeglQOwEtw/ftngisqfQ3v70TWMmwhhHA==} peerDependencies: @@ -4832,14 +4799,6 @@ packages: cpu: [x64] os: [win32] - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.1': - resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==} - engines: {node: 20 || >=22} - '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -5245,11 +5204,6 @@ packages: '@lydell/node-pty@1.2.0-beta.12': resolution: {integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==} - '@mapbox/node-pre-gyp@2.0.3': - resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} - engines: {node: '>=18'} - hasBin: true - '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} @@ -5984,9 +5938,6 @@ packages: cpu: [x64] os: [win32] - '@oxc-project/types@0.110.0': - resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==} - '@oxc-project/types@0.120.0': resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==} @@ -6101,133 +6052,6 @@ packages: cpu: [x64] os: [win32] - '@oxc-transform/binding-android-arm-eabi@0.111.0': - resolution: {integrity: sha512-NdFLicvorfHYu0g2ftjVJaH7+Dz27AQUNJOq8t/ofRUoWmczOodgUCHx8C1M1htCN4ZmhS/FzfSy6yd/UngJGg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@oxc-transform/binding-android-arm64@0.111.0': - resolution: {integrity: sha512-J2v9ajarD2FYlhHtjbgZUFsS2Kvi27pPxDWLGCy7i8tO60xBoozX9/ktSgbiE/QsxKaUhfv4zVKppKWUo71PmQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@oxc-transform/binding-darwin-arm64@0.111.0': - resolution: {integrity: sha512-2UYmExxpXzmiHTldhNlosWqG9Nc4US51K0GB9RLcGlTE23WO33vVo1NVAKwxPE+KYuhffwDnRYTovTMUjzwvZA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@oxc-transform/binding-darwin-x64@0.111.0': - resolution: {integrity: sha512-c4YRwfLV8Pj/ToiTCbndZaHxM2BD4W3bltr/fjXZcGypEK+U2RZFDL7tIZYT/tyneAC9hCORZKDaKhLLNuzPtA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@oxc-transform/binding-freebsd-x64@0.111.0': - resolution: {integrity: sha512-prvf32IcEuLnLZbNVomFosBu0CaZpyj3YsZ6epbOgJy8iJjfLsXBb+PrkO/NBKzjuJoJa2+u7jFKRE0KT7gSOw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': - resolution: {integrity: sha512-+se3579Wp7VOk8TnTZCpT+obTAyzOw2b/UuoM0+51LtbzCSfjKxd4A+o7zRl7GyPrPZvx57KdbMOC9rWB1xNrw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': - resolution: {integrity: sha512-8faC99pStqaSDPK/vBgaagAHUeL0LcIzfeSjSiDTtvPGc3AwZIeqC1tx3CP15a6tWXjdgS/IUw4IjfD5HweBlg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@oxc-transform/binding-linux-arm64-gnu@0.111.0': - resolution: {integrity: sha512-HtfQv8j796gzI5WR/RaP6IMwFpiL0vYeDrUA1hYhlPzTHKYan/B+NlhJkKOI1v24yAl/yEnFmb0pxIxLNqBqBA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxc-transform/binding-linux-arm64-musl@0.111.0': - resolution: {integrity: sha512-ARyfcMCIxVLDgLf6FQ8Oo1/TFySpnquV+vuSb4SFQZfYDqgMklzwv0NYXxWD0aB6enElyMDs6pQJBzusEKCkOg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': - resolution: {integrity: sha512-PKpVRrSvBNK3tv9vwxn7Fay+QWZmprPGlEqJcseBJllQc5mFMD4Q/w44chu5iR9ZLsDeSHzmNWrgMLo4J0sP2A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': - resolution: {integrity: sha512-9bUml6rMgk+8GF5rvNMweFspkzSiCjqpV6HduwiUyexqfGKrmjq9IZOxxvnzkE2RGdQzP507NNDoVNYIoGQYuA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@oxc-transform/binding-linux-riscv64-musl@0.111.0': - resolution: {integrity: sha512-tzGCohGxaeH6KRJjfYZd4mHCoGjCai6N+zZi1Oj+tSDMAAdyvs1dRzYb8PNUGnybCg3Te4M0jLPzWZaSmnKraQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@oxc-transform/binding-linux-s390x-gnu@0.111.0': - resolution: {integrity: sha512-sRG1KIfZ0ML9ToEygm5aM/5GJeBA05uHlgW3M0Rx/DNWMJhuahLmqWuB02aWSmijndLfEKXLLXIWhvWupRG8lg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@oxc-transform/binding-linux-x64-gnu@0.111.0': - resolution: {integrity: sha512-T0Kmvk+OdlUdABdXlDIf3MQReMzFfC75NEI9x8jxy5pKooACEFg0k0V8gyR3gq4DzbDCfucqFQDWNvSgIopAbQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxc-transform/binding-linux-x64-musl@0.111.0': - resolution: {integrity: sha512-EgoutsP3YfqzN8a9vpc9+XLr0bmBl0dA3uOMiP77+exATCPxJBkJErGmQkqk6RtTp5XqX6q6mB45qWQyKk6+pA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxc-transform/binding-openharmony-arm64@0.111.0': - resolution: {integrity: sha512-d8J+ejc0j5WODbVwR/QxFaI65YMwvG0W53vcVCHwa6ja1QI5lpe7sislrefG2EFYgnY47voMRzlXab5d4gEcDw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@oxc-transform/binding-wasm32-wasi@0.111.0': - resolution: {integrity: sha512-HtyIZO8IwuZgXkyb56rysLz1OLbfLhEu8A3BeuyJXzUseAj96yuxgGt3cu3QYX9AXb9pfRfA3c/fvlhsDugyTQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@oxc-transform/binding-win32-arm64-msvc@0.111.0': - resolution: {integrity: sha512-YeP80Riptc0MkVVBnzbmoFuHVLUq278+MbwNo9sTLALmzTIJxJqN029xRZbG+Bun7aLsoZhmRnm3J5JZ1NcP5w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@oxc-transform/binding-win32-ia32-msvc@0.111.0': - resolution: {integrity: sha512-A6ztCXpoSHt6PbvGAFqB0MLOcGG7ZJrrPXY1iB0zfOB1atLgI8oNePGxPl03XSbwpiTsFJ1oo8rj9DXcBzgT9g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@oxc-transform/binding-win32-x64-msvc@0.111.0': - resolution: {integrity: sha512-QddKW4kBH0Wof6Y65eYCNHM4iOGmCTWLLcNYY1FGswhzmTYOUVXajNROR+iCXAOFnOF0ldtsR79SyqgyHH1Bgg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@oxfmt/binding-android-arm-eabi@0.40.0': resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7318,10 +7142,6 @@ packages: react-redux: optional: true - '@renovatebot/pep440@4.2.1': - resolution: {integrity: sha512-2FK1hF93Fuf1laSdfiEmJvSJPVIDHEUTz68D3Fi9s0IZrrpaEcj6pTFBTbYvsgC5du4ogrtf5re7yMMvrKNgkw==} - engines: {node: ^20.9.0 || ^22.11.0 || ^24, pnpm: ^10.0.0} - '@rn-primitives/portal@1.3.0': resolution: {integrity: sha512-a2DSce7TcSfcs0cCngLadAJOvx/+mdH9NRu+GxkX8NPRsGGhJvDEOqouMgDqLwx7z9mjXoUaZcwaVcemUSW9/A==} peerDependencies: @@ -7351,73 +7171,36 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} deprecated: Use Promise.withResolvers instead - '@rolldown/binding-android-arm64@1.0.0-rc.1': - resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - '@rolldown/binding-android-arm64@1.0.0-rc.17': resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.1': - resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.1': - resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.17': resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.1': - resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': - resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': - resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7425,13 +7208,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': - resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7453,13 +7229,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': - resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7467,13 +7236,6 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': - resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -7481,55 +7243,29 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': - resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.1': - resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': - resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': - resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.1': - resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==} - '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} @@ -8086,9 +7822,6 @@ packages: '@silvia-odwyer/photon-node@0.3.4': resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} - '@sinclair/typebox@0.25.24': - resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} - '@sinclair/typebox@0.27.10': resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} @@ -8846,13 +8579,6 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} - - '@tootallnate/quickjs-emscripten@0.23.0': - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@trpc/client@11.17.0': resolution: {integrity: sha512-KpJBFrbKTDeVCFv/3ckL1XBBH5Yssn8hethI/rUy7GIpTj+VzjtPjykDqJpzobuVOz+d26cXCSu1t4I6MYI5Zg==} hasBin: true @@ -8892,9 +8618,6 @@ packages: resolution: {integrity: sha512-w071DSzP94YfN6XiWhOxnLpYT3uqtxJBDYdh6Jdjzt+Ce6DNspJsPQgpC7rbts/B8tEkq0LHoYuIF/O5Jh5rPg==} engines: {node: '>=18'} - '@ts-morph/common@0.11.1': - resolution: {integrity: sha512-7hWZS0NRpEsNV8vWJzg7FEz6V8MaLNeJOmwmghqUXTpzk16V1LLZhdo+4QvE/+zv4cVci0OviuJFnqhEfoV3+g==} - '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -9038,9 +8761,6 @@ packages: '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node@20.11.0': - resolution: {integrity: sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==} - '@types/node@20.19.41': resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==} @@ -9343,47 +9063,10 @@ packages: '@upstash/redis@1.38.0': resolution: {integrity: sha512-wu+dZBptlLy0+MCUEoHmzrY/TnmgDey3+c7EbIGwrLqAvkP8yi5MWZHYGIFtAygmL4Bkz2TdFu+eU0vFPncIcg==} - '@vercel/backends@0.4.0': - resolution: {integrity: sha512-hjoXd64KBnS2dT3U3x1ABd3u9VqRTIflM5Pxszwv/7Defy/rN9KjElOeCvu3T3z8qr02nnqus8S4nfWOhwsY/w==} - - '@vercel/blob@2.3.0': - resolution: {integrity: sha512-oYWiJbWRQ7gz9Mj0X/NHFJ3OcLMOBzq/2b3j6zeNrQmtFo6dHwU8FAwNpxVIYddVMd+g8eqEi7iRueYx8FtM0Q==} - engines: {node: '>=20.0.0'} - - '@vercel/build-utils@13.22.0': - resolution: {integrity: sha512-4DWbevInIV7ZqrPWZR58s6S9FtfpOBEJFKqXEm7bwiC8Hq8hKOk/igkDei3taja1bC6mfps44OEGlCH0cARSHw==} - - '@vercel/cervel@0.1.1': - resolution: {integrity: sha512-2gCMYw7lPPP571X4ojdhueoF1qHqD5JyQuQ/hsRgcEyilV+2v2lNCdb5ptGah4pDeEWcvg3g9wTomR8dLC1SaQ==} - hasBin: true - - '@vercel/cli-config@0.1.1': - resolution: {integrity: sha512-7bYfDRq6EYYbpkDTrbWCHowX3kVQWXluZBIRtqnPoaXcL9jNpwe3ps5qAaEYq24kICLxGDKu1Rmy1U7rBlUr9w==} - - '@vercel/detect-agent@1.2.3': - resolution: {integrity: sha512-VYNCgUc0nOmC4WJmWw9GkrKdfr8Zl4/rxhC5SvgacBgxiW9W/9NRttUoHHXV8xdII3MaRgkZZVX8Ikzc/Jmjag==} - engines: {node: '>=14'} - - '@vercel/elysia@0.1.74': - resolution: {integrity: sha512-O9EpMBfvD+xkkmEliV0BHPbkVO4j/vDWAiNCJdvdFWu11QLqWtZRi2hC+dtw4iNKzXVLzKLo2481BSwBaopDtA==} - - '@vercel/error-utils@2.1.0': - resolution: {integrity: sha512-DiJcXBOB9N6QM4d7hYPM9Ck/AUjzBl58XNQPxS74o7CuvIanjzrGgygP/70VsyEASeIJMazk1LrhwcNTR/eZGQ==} - - '@vercel/express@0.1.84': - resolution: {integrity: sha512-rQqbVgBIkB0OE068i6m225eGk2QsEXy48WcnczIiqYGPDKjtglh03Wq7x8ED/9KrkTkiojGJkLYdAcNumQpSBA==} - - '@vercel/fastify@0.1.77': - resolution: {integrity: sha512-Yd5kzpPbBYdVQ5JcGcr10B6BQSb20urfz8fHEvJv4x+lWUBBkoSogW/GiBcFF1rhqPFAIpVHMWYCc3Q7IR/oPA==} - '@vercel/firewall@1.2.1': resolution: {integrity: sha512-WlxjEPpf+GWYMontNNZqZjvLL40ziGwy9swwI9da/L1fB/syAO1S2fMtlBXkp4EGVF6nlXSKmwvkUd6YPWJbbg==} engines: {node: '>= 20'} - '@vercel/fun@1.3.0': - resolution: {integrity: sha512-8erw9uPe0dFg45THkNxmjtvMX143SkZebmjgSVbcM3XCkXu3RIiBaJMcMNG8aaS+rnTuw8+d4De9HVT0M/r3wg==} - engines: {node: '>= 18'} - '@vercel/functions@3.4.6': resolution: {integrity: sha512-ljfB7SceggUOFjagEmw3PBLSAGQK1NmBln4FV/Cg9cewfbdfJZS88LgC7LRfZ9GgG1kWimkwS/8SLHVtx6lhLA==} engines: {node: '>= 20'} @@ -9393,41 +9076,6 @@ packages: '@aws-sdk/credential-provider-web-identity': optional: true - '@vercel/gatsby-plugin-vercel-analytics@1.0.11': - resolution: {integrity: sha512-iTEA0vY6RBPuEzkwUTVzSHDATo1aF6bdLLspI68mQ/BTbi5UQEGjpjyzdKOVcSYApDtFU6M6vypZ1t4vIEnHvw==} - - '@vercel/gatsby-plugin-vercel-builder@2.2.1': - resolution: {integrity: sha512-ej6b6H+zr0SXgIP1NXt5PD68dRwwNlD6afpBZc+ZxlkVu7qUjtovAW062OHMIpTSvnEcBSbcBtA9OPz4E3Ixug==} - - '@vercel/go@3.6.0': - resolution: {integrity: sha512-60gQxuQBfuGQCPdp1zmG3bfWncj+MRDm9KNogKeu4cA1uC2kGwUoCI6vr8kpGTv62v3gwSLbcnJ3RsqOqxb3KA==} - - '@vercel/h3@0.1.83': - resolution: {integrity: sha512-Q/ssscXDQX6/TCEcKlIUB8i5n67z1uzQiBC7advTVkM45HKid0mMWsQEl0unGhEsPzUsizss4Kow9eUTvnX+qQ==} - - '@vercel/hono@0.2.77': - resolution: {integrity: sha512-N8UsEbP+2jdhU1YZyGQ56btW5SPMgg1uZC4Cr+NzpsbsizBXTLz7BWnJoQM+Eea/p4v2N+FLZ2Lenz2Mk8lagA==} - - '@vercel/hydrogen@1.3.7': - resolution: {integrity: sha512-nh8hZ76Ipf9FRmMmQGd4SjkE0zxdjt+TUpZcuCIUG7yaHEh9STQV655I8rxKCB3hEWaKB3HALGgxZ0htIjQtZQ==} - - '@vercel/koa@0.1.57': - resolution: {integrity: sha512-1mCqpyVsQPMupJdSQ1h9PO5GDiUFo1QhaGFFAlsLUuM1oTUhc2bklg85FroCbncs1MOtoR2a30kywJoe8S8e0A==} - - '@vercel/nestjs@0.2.78': - resolution: {integrity: sha512-8jFlHsy9M9Q+9/qPQ8zJfpVBEM+aklIZFxaclKVli33seovLKTX54yyiNM2aYb6b1Q3E44NQBsgz14fnFLxYEQ==} - - '@vercel/next@4.17.1': - resolution: {integrity: sha512-nEQRgGyU8+VU/zeKsBF89aKmL0Yu5VWWhTbaltp2V+1q6kHUo6Ho4+YS/COAgOrIwoe2nWr9liLVPltrftqG+Q==} - - '@vercel/nft@1.5.0': - resolution: {integrity: sha512-IWTDeIoWhQ7ZtRO/JRKH+jhmeQvZYhtGPmzw/QGDY+wDCQqfm25P9yIdoAFagu4fWsK4IwZXDFIjrmp5rRm/sA==} - engines: {node: '>=20'} - hasBin: true - - '@vercel/node@5.7.16': - resolution: {integrity: sha512-BBnkw/ubZkb87G//+lz+ZRweA+Yj+YAtsSbSuNAUigxvQJZiMvEAZgI5EcuL85ex69KPTjwHPcYPLWxU3xXTLg==} - '@vercel/oidc@3.2.0': resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} @@ -9448,36 +9096,6 @@ packages: '@opentelemetry/sdk-metrics': '>=2.0.0 <3.0.0' '@opentelemetry/sdk-trace-base': '>=2.0.0 <3.0.0' - '@vercel/prepare-flags-definitions@0.2.1': - resolution: {integrity: sha512-ouXTsqn7I9xZ1KKezgvn/w3tZeQHL/tc52j9GHiOYi6kT8xgdbT8s2x8C9BQr44iceX0hfhtZwk9q7NuI2Tqbw==} - - '@vercel/python-analysis@0.11.1': - resolution: {integrity: sha512-EPPLuXJQhIDUx08H9nG76AR2HSgBquwe3OAX5s2w20M923iaWeGGVkhX/4yZ89CJfXEZgE1Aj/mX7lVHOVIcYA==} - - '@vercel/python@6.39.0': - resolution: {integrity: sha512-BIp793WI9TL/N85r22WhSo9n99TPjqI1xXEm8RAqZNJaXcFLHfjF5Hfg14Y4uPHGKfALfEzH3gbUndD8MTA8Hw==} - - '@vercel/redwood@2.4.13': - resolution: {integrity: sha512-pXWzVctZea/J7WMQstjsYUDiMc6oJF72p8J5YZnLSCJWg7m+/dLzYGfaUSEo6Q0JpiO/NOcDmG3WENpn7kHwzg==} - - '@vercel/remix-builder@5.8.1': - resolution: {integrity: sha512-DDuT8NbIUoc1Fso2er0GyHxQR77au+BJr8wToDJcyoKjsypOHMcPwV8Vak9XsOfSUlQHLt1x9XnfTVj5O48Ssw==} - - '@vercel/ruby@2.3.2': - resolution: {integrity: sha512-okIgMmPEePyDR9TZYaKM4oftcxVHM5Dbdl7V/tIdh3lq8MGLi7HR5vvQglmZUwZOeovE6MVtezxl960EOzeIiQ==} - - '@vercel/rust@1.2.0': - resolution: {integrity: sha512-JryMtBa0sFuqxfHpjrNgMks06XDKa8DVhGljTsoo26dIKqsoqeYhJHuepEAEXT+b5N+tUmxIOUcRq5//ewvytQ==} - - '@vercel/sandbox@1.9.0': - resolution: {integrity: sha512-zgr1ad0tkT1xZn/8Vxo60wOUOLqMAVGo4WqJQ8/UDcUtWynNJsBjI2tiMdWZrAo9EKH1MIqEzJNkcclF0UT1EQ==} - - '@vercel/static-build@2.9.23': - resolution: {integrity: sha512-u6uzY3+4BYpf9brVLrhvq08iv6BkQQOz782DbnerQfD8PZZ3uPK4dsksN2XfZO0zaWfUR3Lv6gkx6RGEQkJvqA==} - - '@vercel/static-config@3.3.0': - resolution: {integrity: sha512-GpS3tPwUeDJCkrKbMNtS2XLRFgfxTlN7YNUL+Bo23+fGolrDw6Oq79R3yvxTYgqRaJMGSEqC7iMw6mj6I5loxg==} - '@vitest/coverage-v8@4.1.6': resolution: {integrity: sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==} peerDependencies: @@ -9637,14 +9255,6 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@yarnpkg/parsers@3.0.3': - resolution: {integrity: sha512-mQZgUSgFurUtA07ceMjxrWkYz8QtDuYkvPlu0ZqncgjopQ0t6CNEo/OSealkmnagSUx8ZD5ewvezUwUuMqutQg==} - engines: {node: '>=18.12.0'} - - abbrev@3.0.1: - resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} - engines: {node: ^18.17.0 || >=20.5.0} - abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -9736,9 +9346,6 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - ajv@8.6.3: - resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} - anser@1.4.10: resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} @@ -9820,9 +9427,6 @@ packages: archy@1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - arg@4.1.0: - resolution: {integrity: sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -9863,10 +9467,6 @@ packages: resolution: {integrity: sha512-WHw67kLXYbZuHTmcdbIrVArCq5wxo6NEuj3hiYAWr8mwJeC+C2mMCIBIWCiDoCye/OF/xelc+teJ1ERoWmnEIA==} engines: {node: '>=18'} - ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} - ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} @@ -9878,23 +9478,6 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true - async-listen@1.2.0: - resolution: {integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==} - - async-listen@3.0.0: - resolution: {integrity: sha512-V+SsTpDqkrWTimiotsyl33ePSjA5/KrithwupuvJ6ztsqPvGv6ge4OredFhPffVXiLN/QUWvE0XcqJaYgt6fOg==} - engines: {node: '>= 14'} - - async-listen@3.0.1: - resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} - engines: {node: '>= 14'} - - async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} - - async-sema@3.1.1: - resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} - async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -10091,10 +9674,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - basic-ftp@5.3.1: - resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} - engines: {node: '>=10.0.0'} - before-after-hook@4.0.0: resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} @@ -10116,9 +9695,6 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -10201,9 +9777,6 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} @@ -10237,10 +9810,6 @@ packages: bun-types@1.3.14: resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} - bytes@3.1.0: - resolution: {integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==} - engines: {node: '>= 0.8'} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -10340,10 +9909,6 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.0: - resolution: {integrity: sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==} - engines: {node: '>= 14.16.0'} - chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} @@ -10489,9 +10054,6 @@ packages: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - code-block-writer@10.1.1: - resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==} - code-excerpt@4.0.0: resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -10589,10 +10151,6 @@ packages: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - console-browserify@1.2.0: resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} @@ -10607,18 +10165,10 @@ packages: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} - content-type@1.0.4: - resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} - engines: {node: '>= 0.6'} - content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} - convert-hrtime@3.0.0: - resolution: {integrity: sha512-7V+KqSvMiHp8yWDuwfww06XleMWVVB9b9tURBx+G7UTADuo5hYPuowKloz4OzOqbPezxgo+fdQ1522WzPG4OeA==} - engines: {node: '>=8'} - convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -10629,9 +10179,6 @@ packages: resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - cookie-es@2.0.1: - resolution: {integrity: sha512-aVf4A4hI2w70LnF7GG+7xDQUkliwiXWXFvTjkip4+b64ygDQ2sJPRSKFDHbxn8o0xu9QzPkMuuiWIXyFSE2slA==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -10813,10 +10360,6 @@ packages: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} - data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} @@ -10842,15 +10385,6 @@ packages: supports-color: optional: true - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -10920,18 +10454,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -11241,11 +10767,6 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - edge-runtime@2.5.9: - resolution: {integrity: sha512-pk+k0oK0PVXdlT4oRp4lwh+unuKB7Ng4iZ2HB+EZ7QCEQizX360Rp/F4aRpgpRgdP2ufB35N+1KppHmYjqIGSg==} - engines: {node: '>=16'} - hasBin: true - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -11286,9 +10807,6 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - end-of-stream@1.1.0: - resolution: {integrity: sha512-EoulkdKF/1xa92q25PbjuDcgJ9RDHYU2Rs3SCIvs2/dSQ3BpmxneNHmA/M7fe60M3PrV7nNGTTNbkK62l6vXiQ==} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -11345,12 +10863,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.4.1: - resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} - - es-module-lexer@1.5.0: - resolution: {integrity: sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==} - es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -11511,9 +11023,6 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - events-intercept@2.0.0: - resolution: {integrity: sha512-blk1va0zol9QOrdZt0rFXo5KMkNPVSp92Eju/Qz8THwKWKRKeE0T8Br/1aW6+Edkyq9xHYgYxn2QtOnUKPUp+Q==} - events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} @@ -11536,10 +11045,6 @@ packages: evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - execa@3.2.0: - resolution: {integrity: sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==} - engines: {node: ^8.12.0 || >=9.7.0} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -11947,9 +11452,6 @@ packages: fd-package-json@2.0.0: resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -11979,9 +11481,6 @@ packages: resolution: {integrity: sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA==} engines: {node: '>=22'} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - filesize@10.1.6: resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} engines: {node: '>= 10.4.0'} @@ -12147,14 +11646,6 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} - fs-extra@11.1.0: - resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==} - engines: {node: '>=14.14'} - - fs-extra@11.1.1: - resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} - engines: {node: '>=14.14'} - fs-monkey@1.1.0: resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} @@ -12189,10 +11680,6 @@ packages: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} - generic-pool@3.4.2: - resolution: {integrity: sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==} - engines: {node: '>= 4'} - gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -12232,10 +11719,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -12243,10 +11726,6 @@ packages: get-tsconfig@4.13.7: resolution: {integrity: sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==} - get-uri@6.0.5: - resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} - engines: {node: '>= 14'} - getenv@2.0.0: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} @@ -12459,18 +11938,10 @@ packages: htmlparser2@6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} - http-errors@1.7.3: - resolution: {integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==} - engines: {node: '>= 0.6'} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - http_ece@1.2.0: resolution: {integrity: sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==} engines: {node: '>=16'} @@ -12486,10 +11957,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - human-signals@1.1.1: - resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} - engines: {node: '>=8.12.0'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -12499,10 +11966,6 @@ packages: engines: {node: '>=18'} hasBin: true - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -12643,10 +12106,6 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -12714,9 +12173,6 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} - is-node-process@1.2.0: - resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -13138,9 +12594,6 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - jose@5.9.6: - resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} - jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} @@ -13205,9 +12658,6 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-to-ts@1.6.4: - resolution: {integrity: sha512-pR4yQ9DHz6itqswtHCm26mw45FSNfQ9rEQjosaZErhn5J3J2sIViQiz8rDaezjKAhFGpmsoczYVBgGHzFw/stA==} - json-schema-to-ts@3.1.1: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} @@ -13238,9 +12688,6 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - jsonlines@0.1.1: - resolution: {integrity: sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==} - jsonwebtoken@9.0.3: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} @@ -13507,10 +12954,6 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - lucide-react-native@1.7.0: resolution: {integrity: sha512-wGJY5nosSawh028jg8r1ZKqnGPDIVfIL9xvKOs4wPYFQHeJMHsADYm/lmuFYXMXXatSkHhpsCjeqIRgeFGzf8g==} peerDependencies: @@ -13523,10 +12966,6 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -13746,11 +13185,6 @@ packages: engines: {node: '>=20.19.4'} hasBin: true - micro@9.3.5-canary.3: - resolution: {integrity: sha512-viYIo9PefV+w9dvoIBh1gI44Mvx1BOk67B4BpC2QK77qdY0xZF0Q+vWLt/BII6cLkIc8rLmSIcJaB/OrXXKe1g==} - engines: {node: '>= 8.0.0'} - hasBin: true - micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -13921,10 +13355,6 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} @@ -14006,12 +13436,6 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.1: - resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} - - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -14063,10 +13487,6 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - netmask@2.1.1: - resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} - engines: {node: '>= 0.4.0'} - next-auth@4.24.14: resolution: {integrity: sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==} peerDependencies: @@ -14137,15 +13557,6 @@ packages: encoding: optional: true - node-fetch@2.6.9: - resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -14198,11 +13609,6 @@ packages: resolution: {integrity: sha512-3VW/8JpPqPvnJvseXowjZcirPisssnBuDikk6JIZ8jQzF7KJQX52iPFX4RYYxLycYH7IbMRSPUOga/esVjy5Yg==} engines: {node: '>=18'} - nopt@8.1.0: - resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} - engines: {node: ^18.17.0 || >=20.5.0} - hasBin: true - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -14279,9 +13685,6 @@ packages: resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} engines: {node: '>= 0.8'} - once@1.3.3: - resolution: {integrity: sha512-6vaNInhu+CHxtONf3zw3vq4SP2DOQhjBvIa3rNcG0+P7eKWlYH6Peu7rHizSloRU2EwMz6GraLieis9Ac9+p1w==} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -14352,10 +13755,6 @@ packages: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} - os-paths@4.4.0: - resolution: {integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==} - engines: {node: '>= 6.0'} - outvariant@1.4.0: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} @@ -14366,10 +13765,6 @@ packages: oxc-resolver@11.19.1: resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} - oxc-transform@0.111.0: - resolution: {integrity: sha512-oa5KKSDNLHZGaiqIGAbCWXeN9IJUAz9MElWcQX90epDxdKc9Hrt/BsLj3K4gDqfAYa5dwdH+ZCFJG9hR74fiGg==} - engines: {node: ^20.19.0 || >=22.12.0} - oxfmt@0.40.0: resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -14398,10 +13793,6 @@ packages: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} - p-finally@2.0.1: - resolution: {integrity: sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==} - engines: {node: '>=8'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -14450,14 +13841,6 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - pac-proxy-agent@7.2.0: - resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} - engines: {node: '>= 14'} - - pac-resolver@7.0.1: - resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} - engines: {node: '>= 14'} - package-hash@4.0.0: resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} engines: {node: '>=8'} @@ -14538,9 +13921,6 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} @@ -14559,9 +13939,6 @@ packages: resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} engines: {node: '>= 0.10'} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -14596,9 +13973,6 @@ packages: pgpass@1.0.5: resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} - picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -14817,9 +14191,6 @@ packages: promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} - promisepipe@3.0.0: - resolution: {integrity: sha512-V6TbZDJ/ZswevgkDNpGt/YqNCiZP9ASfgU+p83uJE6NrGtvSGoOcHLiDCqkMs2+yg7F5qHdLV8d0aS8O26G/KA==} - prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -14841,10 +14212,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-agent@6.4.0: - resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} - engines: {node: '>= 14'} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -14924,10 +14291,6 @@ packages: resolution: {integrity: sha512-CX4nij6+ZLHYIaojJNfLTr7W+AiH/IPJi6E9Aw1br2///1KZL2KBOHd68rkcLedc47MPvb4hhH+fzYeGFa4A/Q==} engines: {node: '>=22'} - raw-body@2.4.1: - resolution: {integrity: sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==} - engines: {node: '>= 0.8'} - raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -15175,10 +14538,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - readdirp@5.0.0: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} @@ -15405,11 +14764,6 @@ packages: resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} engines: {node: '>= 0.8'} - rolldown@1.0.0-rc.1: - resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rolldown@1.0.0-rc.17: resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -15465,10 +14819,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sandbox@2.5.6: - resolution: {integrity: sha512-tnFr7nyiuEhsAGb+xy60SDbij0790X+FgDljh3J/2HaRM6yQgNJkQKHbDH8ld7mR+PozXGgEfJ2Dc/5OyFnwsg==} - hasBin: true - sass-loader@16.0.7: resolution: {integrity: sha512-w6q+fRHourZ+e+xA1kcsF27iGM6jdB8teexYCfdUw0sYgcDNeZESnDNT9sUmmPm3ooziwUJXGwZJSTF3kOdBfA==} engines: {node: '>= 18.12.0'} @@ -15521,11 +14871,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -15574,9 +14919,6 @@ packages: setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - setprototypeof@1.1.1: - resolution: {integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -15630,10 +14972,6 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.0.2: - resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} - engines: {node: '>=14'} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -15681,26 +15019,10 @@ packages: resolution: {integrity: sha512-HVk9X1E0gz3mSpoi60h/saazLKXKaZThMLU3u/aNwoYn8/xQyX2MGxL0ui2eaokkD7tF+Zo+cKTHUbe1mmmGzA==} engines: {node: '>=8.0.0'} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - smol-toml@1.5.2: - resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==} - engines: {node: '>= 18'} - smol-toml@1.6.0: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} - - socks@2.8.9: - resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sonner-native@0.23.1: resolution: {integrity: sha512-p4WRxVoTjLTeuLcvuyMNzgd81tEUS0ayoqXEFhi5GNU1okbvBpqU5GiUjv14DgiLUYXPUQ0qq+OdrFJM2j4j+w==} peerDependencies: @@ -15789,11 +15111,6 @@ packages: sqlite-vec@0.1.9: resolution: {integrity: sha512-L7XJWRIBNvR9O5+vh1FQ+IGkh/3D2AzVksW5gdtk28m78Hy8skFD0pqReKH1Yp0/BUKRGcffgKvyO/EON5JXpA==} - srvx@0.8.9: - resolution: {integrity: sha512-wYc3VLZHRzwYrWJhkEqkhLb31TI0SOkfYZDkUhXdp3NoCnNS0FqajiQszZZjfow/VYEuc6Q5sZh9nM6kPy2NBQ==} - engines: {node: '>=20.16.0'} - hasBin: true - stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -15811,9 +15128,6 @@ packages: standardwebhooks@1.0.0: resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} - stat-mode@0.3.0: - resolution: {integrity: sha512-QjMLR0A3WwFY2aZdV0okfFEJB5TRjkggXZjxP3A1RsWsNHNu3YPv8btmtc6iCFZ0Rul3FE93OYogvhOUClU+ng==} - state-local@1.0.7: resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} @@ -15853,9 +15167,6 @@ packages: stream-to-array@2.3.0: resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} - stream-to-promise@2.2.0: - resolution: {integrity: sha512-HAGUASw8NT0k8JvIVutB2Y/9iBk7gpgEyAudXwNJmZERdMITGdajOa4VJfD/kNiA3TppQpTP4J+CtcHwdzKBAw==} - streamx@2.23.0: resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} @@ -16072,9 +15383,6 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar-stream@3.1.8: resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} @@ -16089,11 +15397,6 @@ packages: resolution: {integrity: sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==} engines: {node: '>=18'} - tar@7.5.7: - resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} - engines: {node: '>=18'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - teex@1.0.1: resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} @@ -16139,14 +15442,6 @@ packages: throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} - throttleit@2.1.0: - resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} - engines: {node: '>=18'} - - time-span@4.0.0: - resolution: {integrity: sha512-MyqZCTGLDZ77u4k+jqg4UlrzPTPZ49NDlaekU6uuFaJLzPIN1woaRXCbGeqOfxwc3Y37ZROGAJ614Rdv7Olt+g==} - engines: {node: '>=10'} - timers-browserify@2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} engines: {node: '>=0.6.0'} @@ -16157,9 +15452,6 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.4: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} @@ -16206,10 +15498,6 @@ packages: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} - toidentifier@1.0.0: - resolution: {integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==} - engines: {node: '>=0.6'} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -16307,12 +15595,6 @@ packages: ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} - ts-morph@12.0.0: - resolution: {integrity: sha512-VHC8XgU2fFW7yO1f/b3mxKDje1vmyzFXHWzOYmKEkCEwcLjDtbdLgBQviqj4ZwP4MJkQtRo6Ha2I29lq/B+VxA==} - - ts-toolbelt@6.15.5: - resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==} - tsconfig-paths-webpack-plugin@4.2.0: resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} engines: {node: '>=10.13.0'} @@ -16405,9 +15687,6 @@ packages: uhyphen@0.2.0: resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} - uid-promise@1.0.0: - resolution: {integrity: sha512-R8375j0qwXyIu/7R0tjdF06/sElHqbmdmWC9M2qQHpEVbvE4I5+38KJI7LUUmQMp7NVq4tKHiBMkT0NFM453Ig==} - uint8array-extras@1.5.0: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} @@ -16423,9 +15702,6 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -16435,10 +15711,6 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - undici@5.28.4: - resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} - engines: {node: '>=14.0'} - undici@6.24.1: resolution: {integrity: sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==} engines: {node: '>=18.17'} @@ -16632,11 +15904,6 @@ packages: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - vercel@53.3.1: - resolution: {integrity: sha512-egwINWuSoVm+8FPO7bIY+egSnIpVRy43QtukVa5QYzPgP0fwT2KaHDokPW9v6/VrgA/whAXdZSBn2Icg08WyCQ==} - engines: {node: '>= 18'} - hasBin: true - vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -16786,9 +16053,6 @@ packages: web-tree-sitter@0.26.9: resolution: {integrity: sha512-YJwSHANl6XFgeEjB8nitgj0qZYt5gkIesJ4w2srS2wcLB4GUa4xcOkM0YaMsU6WNR53YVIkDSY7Ej4pf3IXtCA==} - web-vitals@0.2.4: - resolution: {integrity: sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==} - web-vitals@5.1.0: resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} @@ -16970,18 +16234,6 @@ packages: resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} engines: {node: '>=10.0.0'} - xdg-app-paths@5.1.0: - resolution: {integrity: sha512-RAQ3WkPf4KTU1A8RtFx3gWywzVKe00tfOPFfl2NDGqbIFENQO4kqAJp7mhQjNj/33W5x5hiWWUdyfPq/5SU3QA==} - engines: {node: '>=6'} - - xdg-app-paths@5.5.1: - resolution: {integrity: sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==} - engines: {node: '>= 6.0'} - - xdg-portable@7.3.0: - resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} - engines: {node: '>= 6.0'} - xml2js@0.6.0: resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} engines: {node: '>=4.0.0'} @@ -17043,17 +16295,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yauzl-clone@1.0.4: - resolution: {integrity: sha512-igM2RRCf3k8TvZoxR2oguuw4z1xasOnA31joCqHIyLkeWrvAc2Jgay5ISQ2ZplinkoGaJ6orCz56Ey456c5ESA==} - engines: {node: '>=6'} - - yauzl-promise@2.1.3: - resolution: {integrity: sha512-A1pf6fzh6eYkK0L4Qp7g9jzJSDrM6nN0bOn5T0IbY4Yo3w+YkWlHFkJP7mzknMXjqusHFHlKsK2N+4OLsK2MRA==} - engines: {node: '>=6'} - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -17080,18 +16321,9 @@ packages: peerDependencies: zod: ^3.25 || ^4 - zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - - zod@3.24.4: - resolution: {integrity: sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==} - zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.1.11: - resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} - zod@4.1.8: resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==} @@ -18597,8 +17829,6 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@bytecodealliance/preview2-shim@0.17.6': {} - '@chat-adapter/github@4.27.0': dependencies: '@chat-adapter/shared': 4.27.0 @@ -18777,7 +18007,7 @@ snapshots: cjs-module-lexer: 1.2.3 esbuild: 0.27.4 miniflare: 4.20260603.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) wrangler: 4.98.0(@cloudflare/workers-types@4.20260605.1)(bufferutil@4.1.0)(utf-8-validate@6.0.6) zod: 3.25.76 transitivePeerDependencies: @@ -19166,18 +18396,6 @@ snapshots: get-east-asian-width: 1.6.0 marked: 15.0.12 - '@edge-runtime/format@2.2.1': {} - - '@edge-runtime/node-utils@2.3.0': {} - - '@edge-runtime/ponyfill@2.4.2': {} - - '@edge-runtime/primitives@4.1.0': {} - - '@edge-runtime/vm@3.2.0': - dependencies: - '@edge-runtime/primitives': 4.1.0 - '@egjs/hammerjs@2.0.17': dependencies: '@types/hammerjs': 2.0.46 @@ -19673,8 +18891,6 @@ snapshots: '@faker-js/faker@10.3.0': {} - '@fastify/busboy@2.1.1': {} - '@fastify/otel@0.16.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -19857,12 +19073,6 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.1': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.3 @@ -20572,19 +19782,6 @@ snapshots: '@lydell/node-pty-win32-arm64': 1.2.0-beta.12 '@lydell/node-pty-win32-x64': 1.2.0-beta.12 - '@mapbox/node-pre-gyp@2.0.3': - dependencies: - consola: 3.4.2 - detect-libc: 2.1.2 - https-proxy-agent: 7.0.6 - node-fetch: 2.7.0 - nopt: 8.1.0 - semver: 7.7.4 - tar: 7.5.15 - transitivePeerDependencies: - - encoding - - supports-color - '@marijn/find-cluster-break@1.0.2': {} '@mdx-js/loader@3.1.1(webpack@5.105.4(@swc/core@1.15.18)(esbuild@0.27.4))': @@ -21474,8 +20671,6 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.120.0': optional: true - '@oxc-project/types@0.110.0': {} - '@oxc-project/types@0.120.0': {} '@oxc-project/types@0.127.0': {} @@ -21542,71 +20737,6 @@ snapshots: '@oxc-resolver/binding-win32-x64-msvc@11.19.1': optional: true - '@oxc-transform/binding-android-arm-eabi@0.111.0': - optional: true - - '@oxc-transform/binding-android-arm64@0.111.0': - optional: true - - '@oxc-transform/binding-darwin-arm64@0.111.0': - optional: true - - '@oxc-transform/binding-darwin-x64@0.111.0': - optional: true - - '@oxc-transform/binding-freebsd-x64@0.111.0': - optional: true - - '@oxc-transform/binding-linux-arm-gnueabihf@0.111.0': - optional: true - - '@oxc-transform/binding-linux-arm-musleabihf@0.111.0': - optional: true - - '@oxc-transform/binding-linux-arm64-gnu@0.111.0': - optional: true - - '@oxc-transform/binding-linux-arm64-musl@0.111.0': - optional: true - - '@oxc-transform/binding-linux-ppc64-gnu@0.111.0': - optional: true - - '@oxc-transform/binding-linux-riscv64-gnu@0.111.0': - optional: true - - '@oxc-transform/binding-linux-riscv64-musl@0.111.0': - optional: true - - '@oxc-transform/binding-linux-s390x-gnu@0.111.0': - optional: true - - '@oxc-transform/binding-linux-x64-gnu@0.111.0': - optional: true - - '@oxc-transform/binding-linux-x64-musl@0.111.0': - optional: true - - '@oxc-transform/binding-openharmony-arm64@0.111.0': - optional: true - - '@oxc-transform/binding-wasm32-wasi@0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - - '@oxc-transform/binding-win32-arm64-msvc@0.111.0': - optional: true - - '@oxc-transform/binding-win32-ia32-msvc@0.111.0': - optional: true - - '@oxc-transform/binding-win32-x64-msvc@0.111.0': - optional: true - '@oxfmt/binding-android-arm-eabi@0.40.0': optional: true @@ -22803,8 +21933,6 @@ snapshots: react: 19.2.6 react-redux: 9.2.0(@types/react@19.2.14)(react@19.2.6)(redux@5.0.1) - '@renovatebot/pep440@4.2.1': {} - '@rn-primitives/portal@1.3.0(@types/react@19.2.14)(immer@11.1.4)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0)(use-sync-external-store@1.6.0(react@19.2.0))': dependencies: react: 19.2.0 @@ -22824,45 +21952,24 @@ snapshots: '@rocicorp/resolver@1.0.2': {} - '@rolldown/binding-android-arm64@1.0.0-rc.1': - optional: true - '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.1': - optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.1': - optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.1': - optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1': - optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1': - optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.1': - optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true @@ -22872,32 +21979,15 @@ snapshots: '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.1': - optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.1': - optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.1': - optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: '@emnapi/core': 1.10.0 @@ -22905,20 +21995,12 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1': - optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.1': - optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true - '@rolldown/pluginutils@1.0.0-rc.1': {} - '@rolldown/pluginutils@1.0.0-rc.17': {} '@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)': @@ -22941,14 +22023,6 @@ snapshots: optionalDependencies: rollup: 4.59.0 - '@rollup/pluginutils@5.3.0(rollup@4.59.1)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.4 - optionalDependencies: - rollup: 4.59.1 - '@rollup/rollup-android-arm-eabi@4.59.0': optional: true @@ -23456,8 +22530,6 @@ snapshots: '@silvia-odwyer/photon-node@0.3.4': {} - '@sinclair/typebox@0.25.24': {} - '@sinclair/typebox@0.27.10': {} '@sinclair/typebox@0.34.41': {} @@ -24560,10 +23632,6 @@ snapshots: '@tokenizer/token@0.3.0': {} - '@tootallnate/once@2.0.0': {} - - '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trpc/client@11.17.0(@trpc/server@11.17.0(typescript@5.9.3))(typescript@5.9.3)': dependencies: '@trpc/server': 11.17.0(typescript@5.9.3) @@ -24604,13 +23672,6 @@ snapshots: '@ts-graphviz/ast': 2.0.7 '@ts-graphviz/common': 2.1.5 - '@ts-morph/common@0.11.1': - dependencies: - fast-glob: 3.3.3 - minimatch: 3.1.5 - mkdirp: 1.0.4 - path-browserify: 1.0.1 - '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -24773,10 +23834,6 @@ snapshots: '@types/node': 24.12.4 form-data: 4.0.5 - '@types/node@20.11.0': - dependencies: - undici-types: 5.26.5 - '@types/node@20.19.41': dependencies: undici-types: 6.21.0 @@ -25026,244 +24083,14 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@vercel/backends@0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': - dependencies: - '@vercel/build-utils': 13.22.0 - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@yarnpkg/parsers': 3.0.3 - execa: 3.2.0 - fs-extra: 11.1.0 - js-yaml: 3.14.2 - oxc-transform: 0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - path-to-regexp: 8.4.2 - resolve.exports: 2.0.3 - rolldown: 1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - srvx: 0.8.9 - tsx: 4.21.0 - zod: 3.22.4 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - encoding - - rollup - - supports-color - - '@vercel/blob@2.3.0': - dependencies: - async-retry: 1.3.3 - is-buffer: 2.0.5 - is-node-process: 1.2.0 - throttleit: 2.1.0 - undici: 6.24.1 - - '@vercel/build-utils@13.22.0': - dependencies: - '@vercel/python-analysis': 0.11.1 - cjs-module-lexer: 1.2.3 - es-module-lexer: 1.5.0 - - '@vercel/cervel@0.1.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': - dependencies: - '@vercel/backends': 0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - encoding - - rollup - - supports-color - - '@vercel/cli-config@0.1.1': - dependencies: - xdg-app-paths: 5.5.1 - zod: 4.1.11 - - '@vercel/detect-agent@1.2.3': {} - - '@vercel/elysia@0.1.74(rollup@4.59.1)': - dependencies: - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/error-utils@2.1.0': {} - - '@vercel/express@0.1.84(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1)': - dependencies: - '@vercel/cervel': 0.1.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - fs-extra: 11.1.0 - path-to-regexp: 8.4.2 - ts-morph: 12.0.0 - zod: 3.22.4 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - encoding - - rollup - - supports-color - - '@vercel/fastify@0.1.77(rollup@4.59.1)': - dependencies: - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - '@vercel/firewall@1.2.1': {} - '@vercel/fun@1.3.0': - dependencies: - '@tootallnate/once': 2.0.0 - async-listen: 1.2.0 - debug: 4.3.4 - generic-pool: 3.4.2 - micro: 9.3.5-canary.3 - ms: 2.1.1 - node-fetch: 2.6.7 - path-to-regexp: 8.4.2 - promisepipe: 3.0.0 - semver: 7.5.4 - stat-mode: 0.3.0 - stream-to-promise: 2.2.0 - tar: 7.5.7 - tinyexec: 0.3.2 - tree-kill: 1.2.2 - uid-promise: 1.0.0 - xdg-app-paths: 5.1.0 - yauzl-promise: 2.1.3 - transitivePeerDependencies: - - encoding - - supports-color - '@vercel/functions@3.4.6(@aws-sdk/credential-provider-web-identity@3.972.20)': dependencies: '@vercel/oidc': 3.3.1 optionalDependencies: '@aws-sdk/credential-provider-web-identity': 3.972.20 - '@vercel/gatsby-plugin-vercel-analytics@1.0.11': - dependencies: - web-vitals: 0.2.4 - - '@vercel/gatsby-plugin-vercel-builder@2.2.1': - dependencies: - '@sinclair/typebox': 0.25.24 - '@vercel/build-utils': 13.22.0 - esbuild: 0.27.4 - etag: 1.8.1 - fs-extra: 11.1.0 - - '@vercel/go@3.6.0': {} - - '@vercel/h3@0.1.83(rollup@4.59.1)': - dependencies: - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/hono@0.2.77(rollup@4.59.1)': - dependencies: - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - fs-extra: 11.1.0 - path-to-regexp: 8.4.2 - ts-morph: 12.0.0 - zod: 3.22.4 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/hydrogen@1.3.7': - dependencies: - '@vercel/static-config': 3.3.0 - ts-morph: 12.0.0 - - '@vercel/koa@0.1.57(rollup@4.59.1)': - dependencies: - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/nestjs@0.2.78(rollup@4.59.1)': - dependencies: - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/next@4.17.1(rollup@4.59.1)': - dependencies: - '@vercel/nft': 1.5.0(rollup@4.59.1) - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/nft@1.5.0(rollup@4.59.1)': - dependencies: - '@mapbox/node-pre-gyp': 2.0.3 - '@rollup/pluginutils': 5.3.0(rollup@4.59.1) - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) - async-sema: 3.1.1 - bindings: 1.5.0 - estree-walker: 2.0.2 - glob: 13.0.6 - graceful-fs: 4.2.11 - node-gyp-build: 4.8.4 - picomatch: 4.0.4 - resolve-from: 5.0.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/node@5.7.16(rollup@4.59.1)': - dependencies: - '@edge-runtime/node-utils': 2.3.0 - '@edge-runtime/primitives': 4.1.0 - '@edge-runtime/vm': 3.2.0 - '@types/node': 20.11.0 - '@vercel/build-utils': 13.22.0 - '@vercel/error-utils': 2.1.0 - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - async-listen: 3.0.0 - cjs-module-lexer: 1.2.3 - edge-runtime: 2.5.9 - es-module-lexer: 1.4.1 - esbuild: 0.27.4 - etag: 1.8.1 - mime-types: 2.1.35 - node-fetch: 2.6.9 - path-to-regexp: 8.4.2 - path-to-regexp-updated: path-to-regexp@6.3.0 - ts-morph: 12.0.0 - tsx: 4.21.0 - typescript: 5.9.3 - undici: 5.28.4 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - '@vercel/oidc@3.2.0': {} '@vercel/oidc@3.3.1': {} @@ -25278,81 +24105,6 @@ snapshots: '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.1) - '@vercel/prepare-flags-definitions@0.2.1': {} - - '@vercel/python-analysis@0.11.1': - dependencies: - '@bytecodealliance/preview2-shim': 0.17.6 - '@renovatebot/pep440': 4.2.1 - fs-extra: 11.1.1 - js-yaml: 4.1.1 - minimatch: 10.1.1 - smol-toml: 1.5.2 - zod: 3.22.4 - - '@vercel/python@6.39.0': - dependencies: - '@vercel/python-analysis': 0.11.1 - - '@vercel/redwood@2.4.13(rollup@4.59.1)': - dependencies: - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - semver: 6.3.1 - ts-morph: 12.0.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/remix-builder@5.8.1(rollup@4.59.1)': - dependencies: - '@vercel/error-utils': 2.1.0 - '@vercel/nft': 1.5.0(rollup@4.59.1) - '@vercel/static-config': 3.3.0 - path-to-regexp: 8.4.2 - path-to-regexp-updated: path-to-regexp@6.3.0 - ts-morph: 12.0.0 - transitivePeerDependencies: - - encoding - - rollup - - supports-color - - '@vercel/ruby@2.3.2': {} - - '@vercel/rust@1.2.0': - dependencies: - execa: 5.1.1 - smol-toml: 1.5.2 - - '@vercel/sandbox@1.9.0': - dependencies: - '@vercel/oidc': 3.2.0 - async-retry: 1.3.3 - jsonlines: 0.1.1 - ms: 2.1.3 - picocolors: 1.1.1 - tar-stream: 3.1.7 - undici: 7.25.0 - xdg-app-paths: 5.1.0 - zod: 3.24.4 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - - '@vercel/static-build@2.9.23': - dependencies: - '@vercel/gatsby-plugin-vercel-analytics': 1.0.11 - '@vercel/gatsby-plugin-vercel-builder': 2.2.1 - '@vercel/static-config': 3.3.0 - ts-morph: 12.0.0 - - '@vercel/static-config@3.3.0': - dependencies: - ajv: 8.6.3 - json-schema-to-ts: 1.6.4 - ts-morph: 12.0.0 - '@vitest/coverage-v8@4.1.6(vitest@4.1.6)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -25365,7 +24117,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/expect@3.2.4': dependencies: @@ -25451,7 +24203,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/utils@3.2.4': dependencies: @@ -25597,13 +24349,6 @@ snapshots: '@xtuc/long@4.2.2': {} - '@yarnpkg/parsers@3.0.3': - dependencies: - js-yaml: 3.14.2 - tslib: 2.8.1 - - abbrev@3.0.1: {} - abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -25706,13 +24451,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ajv@8.6.3: - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - anser@1.4.10: {} anser@2.3.5: {} @@ -25788,8 +24526,6 @@ snapshots: archy@1.0.0: {} - arg@4.1.0: {} - arg@5.0.2: {} argparse@1.0.10: @@ -25833,10 +24569,6 @@ snapshots: ast-module-types@6.0.1: {} - ast-types@0.13.4: - dependencies: - tslib: 2.8.1 - ast-types@0.16.1: dependencies: tslib: 2.8.1 @@ -25849,18 +24581,6 @@ snapshots: astring@1.9.0: {} - async-listen@1.2.0: {} - - async-listen@3.0.0: {} - - async-listen@3.0.1: {} - - async-retry@1.3.3: - dependencies: - retry: 0.13.1 - - async-sema@3.1.1: {} - async@3.2.6: {} asynckit@0.4.0: {} @@ -26116,8 +24836,6 @@ snapshots: baseline-browser-mapping@2.10.8: {} - basic-ftp@5.3.1: {} - before-after-hook@4.0.0: {} better-opn@3.0.2: @@ -26132,10 +24850,6 @@ snapshots: binary-extensions@2.3.0: {} - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -26252,8 +24966,6 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-crc32@0.2.13: {} - buffer-crc32@1.0.0: {} buffer-equal-constant-time@1.0.1: {} @@ -26284,8 +24996,6 @@ snapshots: dependencies: '@types/node': 24.12.4 - bytes@3.1.0: {} - bytes@3.1.2: {} caching-transform@4.0.0: @@ -26392,10 +25102,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.0: - dependencies: - readdirp: 4.1.2 - chokidar@5.0.0: dependencies: readdirp: 5.0.0 @@ -26526,8 +25232,6 @@ snapshots: co@4.6.0: {} - code-block-writer@10.1.1: {} - code-excerpt@4.0.0: dependencies: convert-to-spaces: 2.0.1 @@ -26634,8 +25338,6 @@ snapshots: transitivePeerDependencies: - supports-color - consola@3.4.2: {} - console-browserify@1.2.0: {} constants-browserify@1.0.0: {} @@ -26646,20 +25348,14 @@ snapshots: content-disposition@1.0.1: {} - content-type@1.0.4: {} - content-type@1.0.5: {} - convert-hrtime@3.0.0: {} - convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} convert-to-spaces@2.0.1: {} - cookie-es@2.0.1: {} - cookie-signature@1.2.2: {} cookie@0.7.2: {} @@ -26893,8 +25589,6 @@ snapshots: data-uri-to-buffer@4.0.1: {} - data-uri-to-buffer@6.0.2: {} - date-fns@4.1.0: {} dayjs@1.11.20: {} @@ -26909,10 +25603,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.4: - dependencies: - ms: 2.1.2 - debug@4.4.3: dependencies: ms: 2.1.3 @@ -26963,16 +25653,8 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - degenerator@5.0.1: - dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - delayed-stream@1.0.0: {} - depd@1.1.2: {} - depd@2.0.0: {} dependency-cruiser@17.3.10: @@ -27248,18 +25930,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - edge-runtime@2.5.9: - dependencies: - '@edge-runtime/format': 2.2.1 - '@edge-runtime/ponyfill': 2.4.2 - '@edge-runtime/vm': 3.2.0 - async-listen: 3.0.1 - mri: 1.2.0 - picocolors: 1.0.0 - pretty-ms: 7.0.1 - signal-exit: 4.0.2 - time-span: 4.0.0 - ee-first@1.1.1: {} effect@4.0.0-beta.57: @@ -27303,10 +25973,6 @@ snapshots: encodeurl@2.0.0: {} - end-of-stream@1.1.0: - dependencies: - once: 1.3.3 - end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -27355,10 +26021,6 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@1.4.1: {} - - es-module-lexer@1.5.0: {} - es-module-lexer@1.7.0: {} es-module-lexer@2.0.0: {} @@ -27559,8 +26221,6 @@ snapshots: eventemitter3@5.0.4: {} - events-intercept@2.0.0: {} - events-universal@1.0.1: dependencies: bare-events: 2.8.2 @@ -27582,19 +26242,6 @@ snapshots: md5.js: 1.3.5 safe-buffer: 5.2.1 - execa@3.2.0: - dependencies: - cross-spawn: 7.0.6 - get-stream: 5.2.0 - human-signals: 1.1.1 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - p-finally: 2.0.1 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -28095,10 +26742,6 @@ snapshots: dependencies: walk-up-path: 4.0.0 - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -28125,8 +26768,6 @@ snapshots: transitivePeerDependencies: - supports-color - file-uri-to-path@1.0.0: {} - filesize@10.1.6: {} filing-cabinet@5.2.0: @@ -28328,18 +26969,6 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 - fs-extra@11.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - - fs-extra@11.1.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - fs-monkey@1.1.0: {} fsevents@2.3.2: @@ -28372,8 +27001,6 @@ snapshots: generator-function@2.0.1: {} - generic-pool@3.4.2: {} - gensync@1.0.0-beta.2: {} get-amd-module-type@6.0.1: @@ -28411,24 +27038,12 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stream@5.2.0: - dependencies: - pump: 3.0.4 - get-stream@6.0.1: {} get-tsconfig@4.13.7: dependencies: resolve-pkg-maps: 1.0.0 - get-uri@6.0.5: - dependencies: - basic-ftp: 5.3.1 - data-uri-to-buffer: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - getenv@2.0.0: {} github-slugger@2.0.0: {} @@ -28705,14 +27320,6 @@ snapshots: domutils: 2.8.0 entities: 2.2.0 - http-errors@1.7.3: - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.1.1 - statuses: 1.5.0 - toidentifier: 1.0.0 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -28721,13 +27328,6 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - http_ece@1.2.0: {} https-browserify@1.0.0: {} @@ -28746,16 +27346,10 @@ snapshots: transitivePeerDependencies: - supports-color - human-signals@1.1.1: {} - human-signals@2.1.0: {} husky@9.1.7: {} - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -28886,8 +27480,6 @@ snapshots: dependencies: binary-extensions: 2.3.0 - is-buffer@2.0.5: {} - is-callable@1.2.7: {} is-core-module@2.16.1: @@ -28940,8 +27532,6 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 - is-node-process@1.2.0: {} - is-number@7.0.0: {} is-obj@1.0.1: {} @@ -29892,8 +28482,6 @@ snapshots: jose@5.10.0: {} - jose@5.9.6: {} - jose@6.2.3: {} jotai-minidb@0.0.8(jotai@2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.6)): @@ -29945,11 +28533,6 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-schema-to-ts@1.6.4: - dependencies: - '@types/json-schema': 7.0.15 - ts-toolbelt: 6.15.5 - json-schema-to-ts@3.1.1: dependencies: '@babel/runtime': 7.29.2 @@ -29975,8 +28558,6 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonlines@0.1.1: {} - jsonwebtoken@9.0.3: dependencies: jws: 4.0.1 @@ -30229,8 +28810,6 @@ snapshots: dependencies: yallist: 4.0.0 - lru-cache@7.18.3: {} - lucide-react-native@1.7.0(react-native-svg@15.15.3(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0))(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0): dependencies: react: 19.2.0 @@ -30241,8 +28820,6 @@ snapshots: dependencies: react: 19.2.6 - luxon@3.7.2: {} - lz-string@1.5.0: {} madge@8.0.0(typescript@5.9.3): @@ -30707,12 +29284,6 @@ snapshots: - supports-color - utf-8-validate - micro@9.3.5-canary.3: - dependencies: - arg: 4.1.0 - content-type: 1.0.4 - raw-body: 2.4.1 - micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.3.0 @@ -31051,10 +29622,6 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.1 - minimatch@10.2.4: dependencies: brace-expansion: 5.0.6 @@ -31124,10 +29691,6 @@ snapshots: ms@2.0.0: {} - ms@2.1.1: {} - - ms@2.1.2: {} - ms@2.1.3: {} msgpackr-extract@3.0.3: @@ -31170,8 +29733,6 @@ snapshots: neo-async@2.6.2: {} - netmask@2.1.1: {} - next-auth@4.24.14(next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 @@ -31248,10 +29809,6 @@ snapshots: dependencies: whatwg-url: 5.0.0 - node-fetch@2.6.9: - dependencies: - whatwg-url: 5.0.0 - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -31321,10 +29878,6 @@ snapshots: dependencies: '@babel/parser': 7.29.0 - nopt@8.1.0: - dependencies: - abbrev: 3.0.1 - normalize-path@3.0.0: {} npm-package-arg@11.0.3: @@ -31420,10 +29973,6 @@ snapshots: on-headers@1.1.0: {} - once@1.3.3: - dependencies: - wrappy: 1.0.2 - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -31559,8 +30108,6 @@ snapshots: os-homedir@1.0.2: {} - os-paths@4.4.0: {} - outvariant@1.4.0: {} oxc-parser@0.120.0: @@ -31611,32 +30158,6 @@ snapshots: '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 - oxc-transform@0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): - optionalDependencies: - '@oxc-transform/binding-android-arm-eabi': 0.111.0 - '@oxc-transform/binding-android-arm64': 0.111.0 - '@oxc-transform/binding-darwin-arm64': 0.111.0 - '@oxc-transform/binding-darwin-x64': 0.111.0 - '@oxc-transform/binding-freebsd-x64': 0.111.0 - '@oxc-transform/binding-linux-arm-gnueabihf': 0.111.0 - '@oxc-transform/binding-linux-arm-musleabihf': 0.111.0 - '@oxc-transform/binding-linux-arm64-gnu': 0.111.0 - '@oxc-transform/binding-linux-arm64-musl': 0.111.0 - '@oxc-transform/binding-linux-ppc64-gnu': 0.111.0 - '@oxc-transform/binding-linux-riscv64-gnu': 0.111.0 - '@oxc-transform/binding-linux-riscv64-musl': 0.111.0 - '@oxc-transform/binding-linux-s390x-gnu': 0.111.0 - '@oxc-transform/binding-linux-x64-gnu': 0.111.0 - '@oxc-transform/binding-linux-x64-musl': 0.111.0 - '@oxc-transform/binding-openharmony-arm64': 0.111.0 - '@oxc-transform/binding-wasm32-wasi': 0.111.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - '@oxc-transform/binding-win32-arm64-msvc': 0.111.0 - '@oxc-transform/binding-win32-ia32-msvc': 0.111.0 - '@oxc-transform/binding-win32-x64-msvc': 0.111.0 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - oxfmt@0.40.0: dependencies: tinypool: 2.1.0 @@ -31700,8 +30221,6 @@ snapshots: p-finally@1.0.0: {} - p-finally@2.0.1: {} - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -31750,24 +30269,6 @@ snapshots: p-try@2.2.0: {} - pac-proxy-agent@7.2.0: - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.4 - debug: 4.4.3 - get-uri: 6.0.5 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - - pac-resolver@7.0.1: - dependencies: - degenerator: 5.0.1 - netmask: 2.1.1 - package-hash@4.0.0: dependencies: graceful-fs: 4.2.11 @@ -31849,8 +30350,6 @@ snapshots: lru-cache: 11.2.7 minipass: 7.1.3 - path-to-regexp@6.3.0: {} - path-to-regexp@8.4.2: {} path-type@4.0.0: {} @@ -31868,8 +30367,6 @@ snapshots: sha.js: 2.4.12 to-buffer: 1.2.2 - pend@1.2.0: {} - pg-cloudflare@1.3.0: optional: true @@ -31905,8 +30402,6 @@ snapshots: dependencies: split2: 4.2.0 - picocolors@1.0.0: {} - picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -32119,8 +30614,6 @@ snapshots: dependencies: asap: 2.0.6 - promisepipe@3.0.0: {} - prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -32150,19 +30643,6 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-agent@6.4.0: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - lru-cache: 7.18.3 - pac-proxy-agent: 7.2.0 - proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.5 - transitivePeerDependencies: - - supports-color - proxy-from-env@1.1.0: {} proxy-from-env@2.1.0: {} @@ -32242,13 +30722,6 @@ snapshots: dependencies: '@silvia-odwyer/photon-node': 0.3.4 - raw-body@2.4.1: - dependencies: - bytes: 3.1.0 - http-errors: 1.7.3 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -32613,8 +31086,6 @@ snapshots: dependencies: picomatch: 2.3.2 - readdirp@4.1.2: {} - readdirp@5.0.0: {} recast@0.23.11: @@ -32894,28 +31365,6 @@ snapshots: hash-base: 3.1.2 inherits: 2.0.4 - rolldown@1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): - dependencies: - '@oxc-project/types': 0.110.0 - '@rolldown/pluginutils': 1.0.0-rc.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.1 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.1 - '@rolldown/binding-darwin-x64': 1.0.0-rc.1 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.1 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.1 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.1 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - rolldown@1.0.0-rc.17: dependencies: '@oxc-project/types': 0.127.0 @@ -33050,16 +31499,6 @@ snapshots: safer-buffer@2.1.2: {} - sandbox@2.5.6: - dependencies: - '@vercel/sandbox': 1.9.0 - debug: 4.4.3 - zod: 4.4.3 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - - supports-color - sass-loader@16.0.7(webpack@5.105.4(esbuild@0.27.4)): dependencies: neo-async: 2.6.2 @@ -33098,10 +31537,6 @@ snapshots: semver@6.3.1: {} - semver@7.5.4: - dependencies: - lru-cache: 6.0.0 - semver@7.6.3: {} semver@7.7.3: {} @@ -33177,8 +31612,6 @@ snapshots: setimmediate@1.0.5: {} - setprototypeof@1.1.1: {} - setprototypeof@1.2.0: {} sf-symbols-typescript@2.2.0: {} @@ -33262,8 +31695,6 @@ snapshots: signal-exit@3.0.7: {} - signal-exit@4.0.2: {} - signal-exit@4.1.0: {} simple-concat@1.0.1: {} @@ -33313,25 +31744,8 @@ snapshots: slugify@1.6.8: {} - smart-buffer@4.2.0: {} - - smol-toml@1.5.2: {} - smol-toml@1.6.0: {} - socks-proxy-agent@8.0.5: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - socks: 2.8.9 - transitivePeerDependencies: - - supports-color - - socks@2.8.9: - dependencies: - ip-address: 10.2.0 - smart-buffer: 4.2.0 - sonner-native@0.23.1(87a488248bd28430641b1320077ef29b): dependencies: react: 19.2.0 @@ -33415,10 +31829,6 @@ snapshots: sqlite-vec-windows-x64: 0.1.9 optional: true - srvx@0.8.9: - dependencies: - cookie-es: 2.0.1 - stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -33436,8 +31846,6 @@ snapshots: '@stablelib/base64': 1.0.1 fast-sha256: 1.3.0 - stat-mode@0.3.0: {} - state-local@1.0.7: {} static-browser-server@1.0.3: @@ -33493,12 +31901,6 @@ snapshots: dependencies: any-promise: 1.3.0 - stream-to-promise@2.2.0: - dependencies: - any-promise: 1.3.0 - end-of-stream: 1.1.0 - stream-to-array: 2.3.0 - streamx@2.23.0: dependencies: events-universal: 1.0.1 @@ -33694,15 +32096,6 @@ snapshots: tapable@2.3.0: {} - tar-stream@3.1.7: - dependencies: - b4a: 1.8.0 - fast-fifo: 1.3.2 - streamx: 2.23.0 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - tar-stream@3.1.8: dependencies: b4a: 1.8.0 @@ -33741,14 +32134,6 @@ snapshots: minizlib: 3.1.0 yallist: 5.0.0 - tar@7.5.7: - dependencies: - '@isaacs/fs-minipass': 4.0.1 - chownr: 3.0.0 - minipass: 7.1.3 - minizlib: 3.1.0 - yallist: 5.0.0 - teex@1.0.1: dependencies: streamx: 2.23.0 @@ -33815,12 +32200,6 @@ snapshots: throat@5.0.0: {} - throttleit@2.1.0: {} - - time-span@4.0.0: - dependencies: - convert-hrtime: 3.0.0 - timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 @@ -33829,8 +32208,6 @@ snapshots: tinybench@2.9.0: {} - tinyexec@0.3.2: {} - tinyexec@1.0.4: {} tinyglobby@0.2.16: @@ -33866,8 +32243,6 @@ snapshots: toad-cache@3.7.0: {} - toidentifier@1.0.0: {} - toidentifier@1.0.1: {} token-types@6.1.2: @@ -33961,13 +32336,6 @@ snapshots: ts-mixer@6.0.4: {} - ts-morph@12.0.0: - dependencies: - '@ts-morph/common': 0.11.1 - code-block-writer: 10.1.1 - - ts-toolbelt@6.15.5: {} - tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 @@ -34043,8 +32411,6 @@ snapshots: uhyphen@0.2.0: {} - uid-promise@1.0.0: {} - uint8array-extras@1.5.0: {} ulid@3.0.2: {} @@ -34053,18 +32419,12 @@ snapshots: uncrypto@0.1.3: {} - undici-types@5.26.5: {} - undici-types@6.21.0: {} undici-types@7.16.0: {} undici-types@7.18.2: {} - undici@5.28.4: - dependencies: - '@fastify/busboy': 2.1.1 - undici@6.24.1: {} undici@7.25.0: {} @@ -34290,50 +32650,6 @@ snapshots: - '@types/react' - '@types/react-dom' - vercel@53.3.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1): - dependencies: - '@vercel/backends': 0.4.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) - '@vercel/blob': 2.3.0 - '@vercel/build-utils': 13.22.0 - '@vercel/cli-config': 0.1.1 - '@vercel/detect-agent': 1.2.3 - '@vercel/elysia': 0.1.74(rollup@4.59.1) - '@vercel/express': 0.1.84(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(rollup@4.59.1) - '@vercel/fastify': 0.1.77(rollup@4.59.1) - '@vercel/fun': 1.3.0 - '@vercel/go': 3.6.0 - '@vercel/h3': 0.1.83(rollup@4.59.1) - '@vercel/hono': 0.2.77(rollup@4.59.1) - '@vercel/hydrogen': 1.3.7 - '@vercel/koa': 0.1.57(rollup@4.59.1) - '@vercel/nestjs': 0.2.78(rollup@4.59.1) - '@vercel/next': 4.17.1(rollup@4.59.1) - '@vercel/node': 5.7.16(rollup@4.59.1) - '@vercel/prepare-flags-definitions': 0.2.1 - '@vercel/python': 6.39.0 - '@vercel/redwood': 2.4.13(rollup@4.59.1) - '@vercel/remix-builder': 5.8.1(rollup@4.59.1) - '@vercel/ruby': 2.3.2 - '@vercel/rust': 1.2.0 - '@vercel/static-build': 2.9.23 - chokidar: 4.0.0 - esbuild: 0.27.4 - form-data: 4.0.5 - jose: 5.9.6 - luxon: 3.7.2 - proxy-agent: 6.4.0 - sandbox: 2.5.6 - smol-toml: 1.5.2 - zod: 4.1.11 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - bare-abort-controller - - encoding - - react-native-b4a - - rollup - - supports-color - vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 @@ -34409,7 +32725,7 @@ snapshots: tsx: 4.21.0 yaml: 2.8.4 - vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@22.19.19)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@22.19.19)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -34432,7 +32748,6 @@ snapshots: vite: 8.0.10(@types/node@22.19.19)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: - '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 22.19.19 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -34451,7 +32766,7 @@ snapshots: - tsx - yaml - vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -34474,7 +32789,6 @@ snapshots: vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: - '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 24.12.4 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -34493,7 +32807,7 @@ snapshots: - tsx - yaml - vitest@4.1.6(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + vitest@4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: '@vitest/expect': 4.1.6 '@vitest/mocker': 4.1.6(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -34516,7 +32830,6 @@ snapshots: vite: 8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) why-is-node-running: 2.3.0 optionalDependencies: - '@edge-runtime/vm': 3.2.0 '@opentelemetry/api': 1.9.1 '@types/node': 25.5.2 '@vitest/coverage-v8': 4.1.6(vitest@4.1.6) @@ -34595,8 +32908,6 @@ snapshots: web-tree-sitter@0.26.9: {} - web-vitals@0.2.4: {} - web-vitals@5.1.0: {} webidl-conversions@3.0.1: {} @@ -34886,19 +33197,6 @@ snapshots: simple-plist: 1.3.1 uuid: 7.0.3 - xdg-app-paths@5.1.0: - dependencies: - xdg-portable: 7.3.0 - - xdg-app-paths@5.5.1: - dependencies: - os-paths: 4.4.0 - xdg-portable: 7.3.0 - - xdg-portable@7.3.0: - dependencies: - os-paths: 4.4.0 - xml2js@0.6.0: dependencies: sax: 1.6.0 @@ -34961,20 +33259,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl-clone@1.0.4: - dependencies: - events-intercept: 2.0.0 - - yauzl-promise@2.1.3: - dependencies: - yauzl: 2.10.0 - yauzl-clone: 1.0.4 - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - yocto-queue@0.1.0: {} yocto-queue@1.2.2: {} @@ -35008,14 +33292,8 @@ snapshots: dependencies: zod: 4.4.3 - zod@3.22.4: {} - - zod@3.24.4: {} - zod@3.25.76: {} - zod@4.1.11: {} - zod@4.1.8: {} zod@4.3.6: {} diff --git a/scripts/typecheck-all.sh b/scripts/typecheck-all.sh index 412881e6a..f9d8da334 100755 --- a/scripts/typecheck-all.sh +++ b/scripts/typecheck-all.sh @@ -42,9 +42,8 @@ else pnpm --filter @kilocode/trpc run build fi -# 2. Root typechecks (always — they are fast with incremental tsgo) +# 2. Root typecheck (always — it's fast with incremental tsgo) tsgo --noEmit -p apps/web/tsconfig.json -tsgo --noEmit -p scripts/web-env/tsconfig.json # 3. Workspace typecheck if ! $changes_only; then diff --git a/scripts/web-env/adapters.test.ts b/scripts/web-env/adapters.test.ts deleted file mode 100644 index 994b3789d..000000000 --- a/scripts/web-env/adapters.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import type { CommandExecutor, CommandRequest, CommandResult } from './command.js'; -import { OnePasswordAdapter } from './onepassword.js'; -import { VercelAdapter } from './vercel.js'; - -function success(stdout: string): CommandResult { - return { status: 0, stdout, stderr: '' }; -} - -void test('Vercel adapter uses isolated project IDs and passes values only through stdin', async () => { - const requests: CommandRequest[] = []; - const execute: CommandExecutor = async request => { - requests.push(request); - const args = request.args; - if (args.includes('--version')) return success('Vercel CLI 53.3.1'); - if (args.includes('whoami')) { - return success(JSON.stringify({ team: { id: 'team_test', slug: 'kilocode' } })); - } - if (args.includes('project') && args.includes('list')) { - const filterIndex = args.indexOf('--filter'); - const name = args[filterIndex + 1]; - return success(JSON.stringify({ projects: [{ id: `id-${name}`, name }] })); - } - if (args.includes('target') && args.includes('list')) { - return success(JSON.stringify({ targets: [{ id: 'env_staging', slug: 'staging' }] })); - } - if (args.includes('api')) { - return success( - JSON.stringify({ env: { API_TOKEN: 'literal\\nsequence {"key":"value"} C:\\temp' } }) - ); - } - if (args.includes('env') && args.includes('add')) return success('{}'); - if (args.includes('env') && args.includes('list')) { - return success(JSON.stringify({ envs: [{ key: 'API_TOKEN', type: 'sensitive' }] })); - } - throw new Error(`Unexpected fake command: ${args.join(' ')}`); - }; - - const adapter = new VercelAdapter(execute, '/private/temp'); - await adapter.initialize(); - await adapter.writeVariable({ - mode: 'add', - project: 'kilocode-app', - environment: 'production', - key: 'API_TOKEN', - value: 'super-secret-value', - sensitive: true, - expectedType: 'sensitive', - }); - await adapter.writeVariable({ - mode: 'add', - project: 'kilocode-app', - environment: 'staging', - key: 'API_TOKEN', - value: 'staging-secret-value', - sensitive: true, - expectedType: 'sensitive', - }); - - const write = requests.find( - request => request.args.includes('add') && request.args.includes('production') - ); - assert.ok(write); - assert.equal(write.stdin, 'super-secret-value'); - assert.equal(write.args.includes('super-secret-value'), false); - assert.equal(write.cwd, '/private/temp'); - assert.equal(write.env?.VERCEL_ORG_ID, 'team_test'); - assert.equal(write.env?.VERCEL_PROJECT_ID, 'id-kilocode-app'); - const stagingWrite = requests.find( - request => request.args.includes('add') && request.args.includes('env_staging') - ); - assert.ok(stagingWrite); - assert.equal(stagingWrite.args.includes('staging'), false); - assert.equal( - await adapter.pullReadableValue('kilocode-app', 'production', 'API_TOKEN'), - 'literal\\nsequence {"key":"value"} C:\\temp' - ); - const pull = requests.find(request => - request.args.includes('/v3/env/pull/id-kilocode-app/production?source=vercel-cli%3Aenv%3Apull') - ); - assert.ok(pull); - assert.ok( - requests.every(request => request.cwd === undefined || request.cwd === '/private/temp') - ); -}); - -void test('Vercel adapter keeps sensitive development values exportable', async () => { - const requests: CommandRequest[] = []; - const execute: CommandExecutor = async request => { - requests.push(request); - if (request.args.includes('--version')) return success('53.3.1'); - if (request.args.includes('whoami')) { - return success(JSON.stringify({ team: { id: 'team_test', slug: 'kilocode' } })); - } - if (request.args.includes('project')) { - const name = request.args[request.args.indexOf('--filter') + 1]; - return success(JSON.stringify({ projects: [{ id: `id-${name}`, name }] })); - } - if (request.args.includes('target')) { - return success(JSON.stringify({ targets: [{ id: 'env_staging', slug: 'staging' }] })); - } - if (request.args.includes('add')) return success('{}'); - if (request.args.includes('list')) { - return success(JSON.stringify({ envs: [{ key: 'TOKEN', type: 'encrypted' }] })); - } - throw new Error('Unexpected fake command'); - }; - const adapter = new VercelAdapter(execute, '/private/temp'); - await adapter.initialize(); - await adapter.writeVariable({ - mode: 'add', - project: 'kilocode-app', - environment: 'development', - key: 'TOKEN', - value: 'development-secret', - sensitive: false, - expectedType: 'encrypted', - }); - const write = requests.find(request => request.args.includes('add')); - assert.ok(write?.args.includes('--no-sensitive')); - assert.equal(write?.args.includes('--sensitive'), false); -}); - -void test('1Password preflight rejects duplicate or malformed existing items', async () => { - const duplicates: CommandExecutor = async request => { - if (request.args[0] === '--version') return success('2.32.0'); - if (request.args[0] === 'whoami') return success('{}'); - if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); - if (request.args[0] === 'item' && request.args[1] === 'list') { - return success( - JSON.stringify([ - { id: 'one', title: 'API_TOKEN' }, - { id: 'two', title: 'API_TOKEN' }, - ]) - ); - } - throw new Error('Unexpected fake command'); - }; - const duplicateAdapter = new OnePasswordAdapter(duplicates); - await duplicateAdapter.initialize(); - await assert.rejects( - duplicateAdapter.validateExistingItem('API_TOKEN'), - /Multiple 1Password items/ - ); - - const malformed: CommandExecutor = async request => { - if (request.args[0] === '--version') return success('2.32.0'); - if (request.args[0] === 'whoami') return success('{}'); - if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); - if (request.args[0] === 'item' && request.args[1] === 'list') { - return success(JSON.stringify([{ id: 'one', title: 'API_TOKEN' }])); - } - if (request.args[0] === 'item' && request.args[1] === 'get') { - return success( - JSON.stringify({ - id: 'one', - fields: [{ id: 'password', label: 'password', type: 'STRING', value: '' }], - }) - ); - } - throw new Error('Unexpected fake command'); - }; - const malformedAdapter = new OnePasswordAdapter(malformed); - await malformedAdapter.initialize(); - await assert.rejects(malformedAdapter.validateExistingItem('API_TOKEN'), /password field/); -}); - -void test('1Password adapter creates and verifies an exact-name concealed item', async () => { - const requests: CommandRequest[] = []; - const execute: CommandExecutor = async request => { - requests.push(request); - if (request.args[0] === '--version') return success('2.32.0'); - if (request.args[0] === 'whoami') return success('{}'); - if (request.args[0] === 'vault') return success(JSON.stringify({ id: 'vault_test' })); - if (request.args[0] === 'item' && request.args[1] === 'list') return success('[]'); - if (request.args[0] === 'item' && request.args[1] === 'template') { - return success( - JSON.stringify({ - title: '', - category: 'PASSWORD', - fields: [{ id: 'password', label: 'password', type: 'CONCEALED', value: '' }], - }) - ); - } - if (request.args[0] === 'item' && request.args[1] === 'create') { - return success(JSON.stringify({ id: 'item_test' })); - } - if ( - request.args[0] === 'item' && - request.args[1] === 'get' && - request.args.includes('--fields') - ) { - return success( - JSON.stringify({ id: 'password', type: 'CONCEALED', value: 'production-secret' }) - ); - } - throw new Error(`Unexpected fake command: ${request.args.join(' ')}`); - }; - - const adapter = new OnePasswordAdapter(execute); - await adapter.initialize(); - await adapter.writeProductionValue('add', 'API_TOKEN', 'production-secret'); - - const create = requests.find(request => request.args[1] === 'create'); - assert.ok(create?.stdin?.includes('production-secret')); - assert.equal(create?.args.includes('production-secret'), false); - assert.ok(create?.stdin?.includes('API_TOKEN')); - assert.ok(create?.args.includes('vault_test')); -}); diff --git a/scripts/web-env/apply.test.ts b/scripts/web-env/apply.test.ts deleted file mode 100644 index 2a474ad87..000000000 --- a/scripts/web-env/apply.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtemp, readFile, rm } from 'node:fs/promises'; -import os from 'node:os'; -import path from 'node:path'; -import test from 'node:test'; -import { applyRemoteChanges, PartialRemoteFailureError } from './apply.js'; -import type { OnePasswordAdapter } from './onepassword.js'; -import type { VercelAdapter } from './vercel.js'; - -const values = { - development: 'development-secret-value', - staging: 'staging-secret-value', - production: 'production-secret-value', -}; - -void test('remote apply stops on first failure and writes a value-free resume journal', async () => { - const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-apply-test-')); - const calls: string[] = []; - const vercel = { - writeVariable: async (input: Parameters[0]) => { - const id = `${input.project}/${input.environment}`; - calls.push(id); - if (id === 'kilocode-app/staging') throw new Error('provider included a secret'); - }, - }; - const onePassword = { - writeProductionValue: async () => { - calls.push('1Password'); - }, - }; - - try { - let failure: PartialRemoteFailureError | undefined; - try { - await applyRemoteChanges({ - repoRoot: root, - mode: 'update', - variableName: 'API_TOKEN', - sensitive: true, - values, - vercel, - onePassword, - now: () => new Date('2026-06-16T12:00:00.000Z'), - }); - } catch (error) { - if (error instanceof PartialRemoteFailureError) failure = error; - else throw error; - } - assert.ok(failure); - assert.deepEqual(calls, [ - 'kilocode-app/development', - 'kilocode-global-app/development', - 'kilocode-app/staging', - ]); - assert.deepEqual(failure.journal.completed, [ - 'kilocode-app/development', - 'kilocode-global-app/development', - ]); - assert.equal(failure.journal.failed, 'kilocode-app/staging'); - const journal = await readFile(path.join(root, failure.journalPath), 'utf8'); - assert.equal(journal.includes('secret-value'), false); - assert.equal(journal.includes('provider included a secret'), false); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - -void test('non-sensitive apply skips 1Password after writing the full matrix', async () => { - const calls: string[] = []; - const vercel = { - writeVariable: async (input: Parameters[0]) => { - calls.push(`${input.project}/${input.environment}/${input.expectedType}`); - }, - }; - const onePassword = { - writeProductionValue: async () => { - calls.push('1Password'); - }, - }; - await applyRemoteChanges({ - repoRoot: '/unused', - mode: 'add', - variableName: 'FEATURE_FLAG', - sensitive: false, - values, - vercel, - onePassword, - }); - assert.equal(calls.length, 6); - assert.ok(calls.every(call => call.endsWith('/encrypted'))); - assert.equal(calls.includes('1Password'), false); -}); - -void test('sensitive apply sends only the production value to 1Password', async () => { - const received: string[] = []; - const vercel = { - writeVariable: async () => undefined, - }; - const onePassword = { - writeProductionValue: async ( - ...input: Parameters - ) => { - received.push(input[2]); - }, - }; - await applyRemoteChanges({ - repoRoot: '/unused', - mode: 'update', - variableName: 'API_TOKEN', - sensitive: true, - values, - vercel, - onePassword, - }); - assert.deepEqual(received, ['production-secret-value']); -}); diff --git a/scripts/web-env/apply.ts b/scripts/web-env/apply.ts deleted file mode 100644 index 73b4e289b..000000000 --- a/scripts/web-env/apply.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { OnePasswordAdapter } from './onepassword.js'; -import { buildWriteOperations, type EnvironmentValues, type WebEnvMode } from './plan.js'; -import { operationId, writeResumeJournal, type ResumeJournal } from './resume.js'; -import type { VercelAdapter } from './vercel.js'; - -export class PartialRemoteFailureError extends Error { - readonly journal: ResumeJournal; - readonly journalPath: string; - - constructor(journal: ResumeJournal, journalPath: string) { - super(`Remote update stopped at ${journal.failed}. Provider output was redacted.`); - this.journal = journal; - this.journalPath = journalPath; - } -} - -export async function applyRemoteChanges(options: { - repoRoot: string; - mode: WebEnvMode; - variableName: string; - sensitive: boolean; - values: EnvironmentValues; - vercel: Pick; - onePassword: Pick; - now?: () => Date; -}): Promise { - const now = options.now ?? (() => new Date()); - const operations = buildWriteOperations(options.sensitive); - const completed: string[] = []; - - for (let index = 0; index < operations.length; index += 1) { - const operation = operations[index]; - if (!operation) continue; - try { - await options.vercel.writeVariable({ - mode: options.mode, - project: operation.project, - environment: operation.environment, - key: options.variableName, - value: options.values[operation.environment], - sensitive: operation.sensitive, - expectedType: operation.expectedType, - }); - completed.push(operationId(operation)); - } catch { - const journal: ResumeJournal = { - version: 1, - variableName: options.variableName, - sensitive: options.sensitive, - createdAt: now().toISOString(), - completed, - failed: operationId(operation), - pending: operations.slice(index + 1).map(operationId), - onePassword: options.sensitive ? 'pending' : 'skipped', - }; - const journalPath = await writeResumeJournal(options.repoRoot, journal); - throw new PartialRemoteFailureError(journal, journalPath); - } - } - - if (!options.sensitive) return; - try { - await options.onePassword.writeProductionValue( - options.mode, - options.variableName, - options.values.production - ); - } catch { - const journal: ResumeJournal = { - version: 1, - variableName: options.variableName, - sensitive: true, - createdAt: now().toISOString(), - completed, - failed: '1Password', - pending: [], - onePassword: 'failed', - }; - const journalPath = await writeResumeJournal(options.repoRoot, journal); - throw new PartialRemoteFailureError(journal, journalPath); - } -} diff --git a/scripts/web-env/backfill-report.ts b/scripts/web-env/backfill-report.ts deleted file mode 100644 index 414195cba..000000000 --- a/scripts/web-env/backfill-report.ts +++ /dev/null @@ -1,38 +0,0 @@ -export type BackfillReport = { - migrated: string[]; - alreadySensitive: string[]; - productionMismatches: string[]; - stagingUnresolved: string[]; - skipped: string[]; - failed: string[]; -}; - -export function createBackfillReport(): BackfillReport { - return { - migrated: [], - alreadySensitive: [], - productionMismatches: [], - stagingUnresolved: [], - skipped: [], - failed: [], - }; -} - -export function formatBackfillReport(report: BackfillReport, timestamp: string): string { - const sections: [string, string[]][] = [ - ['Migrated to 1Password and converted to sensitive', report.migrated], - ['Already sensitive and missing from 1Password', report.alreadySensitive], - ['Unresolved cross-project production mismatches', report.productionMismatches], - ['Unresolved staging mismatches or inaccessible state', report.stagingUnresolved], - ['Operator-skipped non-secrets', report.skipped], - ['Failed or partially converted variables', report.failed], - ]; - const lines = [`Web environment backfill report - ${timestamp}`]; - for (const [heading, variables] of sections) { - lines.push('', heading); - lines.push( - ...(variables.length === 0 ? ['- None'] : variables.sort().map(name => `- ${name}`)) - ); - } - return lines.join('\n'); -} diff --git a/scripts/web-env/backfill.test.ts b/scripts/web-env/backfill.test.ts deleted file mode 100644 index c24d78c5d..000000000 --- a/scripts/web-env/backfill.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { createBackfillReport, formatBackfillReport } from './backfill-report.js'; - -void test('backfill report is copyable and contains statuses without values', () => { - const report = createBackfillReport(); - report.migrated.push('POSTGRES_URL'); - report.alreadySensitive.push('NEXTAUTH_SECRET'); - report.productionMismatches.push('MISMATCHED_TOKEN'); - report.stagingUnresolved.push('STAGING_TOKEN'); - report.skipped.push('PUBLIC_ID'); - report.failed.push('FAILED_TOKEN'); - - const output = formatBackfillReport(report, '2026-06-16T12:00:00.000Z'); - assert.match(output, /POSTGRES_URL/); - assert.match(output, /NEXTAUTH_SECRET/); - assert.match(output, /MISMATCHED_TOKEN/); - assert.match(output, /STAGING_TOKEN/); - assert.match(output, /PUBLIC_ID/); - assert.match(output, /FAILED_TOKEN/); - assert.equal(output.includes('production-secret-value'), false); -}); diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts index e212d6859..30e488011 100644 --- a/scripts/web-env/backfill.ts +++ b/scripts/web-env/backfill.ts @@ -1,199 +1,90 @@ -import { chmod, mkdtemp, rm } from 'node:fs/promises'; +import { mkdtempSync, rmSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; -import { createBackfillReport, formatBackfillReport } from './backfill-report.js'; -import { executeCommand } from './command.js'; -import { OnePasswordAdapter } from './onepassword.js'; -import { createTerminalPrompts } from './prompts.js'; -import { WEB_ENV_PROJECTS, type VariableMetadata } from './plan.js'; -import { VercelAdapter } from './vercel.js'; - -function byKey(variables: VariableMetadata[]): Map { - return new Map(variables.map(variable => [variable.key, variable])); -} +import { + PROJECTS, + confirm, + listVariables, + pullValue, + resolveVault, + resolveVercelContexts, + setVariable, + setVaultValue, +} from './shared.js'; async function main(): Promise { - const confirmed = await createTerminalPrompts().confirm( - 'This temporary migration changes production and staging Vercel metadata. Continue?' - ); - if (!confirmed) { + if ( + !(await confirm('Backfill readable Production secrets into 1Password and mark them sensitive?')) + ) { console.log('Cancelled.'); return; } - const prompts = createTerminalPrompts(); - const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'kilo-web-env-backfill-')); - await chmod(tempRoot, 0o700); - const vercel = new VercelAdapter(executeCommand, tempRoot); - const onePassword = new OnePasswordAdapter(executeCommand); - const report = createBackfillReport(); + const tempDirectory = mkdtempSync(path.join(os.tmpdir(), 'kilo-web-env-backfill-')); + const migrated: string[] = []; + const unresolved: string[] = []; + const skipped: string[] = []; try { - await vercel.initialize(); - await onePassword.initialize(); - - const appProduction = byKey(await vercel.listVariables('kilocode-app', 'production')); - const globalProduction = byKey(await vercel.listVariables('kilocode-global-app', 'production')); - const names = [...new Set([...appProduction.keys(), ...globalProduction.keys()])].sort(); + const contexts = resolveVercelContexts(tempDirectory); + const vaultId = resolveVault(); + const production = contexts.map(context => listVariables(context, 'production')); + const names = [...new Set(production.flatMap(variables => [...variables.keys()]))].sort(); - for (const variableName of names) { - const appMetadata = appProduction.get(variableName); - const globalMetadata = globalProduction.get(variableName); - if (appMetadata?.type === 'system' || globalMetadata?.type === 'system') continue; - if (!appMetadata || !globalMetadata) { - report.productionMismatches.push(variableName); + for (const name of names) { + const types = production.map(variables => variables.get(name)); + if (types.includes('system')) continue; + if (types.some(type => !type) || types.includes('sensitive')) { + unresolved.push(`${name} (missing or already sensitive)`); continue; } - if (appMetadata.type === 'sensitive' && globalMetadata.type === 'sensitive') { - report.alreadySensitive.push(variableName); + if (!(await confirm(`Treat ${name} as a secret?`))) { + skipped.push(name); continue; } - if (appMetadata.type === 'sensitive' || globalMetadata.type === 'sensitive') { - report.productionMismatches.push(variableName); + + const productionValues = contexts.map(context => pullValue(context, 'production', name)); + if (!productionValues[0] || productionValues.some(value => value !== productionValues[0])) { + unresolved.push(`${name} (Production values differ)`); continue; } - let mutationStarted = false; - let activeOperation = 'read-only discovery'; - const completedOperations: string[] = []; - let plannedOperations: string[] = []; - try { - const appProductionValue = await vercel.pullReadableValue( - 'kilocode-app', - 'production', - variableName - ); - const globalProductionValue = await vercel.pullReadableValue( - 'kilocode-global-app', - 'production', - variableName - ); - if ( - appProductionValue === undefined || - globalProductionValue === undefined || - appProductionValue !== globalProductionValue - ) { - report.productionMismatches.push(variableName); - continue; - } - - const isSecret = await prompts.confirm(`Store ${variableName} as a production secret?`); - if (!isSecret) { - report.skipped.push(variableName); + const stagingTypes = contexts.map(context => listVariables(context, 'staging').get(name)); + let stagingValue: string | undefined; + if (stagingTypes.every(type => type === 'sensitive')) { + stagingValue = undefined; + } else { + const stagingValues = contexts.map(context => pullValue(context, 'staging', name)); + if (!stagingValues[0] || stagingValues.some(value => value !== stagingValues[0])) { + unresolved.push(`${name} (Staging values differ or are unavailable)`); continue; } + stagingValue = stagingValues[0]; + } - const appStaging = await vercel.getVariable('kilocode-app', 'staging', variableName); - const globalStaging = await vercel.getVariable( - 'kilocode-global-app', - 'staging', - variableName - ); - let stagingValue: string | undefined; - const stagingAlreadySensitive = - appStaging?.type === 'sensitive' && globalStaging?.type === 'sensitive'; - if (!stagingAlreadySensitive) { - if ( - !appStaging || - !globalStaging || - appStaging.type === 'sensitive' || - globalStaging.type === 'sensitive' - ) { - report.stagingUnresolved.push(variableName); - continue; - } - const appStagingValue = await vercel.pullReadableValue( - 'kilocode-app', - 'staging', - variableName - ); - const globalStagingValue = await vercel.pullReadableValue( - 'kilocode-global-app', - 'staging', - variableName - ); - if ( - appStagingValue === undefined || - globalStagingValue === undefined || - appStagingValue !== globalStagingValue - ) { - report.stagingUnresolved.push(variableName); - continue; - } - stagingValue = appStagingValue; - } - - if (await onePassword.findItem(variableName)) { - report.failed.push(`${variableName} (1Password item already exists)`); - continue; - } - - plannedOperations = [ - '1Password', - ...WEB_ENV_PROJECTS.map(project => `${project}/production`), - ...(stagingValue === undefined - ? [] - : WEB_ENV_PROJECTS.map(project => `${project}/staging`)), - ]; - activeOperation = '1Password'; - mutationStarted = true; - await onePassword.writeProductionValue('add', variableName, appProductionValue); - completedOperations.push(activeOperation); - - for (const project of WEB_ENV_PROJECTS) { - activeOperation = `${project}/production`; - await vercel.writeVariable({ - mode: 'resume', - project, - environment: 'production', - key: variableName, - value: appProductionValue, - sensitive: true, - expectedType: 'sensitive', - }); - completedOperations.push(activeOperation); - } - if (stagingValue !== undefined) { - for (const project of WEB_ENV_PROJECTS) { - activeOperation = `${project}/staging`; - await vercel.writeVariable({ - mode: 'resume', - project, - environment: 'staging', - key: variableName, - value: stagingValue, - sensitive: true, - expectedType: 'sensitive', - }); - completedOperations.push(activeOperation); - } - } - report.migrated.push(variableName); - } catch { - if (!mutationStarted) { - report.failed.push(variableName); - continue; - } - const pending = plannedOperations.filter( - operation => operation !== activeOperation && !completedOperations.includes(operation) - ); - report.failed.push( - `${variableName} (completed: ${completedOperations.join(', ') || 'none'}; failed: ${activeOperation}; pending: ${pending.join(', ') || 'none'})` - ); - throw new Error( - `Backfill stopped after a partial mutation of ${variableName}. Use the value-free report to reconcile it before retrying.` - ); + console.log(`Migrating ${name}...`); + setVaultValue(vaultId, name, productionValues[0]); + for (const context of contexts) { + setVariable(context, 'production', name, productionValues[0], true); + } + if (stagingValue) { + for (const context of contexts) setVariable(context, 'staging', name, stagingValue, true); } + migrated.push(name); } } finally { - await rm(tempRoot, { recursive: true, force: true }); - console.log(`\n${formatBackfillReport(report, new Date().toISOString())}`); + rmSync(tempDirectory, { recursive: true, force: true }); + console.log('\nMigrated:'); + console.log(migrated.length ? migrated.map(name => `- ${name}`).join('\n') : '- None'); + console.log('\nUnresolved:'); + console.log(unresolved.length ? unresolved.map(name => `- ${name}`).join('\n') : '- None'); + console.log('\nSkipped:'); + console.log(skipped.length ? skipped.map(name => `- ${name}`).join('\n') : '- None'); + console.log(`\nProjects checked: ${PROJECTS.join(', ')}`); } } main().catch(error => { - console.error( - error instanceof Error ? error.message : 'Backfill failed. Provider output was redacted.' - ); + console.error(error instanceof Error ? error.message : 'Backfill failed.'); process.exitCode = 1; }); diff --git a/scripts/web-env/command.ts b/scripts/web-env/command.ts deleted file mode 100644 index 868178cf6..000000000 --- a/scripts/web-env/command.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { spawn } from 'node:child_process'; - -export type CommandRequest = { - command: string; - args: string[]; - cwd?: string; - env?: NodeJS.ProcessEnv; - stdin?: string; - timeoutMs?: number; -}; - -export type CommandResult = { - status: number; - stdout: string; - stderr: string; -}; - -export type CommandExecutor = (request: CommandRequest) => Promise; - -export const executeCommand: CommandExecutor = request => - new Promise((resolve, reject) => { - const child = spawn(request.command, request.args, { - cwd: request.cwd, - env: request.env, - stdio: ['pipe', 'pipe', 'pipe'], - shell: false, - }); - - let stdout = ''; - let stderr = ''; - let timedOut = false; - const timeout = request.timeoutMs - ? setTimeout(() => { - timedOut = true; - child.kill('SIGTERM'); - }, request.timeoutMs) - : undefined; - - child.stdout.setEncoding('utf8'); - child.stderr.setEncoding('utf8'); - child.stdout.on('data', chunk => { - stdout += chunk; - }); - child.stderr.on('data', chunk => { - stderr += chunk; - }); - child.on('error', error => { - if (timeout) clearTimeout(timeout); - reject(error); - }); - child.on('close', code => { - if (timeout) clearTimeout(timeout); - resolve({ - status: timedOut ? 124 : (code ?? 1), - stdout, - stderr, - }); - }); - - if (request.stdin !== undefined) { - child.stdin.end(request.stdin); - } else { - child.stdin.end(); - } - }); - -export function requireSuccess(result: CommandResult, operation: string): string { - if (result.status !== 0) { - throw new Error(`${operation} failed (exit ${result.status}). Provider output was redacted.`); - } - return result.stdout; -} diff --git a/scripts/web-env/dotenv-files.test.ts b/scripts/web-env/dotenv-files.test.ts deleted file mode 100644 index 2751640f2..000000000 --- a/scripts/web-env/dotenv-files.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; -import os from 'node:os'; -import path from 'node:path'; -import test from 'node:test'; -import type { CommandExecutor } from './command.js'; -import { - applyDotenvPatches, - assertNoEnvironmentValuesInTrackedFiles, - createDotenvPatch, - discoverTrackedDotenvFiles, - patchDotenvContent, - renderDotenvPatchPreview, - restoreDotenvPatches, -} from './dotenv-files.js'; - -const fakeGit: CommandExecutor = async () => ({ - status: 0, - stdout: [ - '.env.local.example', - '.envrc', - 'apps/web/.env', - 'apps/web/.env.development.local.example', - 'apps/web/.env.test', - 'apps/web/.env.local', - 'apps/mobile/.env', - '', - ].join('\0'), - stderr: '', -}); - -void test('discovers only tracked root and apps/web dotenv defaults', async () => { - assert.deepEqual(await discoverTrackedDotenvFiles('/repo', fakeGit), [ - '.env.local.example', - 'apps/web/.env', - 'apps/web/.env.development.local.example', - 'apps/web/.env.test', - ]); -}); - -void test('patches one assignment without reformatting surrounding content', () => { - const before = "# auth\nTOKEN = 'old value'\nUNCHANGED=x\n"; - const result = patchDotenvContent(before, 'TOKEN', 'safe default'); - assert.equal(result.content, "# auth\nTOKEN = 'safe default'\nUNCHANGED=x\n"); - assert.equal(result.existed, true); -}); - -void test('appends a missing assignment and rejects duplicate keys', () => { - assert.equal( - patchDotenvContent('A=1', 'TOKEN', 'invalid-token').content, - 'A=1\nTOKEN=invalid-token\n' - ); - assert.throws( - () => patchDotenvContent('TOKEN=one\nTOKEN=two\n', 'TOKEN', 'safe'), - /more than once/ - ); -}); - -void test('restores exact pre-command content around existing edits', async () => { - const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-dotenv-test-')); - try { - await mkdir(path.join(root, 'apps', 'web'), { recursive: true }); - const file = path.join(root, 'apps', 'web', '.env.test'); - const before = '# user edit\nTOKEN=old\n'; - await writeFile(file, before); - const patch = await createDotenvPatch(root, 'apps/web/.env.test', 'TOKEN', 'invalid-token'); - await applyDotenvPatches([patch]); - assert.equal(await readFile(file, 'utf8'), '# user edit\nTOKEN=invalid-token\n'); - await restoreDotenvPatches([patch]); - assert.equal(await readFile(file, 'utf8'), before); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - -void test('ignores assignment-like lines inside unrelated multiline values', () => { - const content = 'OTHER="begin\nTOKEN=embedded\nend"\nTOKEN=real\n'; - assert.equal( - patchDotenvContent(content, 'TOKEN', 'safe').content, - 'OTHER="begin\nTOKEN=embedded\nend"\nTOKEN=safe\n' - ); -}); - -void test('preserves inline comments and replaces complete multiline values', () => { - assert.equal( - patchDotenvContent('TOKEN=old-value # setup\n', 'TOKEN', 'safe').content, - 'TOKEN=safe # setup\n' - ); - assert.equal( - patchDotenvContent('TOKEN="old\nmultiline" # setup\nNEXT=x\n', 'TOKEN', 'safe default').content, - 'TOKEN="safe default" # setup\nNEXT=x\n' - ); -}); - -void test('rejects raw or escaped real values in patched and skipped tracked files', async () => { - const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-secret-guard-test-')); - try { - await mkdir(path.join(root, 'apps', 'web'), { recursive: true }); - await writeFile(path.join(root, 'apps', 'web', '.env.test'), 'OTHER="line-one\\nline-two"\n'); - await assert.rejects( - assertNoEnvironmentValuesInTrackedFiles(root, ['apps/web/.env.test'], [], { - development: 'development-real-value', - staging: 'line-one\nline-two', - production: 'production-real-value', - }), - /real environment value/ - ); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - -void test('renders only invocation-owned dotenv lines and redacts old values', () => { - const preview = renderDotenvPatchPreview( - [ - { - relativePath: 'apps/web/.env.test', - absolutePath: '/repo/apps/web/.env.test', - before: 'UNRELATED=secret\nTOKEN=old-secret\n', - after: 'UNRELATED=secret\nTOKEN=invalid-token\n', - existed: true, - defaultValue: 'invalid-token', - }, - ], - 'TOKEN' - ); - assert.match(preview, /TOKEN=/); - assert.match(preview, /TOKEN=invalid-token/); - assert.equal(preview.includes('UNRELATED'), false); - assert.equal(preview.includes('old-secret'), false); -}); diff --git a/scripts/web-env/dotenv-files.ts b/scripts/web-env/dotenv-files.ts deleted file mode 100644 index 01f62517b..000000000 --- a/scripts/web-env/dotenv-files.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { readFile, rename, rm, stat, writeFile } from 'node:fs/promises'; -import path from 'node:path'; -import type { CommandExecutor } from './command.js'; -import { requireSuccess } from './command.js'; -import type { EnvironmentValues } from './plan.js'; - -export type DotenvPatch = { - relativePath: string; - absolutePath: string; - before: string; - after: string; - existed: boolean; - defaultValue: string; -}; - -type ValueSpan = { - start: number; - end: number; - rawValue: string; -}; - -function isManagedDotenvPath(relativePath: string): boolean { - const normalized = relativePath.split(path.sep).join('/'); - const inScope = !normalized.includes('/') || normalized.startsWith('apps/web/'); - if (!inScope) return false; - - const basename = path.posix.basename(normalized); - if (!basename.startsWith('.env') || basename === '.envrc') return false; - if (basename.includes('.local') && !basename.includes('.example')) return false; - return true; -} - -export async function discoverTrackedDotenvFiles( - repoRoot: string, - execute: CommandExecutor -): Promise { - const result = await execute({ - command: 'git', - args: ['ls-files', '-z', '--', '.env*', 'apps/web/.env*'], - cwd: repoRoot, - }); - const stdout = requireSuccess(result, 'Tracked dotenv discovery'); - return stdout.split('\0').filter(Boolean).filter(isManagedDotenvPath).sort(); -} - -function findClosingQuote(value: string, quote: '"' | "'", start: number): number | undefined { - let escaped = false; - for (let index = start; index < value.length; index += 1) { - const character = value[index]; - if (quote === '"' && character === '\\' && !escaped) { - escaped = true; - continue; - } - if (character === quote && !escaped) return index; - escaped = false; - } - return undefined; -} - -function assignmentValueStarts(content: string, key: string): number[] { - const starts: number[] = []; - const assignmentPattern = new RegExp( - `^([ \\t]*(?:export[ \\t]+)?([A-Za-z_][A-Za-z0-9_]*)[ \\t]*=[ \\t]*)(.*)$` - ); - let openQuote: '"' | "'" | undefined; - let offset = 0; - - while (offset <= content.length) { - const newline = content.indexOf('\n', offset); - const lineEnd = newline === -1 ? content.length : newline; - const line = content.slice(offset, lineEnd); - - if (openQuote) { - if (findClosingQuote(line, openQuote, 0) !== undefined) openQuote = undefined; - } else { - const assignment = assignmentPattern.exec(line); - const prefix = assignment?.[1]; - const assignmentKey = assignment?.[2]; - const rawValue = assignment?.[3]; - if (prefix !== undefined && assignmentKey !== undefined && rawValue !== undefined) { - if (assignmentKey === key) starts.push(offset + prefix.length); - const quote = rawValue[0]; - if ( - (quote === '"' || quote === "'") && - findClosingQuote(rawValue, quote, 1) === undefined - ) { - openQuote = quote; - } - } - } - - if (newline === -1) break; - offset = newline + 1; - } - return starts; -} - -export function countKeyAssignments(content: string, key: string): number { - return assignmentValueStarts(content, key).length; -} - -function findValueSpan(content: string, key: string): ValueSpan { - const starts = assignmentValueStarts(content, key); - const start = starts[0]; - if (start === undefined) throw new Error(`Could not parse the existing ${key} assignment.`); - const quote = content[start]; - - if (quote === '"' || quote === "'") { - let escaped = false; - for (let index = start + 1; index < content.length; index += 1) { - const character = content[index]; - if (quote === '"' && character === '\\' && !escaped) { - escaped = true; - continue; - } - if (character === quote && !escaped) { - return { start, end: index + 1, rawValue: content.slice(start, index + 1) }; - } - escaped = false; - } - throw new Error(`Could not find the closing quote for ${key}.`); - } - - let lineEnd = content.indexOf('\n', start); - if (lineEnd === -1) lineEnd = content.length; - let end = lineEnd; - for (let index = start; index < lineEnd; index += 1) { - if (content[index] === '#' && (index === start || /\s/.test(content[index - 1] ?? ''))) { - end = index; - break; - } - } - while (end > start && /[ \t]/.test(content[end - 1] ?? '')) end -= 1; - return { start, end, rawValue: content.slice(start, end) }; -} - -function preferredQuote(rawValue: string): 'single' | 'double' | undefined { - if (rawValue.startsWith("'") && rawValue.endsWith("'")) return 'single'; - if (rawValue.startsWith('"') && rawValue.endsWith('"')) return 'double'; - return undefined; -} - -export function formatDotenvValue( - value: string, - quote: 'single' | 'double' | undefined = undefined -): string { - if (quote === 'single' && !value.includes("'") && !value.includes('\n')) { - return `'${value}'`; - } - const requiresQuotes = - quote === 'double' || - value.includes('\n') || - value.includes('\r') || - value.includes(' ') || - value.includes('#') || - value.includes('"') || - value.includes("'"); - if (!requiresQuotes) return value; - return `"${value - .replace(/\\/g, '\\\\') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/"/g, '\\"')}"`; -} - -export function patchDotenvContent( - content: string, - key: string, - defaultValue: string -): { content: string; existed: boolean } { - const count = countKeyAssignments(content, key); - if (count > 1) { - throw new Error(`Cannot patch ${key}: it is declared more than once in the same file.`); - } - - if (count === 1) { - const span = findValueSpan(content, key); - const replacement = formatDotenvValue(defaultValue, preferredQuote(span.rawValue)); - return { - content: `${content.slice(0, span.start)}${replacement}${content.slice(span.end)}`, - existed: true, - }; - } - - const separator = content.length === 0 || content.endsWith('\n') ? '' : '\n'; - return { - content: `${content}${separator}${key}=${formatDotenvValue(defaultValue)}\n`, - existed: false, - }; -} - -export async function createDotenvPatch( - repoRoot: string, - relativePath: string, - key: string, - defaultValue: string -): Promise { - const absolutePath = path.join(repoRoot, relativePath); - const before = await readFile(absolutePath, 'utf8'); - const patched = patchDotenvContent(before, key, defaultValue); - return { - relativePath, - absolutePath, - before, - after: patched.content, - existed: patched.existed, - defaultValue, - }; -} - -function secretRepresentations(value: string): string[] { - const representations = new Set([value, formatDotenvValue(value), JSON.stringify(value)]); - if (!value.includes("'") && !value.includes('\n')) representations.add(`'${value}'`); - return [...representations].filter(Boolean); -} - -export async function assertNoEnvironmentValuesInTrackedFiles( - repoRoot: string, - relativePaths: string[], - patches: DotenvPatch[], - values: EnvironmentValues -): Promise { - const patchesByPath = new Map(patches.map(patch => [patch.relativePath, patch])); - for (const relativePath of relativePaths) { - const patch = patchesByPath.get(relativePath); - const content = patch?.after ?? (await readFile(path.join(repoRoot, relativePath), 'utf8')); - for (const value of Object.values(values)) { - if (secretRepresentations(value).some(representation => content.includes(representation))) { - throw new Error( - `Refusing to continue: a real environment value appears in tracked file ${relativePath}.` - ); - } - } - } -} - -export function renderDotenvPatchPreview(patches: DotenvPatch[], key: string): string { - const lines: string[] = []; - for (const patch of patches) { - lines.push(`diff -- ${patch.relativePath}`); - lines.push(`@@ ${key} @@`); - if (patch.existed) lines.push(`-${key}=`); - lines.push(`+${key}=${formatDotenvValue(patch.defaultValue)}`); - } - return lines.join('\n'); -} - -async function atomicWrite(filePath: string, content: string): Promise { - const fileStat = await stat(filePath); - const temporaryPath = `${filePath}.web-env-${process.pid}-${Math.random().toString(16).slice(2)}`; - try { - await writeFile(temporaryPath, content, { mode: fileStat.mode }); - await rename(temporaryPath, filePath); - } finally { - await rm(temporaryPath, { force: true }); - } -} - -export async function applyDotenvPatches(patches: DotenvPatch[]): Promise { - const applied: DotenvPatch[] = []; - try { - for (const patch of patches) { - await atomicWrite(patch.absolutePath, patch.after); - applied.push(patch); - } - } catch (error) { - await restoreDotenvPatches(applied); - throw error; - } -} - -export async function restoreDotenvPatches(patches: DotenvPatch[]): Promise { - for (const patch of patches) { - await atomicWrite(patch.absolutePath, patch.before); - } -} - -export async function verifyDotenvPatches(patches: DotenvPatch[], key: string): Promise { - for (const patch of patches) { - const content = await readFile(patch.absolutePath, 'utf8'); - if (countKeyAssignments(content, key) !== 1) { - throw new Error(`Tracked default verification failed for ${patch.relativePath}.`); - } - const expected = patchDotenvContent(patch.before, key, patch.defaultValue).content; - if (content !== expected) { - throw new Error(`Tracked default verification failed for ${patch.relativePath}.`); - } - } -} diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index ed1d80ffc..d31b23d84 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -1,314 +1,172 @@ -import { existsSync, readFileSync } from 'node:fs'; -import { chmod, mkdtemp, readFile, rm } from 'node:fs/promises'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; -import { applyRemoteChanges, PartialRemoteFailureError } from './apply.js'; -import { executeCommand, requireSuccess } from './command.js'; import { - applyDotenvPatches, - assertNoEnvironmentValuesInTrackedFiles, - countKeyAssignments, - createDotenvPatch, - discoverTrackedDotenvFiles, - renderDotenvPatchPreview, - restoreDotenvPatches, - verifyDotenvPatches, - type DotenvPatch, -} from './dotenv-files.js'; -import { OnePasswordAdapter } from './onepassword.js'; -import { - assertNonEmptyValues, - buildWriteOperations, - validateTargetPreconditions, - validateVariableName, - WEB_ENVIRONMENTS, - WEB_ENV_PROJECTS, - type EnvironmentValues, - type TargetState, - type WebEnvMode, -} from './plan.js'; -import { createTerminalPrompts, UserAbortError, type PromptDriver } from './prompts.js'; -import { readResumeJournal, type ResumeJournal } from './resume.js'; -import { VercelAdapter } from './vercel.js'; - -type CliOptions = { - mode: WebEnvMode; - variableName: string; + ENVIRONMENTS, + PROJECTS, + confirm, + findRepoRoot, + question, + readSecret, + resolveVault, + resolveVercelContexts, + setEnvDefault, + setVariable, + setVaultValue, + trackedEnvFiles, + type Environment, + type Values, +} from './shared.js'; + +type Options = { + name: string; sensitive: boolean; dryRun: boolean; - resumePath?: string; + valueFiles: Partial>; }; -function findRepoRoot(): string { - let directory = process.cwd(); - while (true) { - const packagePath = path.join(directory, 'package.json'); - if (existsSync(packagePath)) { - try { - const parsed: unknown = JSON.parse(readFileSync(packagePath, 'utf8')); - if ( - typeof parsed === 'object' && - parsed !== null && - 'name' in parsed && - parsed.name === 'kilocode-monorepo' - ) { - return directory; - } - } catch { - // Keep walking until the repository root is found. - } - } - const parent = path.dirname(directory); - if (parent === directory) throw new Error('Could not find the kilocode-monorepo root.'); - directory = parent; - } -} - -const REPO_ROOT = findRepoRoot(); - -function usage(): string { - return [ - 'Usage:', - ' pnpm web:env add VARIABLE_NAME [--no-sensitive] [--dry-run]', - ' pnpm web:env update VARIABLE_NAME [--no-sensitive] [--dry-run]', - ' pnpm web:env resume JOURNAL_PATH [--dry-run]', - ].join('\n'); -} - -async function parseArgs(args: string[]): Promise { - const mode = args[0]; - if (mode !== 'add' && mode !== 'update' && mode !== 'resume') { - throw new Error(usage()); - } - - const positional = args.filter(argument => !argument.startsWith('--')); - const flags = args.filter(argument => argument.startsWith('--')); - const unknownFlags = flags.filter(flag => flag !== '--no-sensitive' && flag !== '--dry-run'); - if (unknownFlags.length > 0) throw new Error(`Unknown option: ${unknownFlags[0]}\n\n${usage()}`); - if (positional.length !== 2) throw new Error(usage()); - - if (mode === 'resume') { - if (flags.includes('--no-sensitive')) { - throw new Error('Resume sensitivity is read from the journal; omit --no-sensitive.'); - } - const resumePath = path.resolve(REPO_ROOT, positional[1] ?? ''); - const journal = await readResumeJournal(resumePath); - return { - mode, - variableName: journal.variableName, - sensitive: journal.sensitive, - dryRun: flags.includes('--dry-run'), - resumePath, - }; - } - - return { - mode, - variableName: positional[1] ?? '', - sensitive: !flags.includes('--no-sensitive'), - dryRun: flags.includes('--dry-run'), - }; -} - -function defaultRecommendation(relativePath: string, variableName: string): string { - if (relativePath === 'apps/web/.env') return ''; - return `invalid-${variableName.toLowerCase().replaceAll('_', '-')}`; +function usage(): never { + throw new Error( + [ + 'Usage: pnpm web:env set VARIABLE [--no-sensitive] [--dry-run]', + ' [--development-file PATH] [--staging-file PATH] [--production-file PATH]', + ].join('\n') + ); } -async function collectEnvironmentValues(prompts: PromptDriver): Promise { - const values: Partial = {}; - for (const environment of WEB_ENVIRONMENTS) { - const modeAnswer = await prompts.askText( - `Input mode for ${environment} (single-line/multiline)`, - 'single-line' - ); - if (modeAnswer !== 'single-line' && modeAnswer !== 'multiline') { - throw new Error('Input mode must be single-line or multiline.'); +function parseOptions(args: string[]): Options { + if (args[0] !== 'set' || !args[1]) usage(); + const name = args[1]; + const valueFiles: Partial> = {}; + let sensitive = true; + let dryRun = false; + + for (let index = 2; index < args.length; index += 1) { + const argument = args[index]; + if (argument === '--no-sensitive') sensitive = false; + else if (argument === '--dry-run') dryRun = true; + else { + const match = argument?.match(/^--(development|staging|production)-file(?:=(.*))?$/); + if (!match) usage(); + const environment = match[1] as Environment; + const nextArgument = args[index + 1]; + const file = match[2] || nextArgument; + if (!file) usage(); + if (!match[2]) index += 1; + valueFiles[environment] = file; } - values[environment] = await prompts.askSecret(`${environment} value`, modeAnswer); } - const development = values.development; - const staging = values.staging; - const production = values.production; - if (development === undefined || staging === undefined || production === undefined) { - throw new Error('All environment values are required.'); + if (!/^[A-Z_][A-Z0-9_]*$/.test(name)) { + throw new Error('Variable names must contain only uppercase letters, digits, and underscores.'); } - const complete = { development, staging, production } satisfies EnvironmentValues; - assertNonEmptyValues(complete); - return complete; -} - -async function collectDotenvPatches( - prompts: PromptDriver, - variableName: string, - values: EnvironmentValues -): Promise<{ files: string[]; patches: DotenvPatch[] }> { - const files = await discoverTrackedDotenvFiles(REPO_ROOT, executeCommand); - const patches: DotenvPatch[] = []; - for (const relativePath of files) { - const content = await readFile(path.join(REPO_ROOT, relativePath), 'utf8'); - const count = countKeyAssignments(content, variableName); - if (count > 1) { - throw new Error(`${relativePath} declares ${variableName} more than once.`); - } - const status = count === 1 ? 'currently declared' : 'not declared'; - const decision = await prompts.askText( - `${relativePath} (${status}): set a safe default or skip? (set/skip)`, - 'set' - ); - if (decision === 'skip') continue; - if (decision !== 'set') throw new Error('Tracked dotenv decisions must be set or skip.'); - - const recommendation = defaultRecommendation(relativePath, variableName); - const defaultValue = await prompts.askText( - `Safe non-secret default for ${relativePath}`, - recommendation - ); - patches.push(await createDotenvPatch(REPO_ROOT, relativePath, variableName, defaultValue)); + if (sensitive && name.startsWith('NEXT_PUBLIC_')) { + throw new Error('NEXT_PUBLIC_* values are browser-visible; pass --no-sensitive.'); } - await assertNoEnvironmentValuesInTrackedFiles(REPO_ROOT, files, patches, values); - return { files, patches }; + return { name, sensitive, dryRun, valueFiles }; } -function showTrackedDiff(patches: DotenvPatch[], variableName: string): void { - if (patches.length === 0) { - console.log('\nTracked defaults: all files explicitly skipped.'); - return; +async function collectValues(options: Options): Promise { + const values: Partial = {}; + for (const environment of ENVIRONMENTS) { + const file = options.valueFiles[environment]; + const value = file + ? readFileSync(path.resolve(file), 'utf8') + : await readSecret(`${environment} value: `); + if (!value) throw new Error(`${environment} value cannot be empty.`); + values[environment] = value; } - console.log('\nTracked default diff (invocation changes only):'); - console.log(renderDotenvPatchPreview(patches, variableName)); + return values as Values; } -async function runFastChecks(): Promise { - const result = await executeCommand({ - command: 'pnpm', - args: ['run', 'test:web-env'], - cwd: REPO_ROOT, - timeoutMs: 120_000, - }); - requireSuccess(result, 'Web environment script checks'); - console.log('Fast checks passed.'); -} +async function collectDefaults( + repoRoot: string, + name: string, + values: Values +): Promise> { + const defaults = new Map(); + for (const relativeFile of trackedEnvFiles(repoRoot)) { + const decision = ( + await question(`${relativeFile}: set a safe default or skip? [set/skip] `) + ).trim(); + if (decision === 'skip') continue; + if (decision && decision !== 'set') throw new Error('Answer set or skip.'); -function printPlan(variableName: string, sensitive: boolean, mode: WebEnvMode): void { - console.log('\nRedacted operation plan'); - console.log(`Variable: ${variableName}`); - console.log(`Mode: ${mode}`); - console.log(`Classification: ${sensitive ? 'sensitive' : 'non-sensitive'}`); - for (const operation of buildWriteOperations(sensitive)) { - console.log(`- ${operation.project}/${operation.environment}: ${operation.expectedType}`); + const suggested = relativeFile === 'apps/web/.env' ? '' : `invalid-${name.toLowerCase()}`; + const answer = await question(`Safe default for ${relativeFile} [${suggested}] `); + const value = answer || suggested; + if (Object.values(values).includes(value)) { + throw new Error(`The default for ${relativeFile} matches a real environment value.`); + } + defaults.set(relativeFile, value); } - console.log(`- 1Password: ${sensitive ? 'write production value' : 'skipped'}`); - console.log('- Deployment: not triggered'); + return defaults; } -function printFailureMatrix(journal: ResumeJournal): void { - console.error('\nPartial operation status (no values):'); - for (const id of journal.completed) console.error(`- completed: ${id}`); - console.error(`- failed: ${journal.failed}`); - for (const id of journal.pending) console.error(`- pending: ${id}`); - console.error(`- 1Password: ${journal.onePassword}`); +function assertSecretsAreNotTracked(repoRoot: string, values: Values): void { + for (const relativeFile of trackedEnvFiles(repoRoot)) { + const content = readFileSync(path.join(repoRoot, relativeFile), 'utf8'); + if (Object.values(values).some(value => content.includes(value))) { + throw new Error(`A real environment value appears in tracked file ${relativeFile}.`); + } + } } async function main(): Promise { - const options = await parseArgs(process.argv.slice(2)); - validateVariableName(options.variableName, options.sensitive); - - const prompts = createTerminalPrompts(); - const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'kilo-web-env-')); - await chmod(tempRoot, 0o700); - const vercel = new VercelAdapter(executeCommand, tempRoot); - const onePassword = new OnePasswordAdapter(executeCommand); - let patches: DotenvPatch[] = []; - let patchesApplied = false; - let remoteStarted = false; + const options = parseOptions(process.argv.slice(2)); + const repoRoot = findRepoRoot(); + const tempDirectory = mkdtempSync(path.join(os.tmpdir(), 'kilo-web-env-')); try { - console.log('Running read-only preflight...'); - await vercel.initialize(!options.sensitive); - if (options.sensitive) await onePassword.initialize(); - - const states: TargetState[] = []; - for (const environment of WEB_ENVIRONMENTS) { - for (const project of WEB_ENV_PROJECTS) { - states.push({ - project, - environment, - variable: await vercel.getVariable(project, environment, options.variableName), - }); - } - } - if (options.mode !== 'resume') validateTargetPreconditions(options.mode, states); - if (options.sensitive) { - const existingItem = await onePassword.validateExistingItem(options.variableName); - if (options.mode === 'add' && existingItem) { - throw new Error(`1Password already contains an item titled ${options.variableName}.`); - } - } - - const values = await collectEnvironmentValues(prompts); - if (options.mode !== 'resume') { - const trackedDefaults = await collectDotenvPatches(prompts, options.variableName, values); - patches = trackedDefaults.patches; - await applyDotenvPatches(patches); - patchesApplied = true; - await verifyDotenvPatches(patches, options.variableName); - showTrackedDiff(patches, options.variableName); - await runFastChecks(); + console.log('Checking Vercel and 1Password access...'); + const contexts = resolveVercelContexts(tempDirectory); + const vaultId = options.sensitive ? resolveVault() : undefined; + const values = await collectValues(options); + const defaults = await collectDefaults(repoRoot, options.name, values); + + console.log('\nPlan'); + for (const environment of ENVIRONMENTS) { + const type = options.sensitive && environment !== 'development' ? 'sensitive' : 'encrypted'; + for (const project of PROJECTS) console.log(`- ${project}/${environment}: ${type}`); } - printPlan(options.variableName, options.sensitive, options.mode); + for (const [file, value] of defaults) + console.log(`- ${file}: ${options.name}=${JSON.stringify(value)}`); + console.log(`- 1Password: ${options.sensitive ? 'update Production copy' : 'skip'}`); + console.log('- Deployments: not triggered'); if (options.dryRun) { - if (patchesApplied) await restoreDotenvPatches(patches); - console.log('\nDry run complete. No local or remote changes were retained.'); + console.log('\nDry run complete; nothing changed.'); return; } - - const confirmed = await prompts.confirm('Apply this plan?'); - if (!confirmed) { - if (patchesApplied) await restoreDotenvPatches(patches); - console.log('Cancelled. Tracked files were restored; no remote changes were made.'); + if (!(await confirm('\nApply these changes?'))) { + console.log('Cancelled; nothing changed.'); return; } - remoteStarted = true; - try { - await applyRemoteChanges({ - repoRoot: REPO_ROOT, - mode: options.mode, - variableName: options.variableName, - sensitive: options.sensitive, - values, - vercel, - onePassword, - }); - } catch (error) { - if (error instanceof PartialRemoteFailureError) { - printFailureMatrix(error.journal); - console.error(`Resume with: pnpm web:env resume ${error.journalPath}`); + for (const [relativeFile, value] of defaults) { + setEnvDefault(path.join(repoRoot, relativeFile), options.name, value); + } + assertSecretsAreNotTracked(repoRoot, values); + + for (const environment of ENVIRONMENTS) { + for (const context of contexts) { + console.log(`Setting ${context.project}/${environment}...`); + setVariable(context, environment, options.name, values[environment], options.sensitive); } - throw error; + } + if (vaultId) { + console.log('Updating 1Password Production copy...'); + setVaultValue(vaultId, options.name, values.production); } - if (options.resumePath) await rm(options.resumePath, { force: true }); - console.log('\nEnvironment variable update completed.'); - console.log('New deployments are required before staging or production uses the new value.'); - } catch (error) { - if (patchesApplied && !remoteStarted) await restoreDotenvPatches(patches); - throw error; + console.log('\nDone. Rerun the same command if a provider failed partway through.'); + console.log('Deploy Staging or Production separately when the new value should take effect.'); } finally { - await rm(tempRoot, { recursive: true, force: true }); + rmSync(tempDirectory, { recursive: true, force: true }); } } main().catch(error => { - if (error instanceof UserAbortError) { - console.error('Cancelled.'); - } else if (error instanceof Error) { - console.error(error.message); - } else { - console.error('Unexpected failure. Provider output was redacted.'); - } + console.error(error instanceof Error ? error.message : 'Environment update failed.'); process.exitCode = 1; }); diff --git a/scripts/web-env/json.ts b/scripts/web-env/json.ts deleted file mode 100644 index 075cdba8d..000000000 --- a/scripts/web-env/json.ts +++ /dev/null @@ -1,43 +0,0 @@ -export function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value); -} - -export function parseJsonObject(json: string, operation: string): Record { - let parsed: unknown; - try { - parsed = JSON.parse(json); - } catch { - throw new Error(`${operation} returned invalid JSON. Provider output was redacted.`); - } - if (!isRecord(parsed)) { - throw new Error(`${operation} returned an unexpected response. Provider output was redacted.`); - } - return parsed; -} - -export function parseJsonRecords(json: string, operation: string): Record[] { - let parsed: unknown; - try { - parsed = JSON.parse(json); - } catch { - throw new Error(`${operation} returned invalid JSON. Provider output was redacted.`); - } - if (!Array.isArray(parsed) || !parsed.every(isRecord)) { - throw new Error(`${operation} returned an unexpected response. Provider output was redacted.`); - } - return parsed; -} - -export function readString(record: Record, key: string): string | undefined { - const value = record[key]; - return typeof value === 'string' ? value : undefined; -} - -export function readRecords( - record: Record, - key: string -): Record[] { - const value = record[key]; - if (!Array.isArray(value)) return []; - return value.filter(isRecord); -} diff --git a/scripts/web-env/onepassword.ts b/scripts/web-env/onepassword.ts deleted file mode 100644 index fb4812f5f..000000000 --- a/scripts/web-env/onepassword.ts +++ /dev/null @@ -1,180 +0,0 @@ -import type { CommandExecutor, CommandResult } from './command.js'; -import { requireSuccess } from './command.js'; -import { isRecord, parseJsonObject, parseJsonRecords, readString } from './json.js'; -import { WEB_ENV_VAULT } from './plan.js'; - -export class OnePasswordAdapter { - readonly #execute: CommandExecutor; - #vaultId = ''; - - constructor(execute: CommandExecutor) { - this.#execute = execute; - } - - async #run(args: string[], stdin?: string): Promise { - return this.#execute({ - command: 'op', - args, - stdin, - timeoutMs: 120_000, - }); - } - - async initialize(): Promise { - requireSuccess(await this.#run(['--version']), '1Password CLI version check'); - requireSuccess( - await this.#run(['whoami', '--format=json']), - '1Password authentication check; run op signin' - ); - const vault = parseJsonObject( - requireSuccess( - await this.#run(['vault', 'get', WEB_ENV_VAULT, '--format=json']), - `Resolve 1Password vault ${WEB_ENV_VAULT}` - ), - `Resolve 1Password vault ${WEB_ENV_VAULT}` - ); - const vaultId = readString(vault, 'id'); - if (!vaultId) throw new Error(`1Password vault ${WEB_ENV_VAULT} did not include an ID.`); - this.#vaultId = vaultId; - await this.listItems(); - } - - async listItems(): Promise<{ id: string; title: string }[]> { - if (!this.#vaultId) throw new Error('1Password vault has not been resolved.'); - const result = await this.#run(['item', 'list', '--vault', this.#vaultId, '--format=json']); - const records = parseJsonRecords( - requireSuccess(result, `List items in ${WEB_ENV_VAULT}`), - `List items in ${WEB_ENV_VAULT}` - ); - const items: { id: string; title: string }[] = []; - for (const record of records) { - const id = readString(record, 'id'); - const title = readString(record, 'title'); - if (id && title) items.push({ id, title }); - } - return items; - } - - async findItem(variableName: string): Promise<{ id: string; title: string } | undefined> { - const matches = (await this.listItems()).filter(item => item.title === variableName); - if (matches.length > 1) { - throw new Error(`Multiple 1Password items are titled ${variableName}.`); - } - return matches[0]; - } - - async #createTemplate(variableName: string, value: string): Promise { - const result = await this.#run(['item', 'template', 'get', 'Password', '--format=json']); - const template = parseJsonObject( - requireSuccess(result, 'Load 1Password Password template'), - 'Load 1Password Password template' - ); - template.title = variableName; - this.#setPasswordField(template, value); - return JSON.stringify(template); - } - - #getPasswordField(item: Record): Record { - const fields = item.fields; - if (!Array.isArray(fields)) { - throw new Error('1Password item did not include fields. Provider output was redacted.'); - } - const passwordFields = fields.filter( - field => isRecord(field) && (field.id === 'password' || field.label === 'password') - ); - if ( - passwordFields.length !== 1 || - !isRecord(passwordFields[0]) || - readString(passwordFields[0], 'type') !== 'CONCEALED' - ) { - throw new Error('1Password item did not include one concealed password field.'); - } - return passwordFields[0]; - } - - #setPasswordField(item: Record, value: string): void { - this.#getPasswordField(item).value = value; - } - - async #readItem(itemId: string, variableName: string): Promise> { - const getResult = await this.#run([ - 'item', - 'get', - itemId, - '--vault', - this.#vaultId, - '--format=json', - ]); - return parseJsonObject( - requireSuccess(getResult, `Read 1Password item ${variableName}`), - `Read 1Password item ${variableName}` - ); - } - - async validateExistingItem( - variableName: string - ): Promise<{ id: string; title: string } | undefined> { - const existing = await this.findItem(variableName); - if (!existing) return undefined; - const item = await this.#readItem(existing.id, variableName); - this.#getPasswordField(item); - return existing; - } - - async writeProductionValue( - mode: 'add' | 'update' | 'resume', - variableName: string, - value: string - ): Promise { - const existing = await this.findItem(variableName); - if (mode === 'add' && existing) { - throw new Error(`1Password already contains an item titled ${variableName}.`); - } - - let itemId: string; - if (!existing) { - const template = await this.#createTemplate(variableName, value); - const result = await this.#run( - ['item', 'create', '--vault', this.#vaultId, '--format=json', '-'], - template - ); - const created = parseJsonObject( - requireSuccess(result, `Create 1Password item ${variableName}`), - `Create 1Password item ${variableName}` - ); - const createdId = readString(created, 'id'); - if (!createdId) throw new Error(`Created 1Password item ${variableName} has no ID.`); - itemId = createdId; - } else { - const item = await this.#readItem(existing.id, variableName); - this.#setPasswordField(item, value); - const editResult = await this.#run( - ['item', 'edit', existing.id, '--vault', this.#vaultId, '--format=json'], - JSON.stringify(item) - ); - requireSuccess(editResult, `Update 1Password item ${variableName}`); - itemId = existing.id; - } - - const verifyResult = await this.#run([ - 'item', - 'get', - itemId, - '--vault', - this.#vaultId, - '--fields', - 'label=password', - '--format=json', - ]); - const passwordField = parseJsonObject( - requireSuccess(verifyResult, `Verify 1Password item ${variableName}`), - `Verify 1Password item ${variableName}` - ); - if ( - readString(passwordField, 'type') !== 'CONCEALED' || - readString(passwordField, 'value') !== value - ) { - throw new Error(`1Password verification failed for ${variableName}.`); - } - } -} diff --git a/scripts/web-env/plan.test.ts b/scripts/web-env/plan.test.ts deleted file mode 100644 index a885696f1..000000000 --- a/scripts/web-env/plan.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { - buildWriteOperations, - validateTargetPreconditions, - validateVariableName, - WEB_ENVIRONMENTS, - WEB_ENV_PROJECTS, - type TargetState, -} from './plan.js'; - -function states(present: boolean): TargetState[] { - return WEB_ENVIRONMENTS.flatMap(environment => - WEB_ENV_PROJECTS.map(project => ({ - project, - environment, - variable: present ? { key: 'API_TOKEN', type: 'encrypted' as const } : undefined, - })) - ); -} - -void test('builds the fixed project and environment matrix in risk order', () => { - const operations = buildWriteOperations(true); - assert.deepEqual( - operations.map(operation => `${operation.project}/${operation.environment}`), - [ - 'kilocode-app/development', - 'kilocode-global-app/development', - 'kilocode-app/staging', - 'kilocode-global-app/staging', - 'kilocode-app/production', - 'kilocode-global-app/production', - ] - ); - assert.deepEqual( - operations.map(operation => operation.expectedType), - ['encrypted', 'encrypted', 'sensitive', 'sensitive', 'sensitive', 'sensitive'] - ); -}); - -void test('keeps every target encrypted for non-sensitive variables', () => { - assert.ok(buildWriteOperations(false).every(operation => operation.expectedType === 'encrypted')); -}); - -void test('enforces strict add and update preconditions', () => { - assert.doesNotThrow(() => validateTargetPreconditions('add', states(false))); - assert.doesNotThrow(() => validateTargetPreconditions('update', states(true))); - assert.throws(() => validateTargetPreconditions('add', states(true)), /already exists/); - assert.throws(() => validateTargetPreconditions('update', states(false)), /missing/); -}); - -void test('requires explicit non-sensitive mode for client-exposed names', () => { - assert.throws(() => validateVariableName('NEXT_PUBLIC_API_TOKEN', true), /--no-sensitive/); - assert.doesNotThrow(() => validateVariableName('NEXT_PUBLIC_API_TOKEN', false)); - assert.throws(() => validateVariableName('bad-name', false), /uppercase/); -}); diff --git a/scripts/web-env/plan.ts b/scripts/web-env/plan.ts deleted file mode 100644 index 6e2c9fede..000000000 --- a/scripts/web-env/plan.ts +++ /dev/null @@ -1,84 +0,0 @@ -export const WEB_ENV_PROJECTS = ['kilocode-app', 'kilocode-global-app'] as const; -export const WEB_ENVIRONMENTS = ['development', 'staging', 'production'] as const; -export const WEB_ENV_VAULT = 'Kilo Web ENV Production'; -export const VERCEL_VERSION = '53.3.1'; - -export type WebEnvProject = (typeof WEB_ENV_PROJECTS)[number]; -export type WebEnvironment = (typeof WEB_ENVIRONMENTS)[number]; -export type WebEnvMode = 'add' | 'update' | 'resume'; -export type VercelVariableType = 'plain' | 'encrypted' | 'sensitive' | 'system'; - -export type VariableMetadata = { - key: string; - type: VercelVariableType; -}; - -export type TargetState = { - project: WebEnvProject; - environment: WebEnvironment; - variable?: VariableMetadata; -}; - -export type EnvironmentValues = Record; - -export type VercelWriteOperation = { - project: WebEnvProject; - environment: WebEnvironment; - sensitive: boolean; - expectedType: 'encrypted' | 'sensitive'; -}; - -const VARIABLE_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/; - -export function validateVariableName(name: string, sensitive: boolean): void { - if (!VARIABLE_NAME_PATTERN.test(name)) { - throw new Error( - 'Variable names must use uppercase letters, digits, and underscores, and cannot start with a digit.' - ); - } - if (sensitive && name.startsWith('NEXT_PUBLIC_')) { - throw new Error('NEXT_PUBLIC_* variables are client-exposed and must use --no-sensitive.'); - } -} - -export function validateTargetPreconditions(mode: 'add' | 'update', states: TargetState[]): void { - const present = states.filter(state => state.variable !== undefined); - if (mode === 'add' && present.length > 0) { - const locations = present - .map(state => `${state.project}/${state.environment}`) - .sort() - .join(', '); - throw new Error(`Cannot add: the variable already exists in ${locations}. Use update instead.`); - } - - if (mode === 'update' && present.length !== states.length) { - const missing = states - .filter(state => state.variable === undefined) - .map(state => `${state.project}/${state.environment}`) - .sort() - .join(', '); - throw new Error(`Cannot update: the variable is missing from ${missing}.`); - } -} - -export function buildWriteOperations(sensitive: boolean): VercelWriteOperation[] { - return WEB_ENVIRONMENTS.flatMap(environment => - WEB_ENV_PROJECTS.map(project => { - const targetIsSensitive = sensitive && environment !== 'development'; - return { - project, - environment, - sensitive: targetIsSensitive, - expectedType: targetIsSensitive ? 'sensitive' : 'encrypted', - } satisfies VercelWriteOperation; - }) - ); -} - -export function assertNonEmptyValues(values: EnvironmentValues): void { - for (const environment of WEB_ENVIRONMENTS) { - if (values[environment].length === 0) { - throw new Error(`${environment} cannot be empty.`); - } - } -} diff --git a/scripts/web-env/prompts.test.ts b/scripts/web-env/prompts.test.ts deleted file mode 100644 index 702b58ecf..000000000 --- a/scripts/web-env/prompts.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import assert from 'node:assert/strict'; -import { PassThrough } from 'node:stream'; -import test from 'node:test'; -import { createTerminalPrompts, normalizeMultilineInput } from './prompts.js'; - -void test('coalesces pasted CRLF multiline input and never echoes its value', async () => { - const input = new PassThrough() as PassThrough & { - isTTY: boolean; - setRawMode(enabled: boolean): void; - }; - const output = new PassThrough() as PassThrough & { isTTY: boolean }; - const rawModes: boolean[] = []; - let visibleOutput = ''; - input.isTTY = true; - input.setRawMode = enabled => { - rawModes.push(enabled); - }; - output.isTTY = true; - output.setEncoding('utf8'); - output.on('data', chunk => { - visibleOutput += String(chunk); - }); - - const result = createTerminalPrompts(input, output).askSecret('Secret', 'multiline'); - input.write('line-one\r'); - await new Promise(resolve => setImmediate(resolve)); - input.write('\nline-two\r'); - await new Promise(resolve => setImmediate(resolve)); - input.write('\n::end\r'); - await new Promise(resolve => setTimeout(resolve, 30)); - input.write('\n'); - - assert.equal(await result, 'line-one\nline-two'); - assert.equal(input.readableLength, 0); - assert.deepEqual(rawModes, [true, false]); - assert.equal(visibleOutput.includes('line-one'), false); - assert.equal(visibleOutput.includes('line-two'), false); -}); - -void test('normalizes the terminal sentinel newline consistently for both providers', () => { - assert.equal(normalizeMultilineInput('{"key":"value"}\n'), '{"key":"value"}'); - assert.equal( - normalizeMultilineInput('-----BEGIN KEY-----\nvalue\n-----END KEY-----\n'), - '-----BEGIN KEY-----\nvalue\n-----END KEY-----' - ); - assert.equal(normalizeMultilineInput('already-normalized'), 'already-normalized'); -}); diff --git a/scripts/web-env/prompts.ts b/scripts/web-env/prompts.ts deleted file mode 100644 index caa4244f7..000000000 --- a/scripts/web-env/prompts.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { createInterface } from 'node:readline/promises'; -import { PassThrough, type Readable, type Writable } from 'node:stream'; - -export class UserAbortError extends Error { - constructor() { - super('Operation cancelled.'); - } -} - -export type SecretInputMode = 'single-line' | 'multiline'; - -export function normalizeMultilineInput(value: string): string { - return value.endsWith('\n') ? value.slice(0, -1) : value; -} - -export type PromptDriver = { - askText(question: string, defaultValue?: string): Promise; - confirm(question: string): Promise; - askSecret(question: string, mode: SecretInputMode): Promise; -}; - -type TtyReadable = Readable & { - isTTY?: boolean; - setRawMode?: (enabled: boolean) => void; -}; - -type TtyWritable = Writable & { - isTTY?: boolean; -}; - -function createNormalizedInput(input: TtyReadable): Readable { - const normalized = new PassThrough(); - let dropLineFeedAfterCarriageReturn = false; - input.on('data', chunk => { - let output = ''; - for (const character of String(chunk)) { - if (character === '\r') { - output += '\n'; - dropLineFeedAfterCarriageReturn = true; - continue; - } - if (character === '\n' && dropLineFeedAfterCarriageReturn) { - dropLineFeedAfterCarriageReturn = false; - continue; - } - dropLineFeedAfterCarriageReturn = false; - output += character; - } - if (output.length > 0) normalized.write(output); - }); - return normalized; -} - -async function askVisible( - input: Readable, - output: Writable, - question: string, - defaultValue?: string -): Promise { - input.resume(); - const prompt = defaultValue === undefined ? question : `${question} [${defaultValue}] `; - const rl = createInterface({ input, output }); - try { - const answer = await rl.question(prompt); - return answer.length === 0 && defaultValue !== undefined ? defaultValue : answer; - } finally { - rl.close(); - } -} - -function readHidden( - input: Readable, - ttyInput: TtyReadable, - output: TtyWritable, - question: string, - mode: SecretInputMode -): Promise { - if (!ttyInput.isTTY || !output.isTTY || !ttyInput.setRawMode) { - throw new Error('Hidden value input requires an interactive TTY.'); - } - - output.write(question); - input.setEncoding('utf8'); - ttyInput.setRawMode(true); - input.resume(); - - return new Promise((resolve, reject) => { - let value = ''; - let currentLine = ''; - let finished = false; - const sentinel = '::end'; - - const cleanup = () => { - input.off('data', onData); - process.off('SIGINT', onSignal); - process.off('SIGTERM', onSignal); - ttyInput.setRawMode?.(false); - input.pause(); - }; - - const finish = (result: string) => { - if (finished) return; - finished = true; - cleanup(); - output.write('\n'); - resolve(result); - }; - - const onSignal = () => { - if (finished) return; - finished = true; - cleanup(); - output.write('\n'); - reject(new UserAbortError()); - }; - - const processNewline = () => { - if (mode === 'single-line') { - finish(value); - return; - } - if (currentLine === sentinel) { - finish(normalizeMultilineInput(value)); - return; - } - value += `${currentLine}\n`; - currentLine = ''; - }; - - const onData = (chunk: string | Buffer) => { - for (const character of String(chunk)) { - if (character === '\u0003') { - onSignal(); - return; - } - if (character === '\u007f' || character === '\b') { - if (mode === 'single-line') { - value = [...value].slice(0, -1).join(''); - } else { - currentLine = [...currentLine].slice(0, -1).join(''); - } - continue; - } - if (character === '\n') { - processNewline(); - if (finished) return; - continue; - } - if (mode === 'single-line') value += character; - else currentLine += character; - } - }; - - input.on('data', onData); - process.once('SIGINT', onSignal); - process.once('SIGTERM', onSignal); - }); -} - -export function createTerminalPrompts( - input: TtyReadable = process.stdin, - output: TtyWritable = process.stdout -): PromptDriver { - const normalizedInput = createNormalizedInput(input); - return { - askText: (question, defaultValue) => - askVisible(normalizedInput, output, question, defaultValue), - confirm: async question => { - const answer = await askVisible(normalizedInput, output, `${question} [y/N] `); - return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes'; - }, - askSecret: (question, mode) => { - const suffix = mode === 'multiline' ? ' (finish with a line containing ::end)' : ''; - return readHidden(normalizedInput, input, output, `${question}${suffix}: `, mode); - }, - }; -} diff --git a/scripts/web-env/resume.test.ts b/scripts/web-env/resume.test.ts deleted file mode 100644 index 59ea04bff..000000000 --- a/scripts/web-env/resume.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtemp, readFile, rm, stat } from 'node:fs/promises'; -import os from 'node:os'; -import path from 'node:path'; -import test from 'node:test'; -import { readResumeJournal, writeResumeJournal, type ResumeJournal } from './resume.js'; - -void test('resume journals are value-free, private, and round-trip safely', async () => { - const root = await mkdtemp(path.join(os.tmpdir(), 'web-env-resume-test-')); - try { - const journal: ResumeJournal = { - version: 1, - variableName: 'API_TOKEN', - sensitive: true, - createdAt: '2026-06-16T12:00:00.000Z', - completed: ['kilocode-app/development'], - failed: 'kilocode-global-app/development', - pending: ['kilocode-app/staging'], - onePassword: 'pending', - }; - const relativePath = await writeResumeJournal(root, journal); - const absolutePath = path.join(root, relativePath); - const content = await readFile(absolutePath, 'utf8'); - assert.equal(content.includes('super-secret-value'), false); - assert.deepEqual(await readResumeJournal(absolutePath), journal); - assert.equal((await stat(absolutePath)).mode & 0o777, 0o600); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); diff --git a/scripts/web-env/resume.ts b/scripts/web-env/resume.ts deleted file mode 100644 index 22c01005c..000000000 --- a/scripts/web-env/resume.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { mkdir, readFile, writeFile } from 'node:fs/promises'; -import path from 'node:path'; -import { isRecord, readString } from './json.js'; -import type { VercelWriteOperation } from './plan.js'; - -export type ResumeJournal = { - version: 1; - variableName: string; - sensitive: boolean; - createdAt: string; - completed: string[]; - failed: string; - pending: string[]; - onePassword: 'completed' | 'failed' | 'pending' | 'skipped'; -}; - -export function operationId(operation: VercelWriteOperation): string { - return `${operation.project}/${operation.environment}`; -} - -export async function writeResumeJournal( - repoRoot: string, - journal: ResumeJournal -): Promise { - const directory = path.join(repoRoot, '.tmp', 'web-env'); - await mkdir(directory, { recursive: true, mode: 0o700 }); - const safeTimestamp = journal.createdAt.replace(/[:.]/g, '-'); - const destination = path.join(directory, `${journal.variableName}-${safeTimestamp}.json`); - await writeFile(destination, `${JSON.stringify(journal, null, 2)}\n`, { mode: 0o600 }); - return path.relative(repoRoot, destination); -} - -function readStringArray(record: Record, key: string): string[] | undefined { - const value = record[key]; - if (!Array.isArray(value) || !value.every(item => typeof item === 'string')) return undefined; - return value; -} - -export async function readResumeJournal(filePath: string): Promise { - let parsed: unknown; - try { - parsed = JSON.parse(await readFile(filePath, 'utf8')); - } catch { - throw new Error('The resume journal is missing or invalid.'); - } - if (!isRecord(parsed)) throw new Error('The resume journal has an unexpected format.'); - - const variableName = readString(parsed, 'variableName'); - const createdAt = readString(parsed, 'createdAt'); - const completed = readStringArray(parsed, 'completed'); - const failed = readString(parsed, 'failed'); - const pending = readStringArray(parsed, 'pending'); - const onePassword = readString(parsed, 'onePassword'); - if ( - parsed.version !== 1 || - !variableName || - typeof parsed.sensitive !== 'boolean' || - !createdAt || - !completed || - !failed || - !pending || - (onePassword !== 'completed' && - onePassword !== 'failed' && - onePassword !== 'pending' && - onePassword !== 'skipped') - ) { - throw new Error('The resume journal has an unexpected format.'); - } - - return { - version: 1, - variableName, - sensitive: parsed.sensitive, - createdAt, - completed, - failed, - pending, - onePassword, - }; -} diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts new file mode 100644 index 000000000..1616707e8 --- /dev/null +++ b/scripts/web-env/shared.ts @@ -0,0 +1,323 @@ +import { spawnSync } from 'node:child_process'; +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import * as readline from 'node:readline'; + +export const PROJECTS = ['kilocode-app', 'kilocode-global-app'] as const; +export const ENVIRONMENTS = ['development', 'staging', 'production'] as const; +export const VAULT = 'Kilo Web ENV Production'; + +export type Project = (typeof PROJECTS)[number]; +export type Environment = (typeof ENVIRONMENTS)[number]; +export type Values = Record; +export type VercelContext = { + project: Project; + projectId: string; + orgId: string; + stagingId: string; + cwd: string; +}; + +type JsonRecord = Record; + +function isRecord(value: unknown): value is JsonRecord { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +function parseJson(value: string, operation: string): JsonRecord { + try { + const parsed: unknown = JSON.parse(value); + if (isRecord(parsed)) return parsed; + } catch { + // The provider output is intentionally omitted because it may contain secrets. + } + throw new Error(`${operation} returned an unexpected response.`); +} + +function records(value: unknown): JsonRecord[] { + return Array.isArray(value) ? value.filter(isRecord) : []; +} + +function stringValue(record: JsonRecord, key: string): string | undefined { + return typeof record[key] === 'string' ? record[key] : undefined; +} + +export function run( + command: string, + args: string[], + options: { cwd?: string; env?: NodeJS.ProcessEnv; input?: string } = {} +): string { + const result = spawnSync(command, args, { + cwd: options.cwd, + env: options.env, + input: options.input, + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + maxBuffer: 10 * 1024 * 1024, + }); + if (result.status !== 0) { + throw new Error( + `${command} ${args.slice(0, 3).join(' ')} failed; provider output was redacted.` + ); + } + return result.stdout; +} + +function vercel( + context: Pick | undefined, + args: string[], + input?: string +): string { + return run( + 'pnpm', + [ + 'dlx', + '--yes', + 'vercel@53.3.1', + ...args, + '--scope', + 'kilocode', + '--non-interactive', + '--no-color', + ...(context ? ['--cwd', context.cwd] : []), + ], + { + cwd: context?.cwd, + env: context + ? { + ...process.env, + VERCEL_ORG_ID: context.orgId, + VERCEL_PROJECT_ID: context.projectId, + } + : process.env, + input, + } + ); +} + +export function resolveVercelContexts(tempDirectory: string): VercelContext[] { + const whoami = parseJson(vercel(undefined, ['whoami', '--format=json']), 'Vercel login'); + const team = isRecord(whoami.team) ? whoami.team : undefined; + const orgId = team ? stringValue(team, 'id') : undefined; + if (!orgId || stringValue(team ?? {}, 'slug') !== 'kilocode') { + throw new Error('Sign in to the kilocode Vercel team with `vercel login`.'); + } + + return PROJECTS.map(project => { + const projectList = parseJson( + vercel(undefined, ['project', 'list', '--filter', project, '--format=json']), + `Resolve ${project}` + ); + const match = records(projectList.projects).find(candidate => candidate.name === project); + const projectId = match ? stringValue(match, 'id') : undefined; + if (!projectId) throw new Error(`Could not resolve Vercel project ${project}.`); + + const base = { project, projectId, orgId, cwd: tempDirectory }; + const targetList = parseJson(vercel(base, ['target', 'list', '--format=json']), 'List targets'); + const staging = records(targetList.targets).find(candidate => candidate.slug === 'staging'); + const stagingId = staging ? stringValue(staging, 'id') : undefined; + if (!stagingId) throw new Error(`${project} does not have a custom staging environment.`); + return { ...base, stagingId }; + }); +} + +function target(context: VercelContext, environment: Environment): string { + return environment === 'staging' ? context.stagingId : environment; +} + +export function listVariables( + context: VercelContext, + environment: Environment +): Map { + const response = parseJson( + vercel(context, ['env', 'list', target(context, environment), '--format=json']), + `List ${context.project}/${environment}` + ); + return new Map( + records(response.envs) + .map(variable => [stringValue(variable, 'key'), stringValue(variable, 'type')] as const) + .filter((entry): entry is [string, string] => Boolean(entry[0] && entry[1])) + ); +} + +export function setVariable( + context: VercelContext, + environment: Environment, + name: string, + value: string, + sensitive: boolean +): void { + const shouldBeSensitive = sensitive && environment !== 'development'; + vercel( + context, + [ + 'env', + 'add', + name, + target(context, environment), + '--force', + shouldBeSensitive ? '--sensitive' : '--no-sensitive', + '--yes', + ], + value + ); + const type = listVariables(context, environment).get(name); + const expected = shouldBeSensitive ? 'sensitive' : 'encrypted'; + if (type !== expected) { + throw new Error( + `${context.project}/${environment} has type ${type ?? 'missing'}, expected ${expected}.` + ); + } +} + +export function pullValue( + context: VercelContext, + environment: Environment, + name: string +): string | undefined { + const endpoint = `/v3/env/pull/${encodeURIComponent(context.projectId)}/${encodeURIComponent(target(context, environment))}?source=vercel-cli%3Aenv%3Apull`; + const response = parseJson(vercel(context, ['api', endpoint, '--raw']), 'Pull Vercel values'); + const values = isRecord(response.env) ? response.env : undefined; + return values && typeof values[name] === 'string' ? values[name] : undefined; +} + +export function resolveVault(): string { + run('op', ['whoami', '--format=json']); + const vault = parseJson(run('op', ['vault', 'get', VAULT, '--format=json']), 'Resolve vault'); + const vaultId = stringValue(vault, 'id'); + if (!vaultId) throw new Error(`Could not resolve 1Password vault ${VAULT}.`); + return vaultId; +} + +function findVaultItem(vaultId: string, name: string): JsonRecord | undefined { + const items = JSON.parse( + run('op', ['item', 'list', '--vault', vaultId, '--format=json']) + ) as unknown; + const matches = records(items).filter(item => item.title === name); + if (matches.length > 1) throw new Error(`More than one 1Password item is named ${name}.`); + return matches[0]; +} + +export function setVaultValue(vaultId: string, name: string, value: string): void { + const existing = findVaultItem(vaultId, name); + if (!existing) { + const item = { + title: name, + category: 'PASSWORD', + fields: [{ id: 'password', label: 'password', type: 'CONCEALED', value }], + }; + run('op', ['item', 'create', '--vault', vaultId, '--format=json', '-'], { + input: JSON.stringify(item), + }); + return; + } + + const id = stringValue(existing, 'id'); + if (!id) throw new Error(`1Password item ${name} has no ID.`); + const item = parseJson( + run('op', ['item', 'get', id, '--vault', vaultId, '--format=json']), + `Read ${name}` + ); + const password = records(item.fields).find(field => field.id === 'password'); + if (!password || password.type !== 'CONCEALED') { + throw new Error(`1Password item ${name} does not have a concealed password field.`); + } + password.value = value; + run('op', ['item', 'edit', id, '--vault', vaultId, '--format=json'], { + input: JSON.stringify(item), + }); +} + +export function findRepoRoot(): string { + let directory = process.cwd(); + while (path.dirname(directory) !== directory) { + const packageFile = path.join(directory, 'package.json'); + if (existsSync(packageFile)) { + const packageJson = JSON.parse(readFileSync(packageFile, 'utf8')) as { name?: string }; + if (packageJson.name === 'kilocode-monorepo') return directory; + } + directory = path.dirname(directory); + } + throw new Error('Run this command inside the kilocode-monorepo checkout.'); +} + +export function trackedEnvFiles(repoRoot: string): string[] { + return run('git', ['ls-files', '-z', '--', '.env*', 'apps/web/.env*'], { cwd: repoRoot }) + .split('\0') + .filter(file => { + if (!file) return false; + const inScope = !file.includes('/') || file.startsWith('apps/web/'); + const basename = path.basename(file); + return ( + inScope && + basename.startsWith('.env') && + basename !== '.envrc' && + (!basename.includes('.local') || basename.includes('.example')) + ); + }); +} + +export function setEnvDefault(file: string, name: string, value: string): void { + const content = readFileSync(file, 'utf8'); + const lines = content.split('\n'); + const matches = lines.flatMap((line, index) => + new RegExp(`^${name}=`).test(line) ? [index] : [] + ); + if (matches.length > 1) throw new Error(`${file} declares ${name} more than once.`); + const assignment = `${name}=${JSON.stringify(value)}`; + if (matches.length === 1) lines[matches[0] ?? 0] = assignment; + else lines.push(assignment); + writeFileSync(file, lines.join('\n')); +} + +export function question(prompt: string): Promise { + const interface_ = readline.createInterface({ input: process.stdin, output: process.stdout }); + return new Promise(resolve => { + interface_.question(prompt, answer => { + interface_.close(); + resolve(answer); + }); + }); +} + +export async function confirm(prompt: string): Promise { + return ['y', 'yes'].includes((await question(`${prompt} [y/N] `)).trim().toLowerCase()); +} + +export function readSecret(prompt: string): Promise { + if (!process.stdin.isTTY || !process.stdout.isTTY) { + throw new Error( + 'Secret prompts require an interactive terminal; use the --*-file options instead.' + ); + } + process.stdout.write(prompt); + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.setEncoding('utf8'); + return new Promise((resolve, reject) => { + let value = ''; + const finish = () => { + process.stdin.off('data', onData); + process.stdin.setRawMode(false); + process.stdin.pause(); + process.stdout.write('\n'); + }; + const onData = (chunk: string) => { + for (const character of chunk) { + if (character === '\u0003') { + finish(); + reject(new Error('Cancelled.')); + return; + } + if (character === '\r' || character === '\n') { + finish(); + resolve(value); + return; + } + if (character === '\u007f') value = value.slice(0, -1); + else value += character; + } + }; + process.stdin.on('data', onData); + }); +} diff --git a/scripts/web-env/tsconfig.json b/scripts/web-env/tsconfig.json deleted file mode 100644 index 68212bf40..000000000 --- a/scripts/web-env/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "noEmit": true, - "skipLibCheck": true, - "types": ["node"] - }, - "include": ["./**/*.ts"] -} diff --git a/scripts/web-env/vercel.ts b/scripts/web-env/vercel.ts deleted file mode 100644 index 8abdc00ec..000000000 --- a/scripts/web-env/vercel.ts +++ /dev/null @@ -1,233 +0,0 @@ -import type { CommandExecutor, CommandResult } from './command.js'; -import { requireSuccess } from './command.js'; -import { isRecord, parseJsonObject, readRecords, readString } from './json.js'; -import { - VERCEL_VERSION, - WEB_ENV_PROJECTS, - type VariableMetadata, - type VercelVariableType, - type WebEnvironment, - type WebEnvProject, -} from './plan.js'; - -const VERCEL_SCOPE = 'kilocode'; -const VERCEL_TYPES = new Set(['plain', 'encrypted', 'sensitive', 'system']); - -function parseVariableType(value: unknown): VercelVariableType | undefined { - if (typeof value !== 'string') return undefined; - if (value === 'plain' || value === 'encrypted' || value === 'sensitive' || value === 'system') { - return value; - } - return undefined; -} - -export type ResolvedVercelProject = { - name: WebEnvProject; - id: string; -}; - -export class VercelAdapter { - readonly #execute: CommandExecutor; - readonly #tempRoot: string; - readonly #projectIds = new Map(); - readonly #stagingEnvironmentIds = new Map(); - #orgId = ''; - - constructor(execute: CommandExecutor, tempRoot: string) { - this.#execute = execute; - this.#tempRoot = tempRoot; - } - - async #run(args: string[], project?: WebEnvProject, stdin?: string): Promise { - const env: NodeJS.ProcessEnv = { - ...process.env, - AI_AGENT: 'kilo-web-env-adapter', - }; - if (project) { - env.VERCEL_ORG_ID = this.#orgId; - env.VERCEL_PROJECT_ID = this.#getProjectId(project); - } - return this.#execute({ - command: 'pnpm', - args: [ - 'exec', - 'vercel', - ...args, - '--scope', - VERCEL_SCOPE, - '--cwd', - this.#tempRoot, - '--non-interactive', - '--no-color', - ], - cwd: this.#tempRoot, - env, - stdin, - timeoutMs: 120_000, - }); - } - - #getProjectId(project: WebEnvProject): string { - const id = this.#projectIds.get(project); - if (!id) throw new Error(`Vercel project ${project} has not been resolved.`); - return id; - } - - #getEnvironmentTarget(project: WebEnvProject, environment: WebEnvironment): string { - if (environment !== 'staging') return environment; - const id = this.#stagingEnvironmentIds.get(project); - if (!id) throw new Error(`Vercel staging environment for ${project} has not been resolved.`); - return id; - } - - async initialize(requireNonSensitivePolicy = false): Promise { - const versionResult = await this.#run(['--version']); - const version = requireSuccess(versionResult, 'Vercel CLI version check'); - if (!version.includes(VERCEL_VERSION)) { - throw new Error(`Expected Vercel CLI ${VERCEL_VERSION}. Run pnpm install.`); - } - - const whoamiResult = await this.#run(['whoami', '--format=json']); - const whoami = parseJsonObject( - requireSuccess(whoamiResult, 'Vercel authentication check'), - 'Vercel authentication check' - ); - const team = whoami.team; - if (!isRecord(team) || readString(team, 'slug') !== VERCEL_SCOPE) { - throw new Error(`Vercel CLI is not authenticated to the ${VERCEL_SCOPE} scope.`); - } - const orgId = readString(team, 'id'); - if (!orgId) throw new Error('Vercel authentication response did not include a team ID.'); - this.#orgId = orgId; - - const resolved: ResolvedVercelProject[] = []; - for (const project of WEB_ENV_PROJECTS) { - const listResult = await this.#run(['project', 'list', '--filter', project, '--format=json']); - const response = parseJsonObject( - requireSuccess(listResult, `Resolve Vercel project ${project}`), - `Resolve Vercel project ${project}` - ); - const exactMatches = readRecords(response, 'projects').filter( - candidate => readString(candidate, 'name') === project - ); - if (exactMatches.length !== 1) { - throw new Error(`Expected exactly one Vercel project named ${project}.`); - } - const id = readString(exactMatches[0] ?? {}, 'id'); - if (!id) throw new Error(`Vercel project ${project} did not include an ID.`); - this.#projectIds.set(project, id); - resolved.push({ name: project, id }); - } - - for (const project of WEB_ENV_PROJECTS) { - const targetsResult = await this.#run(['target', 'list', '--format=json'], project); - const targets = parseJsonObject( - requireSuccess(targetsResult, `List Vercel targets for ${project}`), - `List Vercel targets for ${project}` - ); - const stagingTargets = readRecords(targets, 'targets').filter( - target => readString(target, 'slug') === 'staging' - ); - if (stagingTargets.length !== 1) { - throw new Error(`Vercel project ${project} must have one custom staging environment.`); - } - const stagingId = readString(stagingTargets[0] ?? {}, 'id'); - if (!stagingId) throw new Error(`Vercel staging environment for ${project} has no ID.`); - this.#stagingEnvironmentIds.set(project, stagingId); - } - - if (requireNonSensitivePolicy) { - const policyResult = await this.#run(['api', `/teams/${this.#orgId}`, '--raw']); - const policy = parseJsonObject( - requireSuccess(policyResult, 'Vercel sensitive-variable policy check'), - 'Vercel sensitive-variable policy check' - ); - if (readString(policy, 'sensitiveEnvironmentVariablePolicy') === 'on') { - throw new Error( - 'The Vercel team policy forces sensitive deployed variables, so --no-sensitive cannot be honored.' - ); - } - } - - return resolved; - } - - async listVariables( - project: WebEnvProject, - environment: WebEnvironment - ): Promise { - const target = this.#getEnvironmentTarget(project, environment); - const result = await this.#run(['env', 'list', target, '--format=json'], project); - const response = parseJsonObject( - requireSuccess(result, `List ${project}/${environment} variables`), - `List ${project}/${environment} variables` - ); - const variables: VariableMetadata[] = []; - for (const candidate of readRecords(response, 'envs')) { - const key = readString(candidate, 'key'); - const type = parseVariableType(candidate.type); - if (key && type && VERCEL_TYPES.has(type)) variables.push({ key, type }); - } - return variables; - } - - async getVariable( - project: WebEnvProject, - environment: WebEnvironment, - key: string - ): Promise { - const matches = (await this.listVariables(project, environment)).filter( - variable => variable.key === key - ); - if (matches.length > 1) { - throw new Error(`Multiple ${key} definitions exist in ${project}/${environment}.`); - } - return matches[0]; - } - - async writeVariable(options: { - mode: 'add' | 'update' | 'resume'; - project: WebEnvProject; - environment: WebEnvironment; - key: string; - value: string; - sensitive: boolean; - expectedType: 'encrypted' | 'sensitive'; - }): Promise { - const target = this.#getEnvironmentTarget(options.project, options.environment); - const args = ['env', 'add', options.key, target]; - if (options.mode !== 'add') args.push('--force'); - args.push(options.sensitive ? '--sensitive' : '--no-sensitive', '--yes'); - - const result = await this.#run(args, options.project, options.value); - requireSuccess(result, `Write ${options.project}/${options.environment}`); - - const metadata = await this.getVariable(options.project, options.environment, options.key); - if (metadata?.type !== options.expectedType) { - throw new Error( - `Vercel type verification failed for ${options.project}/${options.environment}.` - ); - } - } - - async pullReadableValue( - project: WebEnvProject, - environment: WebEnvironment, - key: string - ): Promise { - const target = encodeURIComponent(this.#getEnvironmentTarget(project, environment)); - const projectId = encodeURIComponent(this.#getProjectId(project)); - const endpoint = `/v3/env/pull/${projectId}/${target}?source=vercel-cli%3Aenv%3Apull`; - const result = await this.#run(['api', endpoint, '--raw'], project); - const response = parseJsonObject( - requireSuccess(result, `Pull ${project}/${environment} variables`), - `Pull ${project}/${environment} variables` - ); - const environmentValues = response.env; - if (!isRecord(environmentValues)) { - throw new Error(`Vercel returned an unexpected ${project}/${environment} response.`); - } - const value = environmentValues[key]; - return typeof value === 'string' ? value : undefined; - } -} From 8fd783c17694216ed6ea74f449591fb6292afcef Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 17:18:00 +0200 Subject: [PATCH 03/22] docs(web): document simplified env workflow --- DEVELOPMENT.md | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index f39b0b717..ab740b010 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -155,35 +155,28 @@ These changes will allow you to do local testing with a fake account. Use the repository workflow instead of editing Vercel projects independently. It updates `kilocode-app` and `kilocode-global-app` together for Development, Staging, and Production: ```bash -pnpm web:env add EXAMPLE_API_TOKEN -pnpm web:env update EXAMPLE_API_TOKEN +pnpm web:env set EXAMPLE_API_TOKEN ``` Prerequisites: - Sign in with `vercel login` and have access to both projects in the `kilocode` scope. - Sign in with `op signin` and have write access to the `Kilo Web ENV Production` vault. -- Run `pnpm install` so the repository-pinned Vercel CLI is available. +- Have `pnpm` available; the command runs the pinned Vercel CLI with `pnpm dlx`. Variables are sensitive by default. Production and Staging become Vercel-sensitive, while the separate Development value remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. For public or otherwise non-secret configuration, opt out explicitly: ```bash -pnpm web:env add EXAMPLE_FEATURE_FLAG --no-sensitive +pnpm web:env set EXAMPLE_FEATURE_FLAG --no-sensitive ``` `NEXT_PUBLIC_*` variables require `--no-sensitive` because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for all three values using hidden input, then asks for an explicit safe default or skip decision for every tracked root and `apps/web` dotenv file. Real environment values are never written to tracked files. Use `--dry-run` to perform preflight and preview the redacted plan without retaining changes. +The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. -Remote updates are not transactional. If a provider write fails, the command stops and writes a value-free resume journal under `.tmp/web-env/`. Re-enter all three values with the printed command: - -```bash -pnpm web:env resume .tmp/web-env/.json -``` - -The workflow does not deploy. Trigger the appropriate Staging or Production deployment separately when the new values should take effect. +Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. ### 4. Start the database From 0f84777a6141724d8a2f3f37bbb444354c0a706d Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 17:18:06 +0200 Subject: [PATCH 04/22] ci(web): narrow setup smoke triggers --- .github/workflows/setup-smoke.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/setup-smoke.yml b/.github/workflows/setup-smoke.yml index 8d9b115f2..b7544e8f5 100644 --- a/.github/workflows/setup-smoke.yml +++ b/.github/workflows/setup-smoke.yml @@ -10,7 +10,8 @@ on: - '.env.local.example' - 'apps/web/.env' - 'apps/web/.env.development.local.example' - - 'dev/local/**' + - 'dev/local/setup-env.ts' + - 'dev/local/env-sync/**' - 'scripts/dev.sh' - '.github/workflows/setup-smoke.yml' From 14a95a4ae02f6b7e4c20e703b4c6af1854e125e6 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 17:20:02 +0200 Subject: [PATCH 05/22] chore(web): typecheck env scripts --- package.json | 1 + pnpm-lock.yaml | 3 +++ scripts/typecheck-all.sh | 3 ++- scripts/web-env/tsconfig.json | 10 ++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 scripts/web-env/tsconfig.json diff --git a/package.json b/package.json index a536e9325..a4755d1d2 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ }, "packageManager": "pnpm@11.1.2", "devDependencies": { + "@types/node": "catalog:", "@typescript/native-preview": "catalog:", "husky": "9.1.7", "ink": "6.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c6c88eaf6..c4421b024 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,6 +129,9 @@ importers: .: devDependencies: + '@types/node': + specifier: 'catalog:' + version: 24.12.4 '@typescript/native-preview': specifier: 'catalog:' version: 7.0.0-dev.20260514.1 diff --git a/scripts/typecheck-all.sh b/scripts/typecheck-all.sh index f9d8da334..412881e6a 100755 --- a/scripts/typecheck-all.sh +++ b/scripts/typecheck-all.sh @@ -42,8 +42,9 @@ else pnpm --filter @kilocode/trpc run build fi -# 2. Root typecheck (always — it's fast with incremental tsgo) +# 2. Root typechecks (always — they are fast with incremental tsgo) tsgo --noEmit -p apps/web/tsconfig.json +tsgo --noEmit -p scripts/web-env/tsconfig.json # 3. Workspace typecheck if ! $changes_only; then diff --git a/scripts/web-env/tsconfig.json b/scripts/web-env/tsconfig.json new file mode 100644 index 000000000..732a7df9c --- /dev/null +++ b/scripts/web-env/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "noEmit": true, + "types": ["node"] + }, + "include": ["*.ts"] +} From 72966202e2d0f18b349da8fc6cc77a4f88fb83ee Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Tue, 16 Jun 2026 17:20:59 +0200 Subject: [PATCH 06/22] fix(web): invoke pinned Vercel CLI correctly --- scripts/web-env/shared.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index 1616707e8..df24fab42 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -72,7 +72,6 @@ function vercel( 'pnpm', [ 'dlx', - '--yes', 'vercel@53.3.1', ...args, '--scope', From 2ea10f9b6ea93f1ffd9a3aa1029aabee99dc1b11 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:12:50 +0200 Subject: [PATCH 07/22] feat(web): prompt for env sensitivity --- DEVELOPMENT.md | 10 ++-------- scripts/web-env/index.ts | 27 ++++++++++++++++----------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index ab740b010..a514c75a8 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -164,15 +164,9 @@ Prerequisites: - Sign in with `op signin` and have write access to the `Kilo Web ENV Production` vault. - Have `pnpm` available; the command runs the pinned Vercel CLI with `pnpm dlx`. -Variables are sensitive by default. Production and Staging become Vercel-sensitive, while the separate Development value remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. +The command asks whether the variable is sensitive, defaulting to yes. Sensitive Production and Staging values use Vercel's sensitive type, while Development remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. -For public or otherwise non-secret configuration, opt out explicitly: - -```bash -pnpm web:env set EXAMPLE_FEATURE_FLAG --no-sensitive -``` - -`NEXT_PUBLIC_*` variables require `--no-sensitive` because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. +Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index d31b23d84..6c3b3e3b8 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -20,7 +20,6 @@ import { type Options = { name: string; - sensitive: boolean; dryRun: boolean; valueFiles: Partial>; }; @@ -28,7 +27,7 @@ type Options = { function usage(): never { throw new Error( [ - 'Usage: pnpm web:env set VARIABLE [--no-sensitive] [--dry-run]', + 'Usage: pnpm web:env set VARIABLE [--dry-run]', ' [--development-file PATH] [--staging-file PATH] [--production-file PATH]', ].join('\n') ); @@ -38,13 +37,11 @@ function parseOptions(args: string[]): Options { if (args[0] !== 'set' || !args[1]) usage(); const name = args[1]; const valueFiles: Partial> = {}; - let sensitive = true; let dryRun = false; for (let index = 2; index < args.length; index += 1) { const argument = args[index]; - if (argument === '--no-sensitive') sensitive = false; - else if (argument === '--dry-run') dryRun = true; + if (argument === '--dry-run') dryRun = true; else { const match = argument?.match(/^--(development|staging|production)-file(?:=(.*))?$/); if (!match) usage(); @@ -60,10 +57,17 @@ function parseOptions(args: string[]): Options { if (!/^[A-Z_][A-Z0-9_]*$/.test(name)) { throw new Error('Variable names must contain only uppercase letters, digits, and underscores.'); } + return { name, dryRun, valueFiles }; +} + +async function askSensitivity(name: string): Promise { + const answer = (await question(`Is ${name} sensitive? [Y/n] `)).trim().toLowerCase(); + if (!['', 'y', 'yes', 'n', 'no'].includes(answer)) throw new Error('Answer yes or no.'); + const sensitive = !['n', 'no'].includes(answer); if (sensitive && name.startsWith('NEXT_PUBLIC_')) { - throw new Error('NEXT_PUBLIC_* values are browser-visible; pass --no-sensitive.'); + throw new Error('NEXT_PUBLIC_* values are browser-visible; answer no.'); } - return { name, sensitive, dryRun, valueFiles }; + return sensitive; } async function collectValues(options: Options): Promise { @@ -114,24 +118,25 @@ function assertSecretsAreNotTracked(repoRoot: string, values: Values): void { async function main(): Promise { const options = parseOptions(process.argv.slice(2)); + const sensitive = await askSensitivity(options.name); const repoRoot = findRepoRoot(); const tempDirectory = mkdtempSync(path.join(os.tmpdir(), 'kilo-web-env-')); try { console.log('Checking Vercel and 1Password access...'); const contexts = resolveVercelContexts(tempDirectory); - const vaultId = options.sensitive ? resolveVault() : undefined; + const vaultId = sensitive ? resolveVault() : undefined; const values = await collectValues(options); const defaults = await collectDefaults(repoRoot, options.name, values); console.log('\nPlan'); for (const environment of ENVIRONMENTS) { - const type = options.sensitive && environment !== 'development' ? 'sensitive' : 'encrypted'; + const type = sensitive && environment !== 'development' ? 'sensitive' : 'encrypted'; for (const project of PROJECTS) console.log(`- ${project}/${environment}: ${type}`); } for (const [file, value] of defaults) console.log(`- ${file}: ${options.name}=${JSON.stringify(value)}`); - console.log(`- 1Password: ${options.sensitive ? 'update Production copy' : 'skip'}`); + console.log(`- 1Password: ${sensitive ? 'update Production copy' : 'skip'}`); console.log('- Deployments: not triggered'); if (options.dryRun) { @@ -151,7 +156,7 @@ async function main(): Promise { for (const environment of ENVIRONMENTS) { for (const context of contexts) { console.log(`Setting ${context.project}/${environment}...`); - setVariable(context, environment, options.name, values[environment], options.sensitive); + setVariable(context, environment, options.name, values[environment], sensitive); } } if (vaultId) { From 69cef4617439f9e4527794265367b536f6e8b903 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:16:06 +0200 Subject: [PATCH 08/22] fix(web): warn on matching tracked env values --- DEVELOPMENT.md | 2 +- scripts/web-env/index.ts | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a514c75a8..a169048ae 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -168,7 +168,7 @@ The command asks whether the variable is sensitive, defaulting to yes. Sensitive Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. +The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index 6c3b3e3b8..6b4831ca4 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -83,11 +83,7 @@ async function collectValues(options: Options): Promise { return values as Values; } -async function collectDefaults( - repoRoot: string, - name: string, - values: Values -): Promise> { +async function collectDefaults(repoRoot: string, name: string): Promise> { const defaults = new Map(); for (const relativeFile of trackedEnvFiles(repoRoot)) { const decision = ( @@ -99,19 +95,26 @@ async function collectDefaults( const suggested = relativeFile === 'apps/web/.env' ? '' : `invalid-${name.toLowerCase()}`; const answer = await question(`Safe default for ${relativeFile} [${suggested}] `); const value = answer || suggested; - if (Object.values(values).includes(value)) { - throw new Error(`The default for ${relativeFile} matches a real environment value.`); - } defaults.set(relativeFile, value); } return defaults; } -function assertSecretsAreNotTracked(repoRoot: string, values: Values): void { +function warnAboutMatchingTrackedValues( + repoRoot: string, + values: Values, + defaults: Map +): void { for (const relativeFile of trackedEnvFiles(repoRoot)) { const content = readFileSync(path.join(repoRoot, relativeFile), 'utf8'); - if (Object.values(values).some(value => content.includes(value))) { - throw new Error(`A real environment value appears in tracked file ${relativeFile}.`); + const defaultValue = defaults.get(relativeFile); + const matchesRemoteValue = Object.values(values).some( + value => content.includes(value) || defaultValue === value + ); + if (matchesRemoteValue) { + console.warn( + `\x1b[1;33mWARNING:\x1b[0m ${relativeFile} contains or will contain a value also used in a remote environment. This may be intentional.` + ); } } } @@ -127,7 +130,8 @@ async function main(): Promise { const contexts = resolveVercelContexts(tempDirectory); const vaultId = sensitive ? resolveVault() : undefined; const values = await collectValues(options); - const defaults = await collectDefaults(repoRoot, options.name, values); + const defaults = await collectDefaults(repoRoot, options.name); + warnAboutMatchingTrackedValues(repoRoot, values, defaults); console.log('\nPlan'); for (const environment of ENVIRONMENTS) { @@ -151,7 +155,6 @@ async function main(): Promise { for (const [relativeFile, value] of defaults) { setEnvDefault(path.join(repoRoot, relativeFile), options.name, value); } - assertSecretsAreNotTracked(repoRoot, values); for (const environment of ENVIRONMENTS) { for (const context of contexts) { From 96646f4ee7ddbc4ee0ff20282cd1b63ca6d34b38 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:26:50 +0200 Subject: [PATCH 09/22] fix(web): show 1Password command failures --- scripts/web-env/shared.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index df24fab42..b1cea3fe4 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -56,9 +56,15 @@ export function run( maxBuffer: 10 * 1024 * 1024, }); if (result.status !== 0) { - throw new Error( - `${command} ${args.slice(0, 3).join(' ')} failed; provider output was redacted.` - ); + const operation = `${command} ${args.slice(0, 3).join(' ')}`; + if (command === 'op') { + const output = [result.stderr, result.stdout, result.error?.message] + .filter(Boolean) + .join('\n') + .trim(); + throw new Error(`${operation} failed${output ? `:\n${output}` : '.'}`); + } + throw new Error(`${operation} failed; provider output was redacted.`); } return result.stdout; } From fe11443f30ca5438bfb1b8998768fe8279634ebd Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:32:19 +0200 Subject: [PATCH 10/22] fix(web): create 1Password items from stdin template --- scripts/web-env/shared.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index b1cea3fe4..ec6f79fdc 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -209,9 +209,25 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi const item = { title: name, category: 'PASSWORD', - fields: [{ id: 'password', label: 'password', type: 'CONCEALED', value }], + fields: [ + { + id: 'password', + label: 'password', + type: 'CONCEALED', + purpose: 'PASSWORD', + value, + }, + { + id: 'notesPlain', + label: 'notesPlain', + type: 'STRING', + purpose: 'NOTES', + value: '', + }, + ], + sections: [], }; - run('op', ['item', 'create', '--vault', vaultId, '--format=json', '-'], { + run('op', ['item', 'create', '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { input: JSON.stringify(item), }); return; From e1c69d3fbd6516f3202afb892b4d423a95f5abff Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:44:17 +0200 Subject: [PATCH 11/22] fix(web): let 1Password prompt for sign-in --- DEVELOPMENT.md | 2 +- scripts/web-env/shared.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a169048ae..75fc26a24 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -161,7 +161,7 @@ pnpm web:env set EXAMPLE_API_TOKEN Prerequisites: - Sign in with `vercel login` and have access to both projects in the `kilocode` scope. -- Sign in with `op signin` and have write access to the `Kilo Web ENV Production` vault. +- Install the 1Password CLI and have write access to the `Kilo Web ENV Production` vault. If needed, the CLI prompts you to sign in with Touch ID. - Have `pnpm` available; the command runs the pinned Vercel CLI with `pnpm dlx`. The command asks whether the variable is sensitive, defaulting to yes. Sensitive Production and Staging values use Vercel's sensitive type, while Development remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index ec6f79fdc..c9748e9b2 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -187,7 +187,6 @@ export function pullValue( } export function resolveVault(): string { - run('op', ['whoami', '--format=json']); const vault = parseJson(run('op', ['vault', 'get', VAULT, '--format=json']), 'Resolve vault'); const vaultId = stringValue(vault, 'id'); if (!vaultId) throw new Error(`Could not resolve 1Password vault ${VAULT}.`); From 2c2f2cad53cb7a6b093aff19c56fde0cb27ac37e Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:51:10 +0200 Subject: [PATCH 12/22] fix(web): default env file prompts to skip --- DEVELOPMENT.md | 2 +- scripts/web-env/index.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 75fc26a24..a0aa8ce50 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -168,7 +168,7 @@ The command asks whether the variable is sensitive, defaulting to yes. Sensitive Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. +The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. Pressing Return selects skip. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index 6b4831ca4..b1329524f 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -86,11 +86,11 @@ async function collectValues(options: Options): Promise { async function collectDefaults(repoRoot: string, name: string): Promise> { const defaults = new Map(); for (const relativeFile of trackedEnvFiles(repoRoot)) { - const decision = ( - await question(`${relativeFile}: set a safe default or skip? [set/skip] `) - ).trim(); - if (decision === 'skip') continue; - if (decision && decision !== 'set') throw new Error('Answer set or skip.'); + const decision = (await question(`${relativeFile}: set a safe default or skip? [set/Skip] `)) + .trim() + .toLowerCase(); + if (!decision || decision === 'skip') continue; + if (decision !== 'set') throw new Error('Answer set or skip.'); const suggested = relativeFile === 'apps/web/.env' ? '' : `invalid-${name.toLowerCase()}`; const answer = await question(`Safe default for ${relativeFile} [${suggested}] `); From 5eb9253a4f94e7806096908cbc7469b84fd4b97c Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 08:56:16 +0200 Subject: [PATCH 13/22] fix(web): warn when env defaults are skipped --- DEVELOPMENT.md | 2 +- scripts/web-env/index.ts | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a0aa8ce50..bd851124a 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -168,7 +168,7 @@ The command asks whether the variable is sensitive, defaulting to yes. Sensitive Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. Pressing Return selects skip. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. +The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. Pressing Return selects skip. If every file is skipped, the command warns that the application must work without the variable so external contributors can still run it. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index b1329524f..a93aaced0 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -100,6 +100,19 @@ async function collectDefaults(repoRoot: string, name: string): Promise { const vaultId = sensitive ? resolveVault() : undefined; const values = await collectValues(options); const defaults = await collectDefaults(repoRoot, options.name); + if (defaults.size === 0) warnAboutMissingTrackedDefault(options.name); warnAboutMatchingTrackedValues(repoRoot, values, defaults); console.log('\nPlan'); From f4008347cc9af38ccc6c801d0a5e403f5daf7152 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 09:02:10 +0200 Subject: [PATCH 14/22] fix(web): streamline env default prompts --- DEVELOPMENT.md | 2 +- scripts/web-env/index.ts | 48 +++++++++++++++++++++++---------------- scripts/web-env/shared.ts | 7 +++++- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index bd851124a..0d4cfd3b6 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -168,7 +168,7 @@ The command asks whether the variable is sensitive, defaulting to yes. Sensitive Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for single-line values without echoing them, then asks for a safe default or skip decision for each tracked root and `apps/web` dotenv file. Pressing Return selects skip. If every file is skipped, the command warns that the application must work without the variable so external contributors can still run it. If a tracked value matches a remote value, the command highlights the collision but allows it. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. +The command prompts for single-line values without echoing them, then asks for a default value for each tracked root and `apps/web` dotenv file. Enter a value directly, or press Return to skip that file. If every file is skipped, the command warns that the application must work without the variable so external contributors can still run it. If a tracked value matches a remote value, the command highlights the collision but allows it. Invalid yes/no answers and empty remote values are prompted again instead of terminating the command. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index a93aaced0..13c66e3c1 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -61,24 +61,37 @@ function parseOptions(args: string[]): Options { } async function askSensitivity(name: string): Promise { - const answer = (await question(`Is ${name} sensitive? [Y/n] `)).trim().toLowerCase(); - if (!['', 'y', 'yes', 'n', 'no'].includes(answer)) throw new Error('Answer yes or no.'); - const sensitive = !['n', 'no'].includes(answer); - if (sensitive && name.startsWith('NEXT_PUBLIC_')) { - throw new Error('NEXT_PUBLIC_* values are browser-visible; answer no.'); + while (true) { + const answer = (await question(`Is ${name} sensitive? [Y/n] `)).trim().toLowerCase(); + if (!['', 'y', 'yes', 'n', 'no'].includes(answer)) { + console.warn('Please answer yes or no.'); + continue; + } + const sensitive = !['n', 'no'].includes(answer); + if (sensitive && name.startsWith('NEXT_PUBLIC_')) { + console.warn('NEXT_PUBLIC_* values are browser-visible; answer no.'); + continue; + } + return sensitive; } - return sensitive; } async function collectValues(options: Options): Promise { const values: Partial = {}; for (const environment of ENVIRONMENTS) { const file = options.valueFiles[environment]; - const value = file - ? readFileSync(path.resolve(file), 'utf8') - : await readSecret(`${environment} value: `); - if (!value) throw new Error(`${environment} value cannot be empty.`); - values[environment] = value; + if (file) { + const value = readFileSync(path.resolve(file), 'utf8'); + if (!value) throw new Error(`${environment} value file cannot be empty.`); + values[environment] = value; + continue; + } + + while (!values[environment]) { + const value = await readSecret(`${environment} value: `); + if (value) values[environment] = value; + else console.warn(`${environment} value cannot be empty. Please try again.`); + } } return values as Values; } @@ -86,15 +99,10 @@ async function collectValues(options: Options): Promise { async function collectDefaults(repoRoot: string, name: string): Promise> { const defaults = new Map(); for (const relativeFile of trackedEnvFiles(repoRoot)) { - const decision = (await question(`${relativeFile}: set a safe default or skip? [set/Skip] `)) - .trim() - .toLowerCase(); - if (!decision || decision === 'skip') continue; - if (decision !== 'set') throw new Error('Answer set or skip.'); - - const suggested = relativeFile === 'apps/web/.env' ? '' : `invalid-${name.toLowerCase()}`; - const answer = await question(`Safe default for ${relativeFile} [${suggested}] `); - const value = answer || suggested; + const value = await question( + `${relativeFile}: default value for ${name} (press Return to skip): ` + ); + if (!value) continue; defaults.set(relativeFile, value); } return defaults; diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index c9748e9b2..8404fb832 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -301,7 +301,12 @@ export function question(prompt: string): Promise { } export async function confirm(prompt: string): Promise { - return ['y', 'yes'].includes((await question(`${prompt} [y/N] `)).trim().toLowerCase()); + while (true) { + const answer = (await question(`${prompt} [y/N] `)).trim().toLowerCase(); + if (!answer || answer === 'n' || answer === 'no') return false; + if (answer === 'y' || answer === 'yes') return true; + console.warn('Please answer yes or no.'); + } } export function readSecret(prompt: string): Promise { From 53d76d8bae434e766c8881f1d80bbcb6af7b32a3 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 09:17:13 +0200 Subject: [PATCH 15/22] feat(web): record env updater in 1Password notes --- DEVELOPMENT.md | 2 +- scripts/web-env/shared.ts | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 0d4cfd3b6..26b1897cc 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -164,7 +164,7 @@ Prerequisites: - Install the 1Password CLI and have write access to the `Kilo Web ENV Production` vault. If needed, the CLI prompts you to sign in with Touch ID. - Have `pnpm` available; the command runs the pinned Vercel CLI with `pnpm dlx`. -The command asks whether the variable is sensitive, defaulting to yes. Sensitive Production and Staging values use Vercel's sensitive type, while Development remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`. +The command asks whether the variable is sensitive, defaulting to yes. Sensitive Production and Staging values use Vercel's sensitive type, while Development remains encrypted but exportable through `vercel env pull`. The Production value is also stored as a concealed, exact-name item in `Kilo Web ENV Production`; its notes identify the local user and computer that last updated it. Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index 8404fb832..e6b44af44 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -1,5 +1,6 @@ import { spawnSync } from 'node:child_process'; import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; import path from 'node:path'; import * as readline from 'node:readline'; @@ -202,7 +203,37 @@ function findVaultItem(vaultId: string, name: string): JsonRecord | undefined { return matches[0]; } +const AUDIT_NOTE_PREFIX = 'Managed by pnpm web:env. Last updated by '; + +function auditNote(): string { + return `${AUDIT_NOTE_PREFIX}${os.userInfo().username} on ${os.hostname()} at ${new Date().toISOString()}.`; +} + +function setAuditNote(item: JsonRecord, note: string): void { + const fields = item.fields; + if (!Array.isArray(fields)) throw new Error('1Password item does not have editable fields.'); + const notes = records(fields).find(field => field.id === 'notesPlain'); + if (!notes) { + fields.push({ + id: 'notesPlain', + label: 'notesPlain', + type: 'STRING', + purpose: 'NOTES', + value: note, + }); + return; + } + const existing = stringValue(notes, 'value') ?? ''; + const preserved = existing + .split('\n') + .filter(line => !line.startsWith(AUDIT_NOTE_PREFIX)) + .join('\n') + .trimEnd(); + notes.value = preserved ? `${preserved}\n${note}` : note; +} + export function setVaultValue(vaultId: string, name: string, value: string): void { + const note = auditNote(); const existing = findVaultItem(vaultId, name); if (!existing) { const item = { @@ -221,7 +252,7 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi label: 'notesPlain', type: 'STRING', purpose: 'NOTES', - value: '', + value: note, }, ], sections: [], @@ -243,6 +274,7 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi throw new Error(`1Password item ${name} does not have a concealed password field.`); } password.value = value; + setAuditNote(item, note); run('op', ['item', 'edit', id, '--vault', vaultId, '--format=json'], { input: JSON.stringify(item), }); From 3044f7d46b99128af33d56981ec7663dd83a3022 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 09:40:12 +0200 Subject: [PATCH 16/22] perf(web): trust fixed Vercel env targets --- scripts/web-env/shared.ts | 44 ++++++--------------------------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index e6b44af44..ccc71ca76 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -13,9 +13,7 @@ export type Environment = (typeof ENVIRONMENTS)[number]; export type Values = Record; export type VercelContext = { project: Project; - projectId: string; orgId: string; - stagingId: string; cwd: string; }; @@ -70,11 +68,7 @@ export function run( return result.stdout; } -function vercel( - context: Pick | undefined, - args: string[], - input?: string -): string { +function vercel(context: VercelContext | undefined, args: string[], input?: string): string { return run( 'pnpm', [ @@ -93,7 +87,7 @@ function vercel( ? { ...process.env, VERCEL_ORG_ID: context.orgId, - VERCEL_PROJECT_ID: context.projectId, + VERCEL_PROJECT_ID: context.project, } : process.env, input, @@ -109,26 +103,7 @@ export function resolveVercelContexts(tempDirectory: string): VercelContext[] { throw new Error('Sign in to the kilocode Vercel team with `vercel login`.'); } - return PROJECTS.map(project => { - const projectList = parseJson( - vercel(undefined, ['project', 'list', '--filter', project, '--format=json']), - `Resolve ${project}` - ); - const match = records(projectList.projects).find(candidate => candidate.name === project); - const projectId = match ? stringValue(match, 'id') : undefined; - if (!projectId) throw new Error(`Could not resolve Vercel project ${project}.`); - - const base = { project, projectId, orgId, cwd: tempDirectory }; - const targetList = parseJson(vercel(base, ['target', 'list', '--format=json']), 'List targets'); - const staging = records(targetList.targets).find(candidate => candidate.slug === 'staging'); - const stagingId = staging ? stringValue(staging, 'id') : undefined; - if (!stagingId) throw new Error(`${project} does not have a custom staging environment.`); - return { ...base, stagingId }; - }); -} - -function target(context: VercelContext, environment: Environment): string { - return environment === 'staging' ? context.stagingId : environment; + return PROJECTS.map(project => ({ project, orgId, cwd: tempDirectory })); } export function listVariables( @@ -136,7 +111,7 @@ export function listVariables( environment: Environment ): Map { const response = parseJson( - vercel(context, ['env', 'list', target(context, environment), '--format=json']), + vercel(context, ['env', 'list', environment, '--format=json']), `List ${context.project}/${environment}` ); return new Map( @@ -160,20 +135,13 @@ export function setVariable( 'env', 'add', name, - target(context, environment), + environment, '--force', shouldBeSensitive ? '--sensitive' : '--no-sensitive', '--yes', ], value ); - const type = listVariables(context, environment).get(name); - const expected = shouldBeSensitive ? 'sensitive' : 'encrypted'; - if (type !== expected) { - throw new Error( - `${context.project}/${environment} has type ${type ?? 'missing'}, expected ${expected}.` - ); - } } export function pullValue( @@ -181,7 +149,7 @@ export function pullValue( environment: Environment, name: string ): string | undefined { - const endpoint = `/v3/env/pull/${encodeURIComponent(context.projectId)}/${encodeURIComponent(target(context, environment))}?source=vercel-cli%3Aenv%3Apull`; + const endpoint = `/v3/env/pull/${encodeURIComponent(context.project)}/${encodeURIComponent(environment)}?source=vercel-cli%3Aenv%3Apull`; const response = parseJson(vercel(context, ['api', endpoint, '--raw']), 'Pull Vercel values'); const values = isRecord(response.env) ? response.env : undefined; return values && typeof values[name] === 'string' ? values[name] : undefined; From b022c03a1916cf336b1618effe929241367fa642 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 09:43:33 +0200 Subject: [PATCH 17/22] fix(web): persist 1Password item updates --- scripts/web-env/shared.ts | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index ccc71ca76..17261c99b 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -225,9 +225,17 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi ], sections: [], }; - run('op', ['item', 'create', '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { - input: JSON.stringify(item), - }); + const created = parseJson( + run('op', ['item', 'create', '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { + input: JSON.stringify(item), + }), + `Create ${name}` + ); + const createdPassword = records(created.fields).find(field => field.id === 'password'); + const createdNotes = records(created.fields).find(field => field.id === 'notesPlain'); + if (createdPassword?.value !== value || createdNotes?.value !== note) { + throw new Error(`1Password did not persist the new ${name} value and audit note.`); + } return; } @@ -243,9 +251,21 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi } password.value = value; setAuditNote(item, note); - run('op', ['item', 'edit', id, '--vault', vaultId, '--format=json'], { - input: JSON.stringify(item), - }); + const expectedNotes = stringValue( + records(item.fields).find(field => field.id === 'notesPlain') ?? {}, + 'value' + ); + const updated = parseJson( + run('op', ['item', 'edit', id, '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { + input: JSON.stringify(item), + }), + `Update ${name}` + ); + const updatedPassword = records(updated.fields).find(field => field.id === 'password'); + const updatedNotes = records(updated.fields).find(field => field.id === 'notesPlain'); + if (updatedPassword?.value !== value || updatedNotes?.value !== expectedNotes) { + throw new Error(`1Password did not persist the updated ${name} value and audit note.`); + } } export function findRepoRoot(): string { From 34ad7e1368aa748d5e6ed49f2d005a63674a1064 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 11:22:09 +0200 Subject: [PATCH 18/22] perf(web): batch backfill environment reads --- scripts/web-env/backfill.ts | 27 ++++++++++++++++++--------- scripts/web-env/shared.ts | 13 +++++++------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts index 30e488011..9d760ff14 100644 --- a/scripts/web-env/backfill.ts +++ b/scripts/web-env/backfill.ts @@ -5,7 +5,7 @@ import { PROJECTS, confirm, listVariables, - pullValue, + pullValues, resolveVault, resolveVercelContexts, setVariable, @@ -29,6 +29,9 @@ async function main(): Promise { const contexts = resolveVercelContexts(tempDirectory); const vaultId = resolveVault(); const production = contexts.map(context => listVariables(context, 'production')); + const staging = contexts.map(context => listVariables(context, 'staging')); + const productionValues = contexts.map(context => pullValues(context, 'production')); + const stagingValues = contexts.map(context => pullValues(context, 'staging')); const names = [...new Set(production.flatMap(variables => [...variables.keys()]))].sort(); for (const name of names) { @@ -43,29 +46,35 @@ async function main(): Promise { continue; } - const productionValues = contexts.map(context => pullValue(context, 'production', name)); - if (!productionValues[0] || productionValues.some(value => value !== productionValues[0])) { + const projectProductionValues = productionValues.map(values => values.get(name)); + if ( + !projectProductionValues[0] || + projectProductionValues.some(value => value !== projectProductionValues[0]) + ) { unresolved.push(`${name} (Production values differ)`); continue; } - const stagingTypes = contexts.map(context => listVariables(context, 'staging').get(name)); + const stagingTypes = staging.map(variables => variables.get(name)); let stagingValue: string | undefined; if (stagingTypes.every(type => type === 'sensitive')) { stagingValue = undefined; } else { - const stagingValues = contexts.map(context => pullValue(context, 'staging', name)); - if (!stagingValues[0] || stagingValues.some(value => value !== stagingValues[0])) { + const projectStagingValues = stagingValues.map(values => values.get(name)); + if ( + !projectStagingValues[0] || + projectStagingValues.some(value => value !== projectStagingValues[0]) + ) { unresolved.push(`${name} (Staging values differ or are unavailable)`); continue; } - stagingValue = stagingValues[0]; + stagingValue = projectStagingValues[0]; } console.log(`Migrating ${name}...`); - setVaultValue(vaultId, name, productionValues[0]); + setVaultValue(vaultId, name, projectProductionValues[0]); for (const context of contexts) { - setVariable(context, 'production', name, productionValues[0], true); + setVariable(context, 'production', name, projectProductionValues[0], true); } if (stagingValue) { for (const context of contexts) setVariable(context, 'staging', name, stagingValue, true); diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index 17261c99b..fbee4e967 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -144,15 +144,16 @@ export function setVariable( ); } -export function pullValue( - context: VercelContext, - environment: Environment, - name: string -): string | undefined { +export function pullValues(context: VercelContext, environment: Environment): Map { const endpoint = `/v3/env/pull/${encodeURIComponent(context.project)}/${encodeURIComponent(environment)}?source=vercel-cli%3Aenv%3Apull`; const response = parseJson(vercel(context, ['api', endpoint, '--raw']), 'Pull Vercel values'); const values = isRecord(response.env) ? response.env : undefined; - return values && typeof values[name] === 'string' ? values[name] : undefined; + if (!values) throw new Error(`Could not pull ${context.project}/${environment} values.`); + return new Map( + Object.entries(values).filter( + (entry): entry is [string, string] => typeof entry[1] === 'string' + ) + ); } export function resolveVault(): string { From 15272e4154a04c07db1db77e536229f8e0ff0309 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 11:24:42 +0200 Subject: [PATCH 19/22] feat(web): default env backfill to dry run --- scripts/web-env/backfill.ts | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts index 9d760ff14..947bc8a4d 100644 --- a/scripts/web-env/backfill.ts +++ b/scripts/web-env/backfill.ts @@ -13,9 +13,15 @@ import { } from './shared.js'; async function main(): Promise { - if ( - !(await confirm('Backfill readable Production secrets into 1Password and mark them sensitive?')) - ) { + const args = process.argv.slice(2); + if (args.some(argument => argument !== '--apply')) { + throw new Error('Usage: tsx scripts/web-env/backfill.ts [--apply]'); + } + const apply = args.includes('--apply'); + if (!apply) { + console.log('DRY RUN: no 1Password or Vercel values will be changed.'); + } + if (!(await confirm(`${apply ? 'Run' : 'Preview'} the Production secret backfill?`))) { console.log('Cancelled.'); return; } @@ -27,7 +33,7 @@ async function main(): Promise { try { const contexts = resolveVercelContexts(tempDirectory); - const vaultId = resolveVault(); + const vaultId = apply ? resolveVault() : undefined; const production = contexts.map(context => listVariables(context, 'production')); const staging = contexts.map(context => listVariables(context, 'staging')); const productionValues = contexts.map(context => pullValues(context, 'production')); @@ -71,19 +77,22 @@ async function main(): Promise { stagingValue = projectStagingValues[0]; } - console.log(`Migrating ${name}...`); - setVaultValue(vaultId, name, projectProductionValues[0]); - for (const context of contexts) { - setVariable(context, 'production', name, projectProductionValues[0], true); - } - if (stagingValue) { - for (const context of contexts) setVariable(context, 'staging', name, stagingValue, true); + console.log(`${apply ? 'Migrating' : 'Would migrate'} ${name}...`); + if (apply) { + if (!vaultId) throw new Error('Could not resolve the 1Password vault.'); + setVaultValue(vaultId, name, projectProductionValues[0]); + for (const context of contexts) { + setVariable(context, 'production', name, projectProductionValues[0], true); + } + if (stagingValue) { + for (const context of contexts) setVariable(context, 'staging', name, stagingValue, true); + } } migrated.push(name); } } finally { rmSync(tempDirectory, { recursive: true, force: true }); - console.log('\nMigrated:'); + console.log(`\n${apply ? 'Migrated' : 'Would migrate'}:`); console.log(migrated.length ? migrated.map(name => `- ${name}`).join('\n') : '- None'); console.log('\nUnresolved:'); console.log(unresolved.length ? unresolved.map(name => `- ${name}`).join('\n') : '- None'); @@ -91,6 +100,9 @@ async function main(): Promise { console.log(skipped.length ? skipped.map(name => `- ${name}`).join('\n') : '- None'); console.log(`\nProjects checked: ${PROJECTS.join(', ')}`); } + if (!apply) { + console.log('\nDry run complete. Re-run with --apply to perform the migration.'); + } } main().catch(error => { From 556e255d0dba41437010f0560b6cd5315ad446e6 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 11:45:15 +0200 Subject: [PATCH 20/22] fix(web): limit env backfill to Production --- scripts/web-env/backfill.ts | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts index 947bc8a4d..ddab869ae 100644 --- a/scripts/web-env/backfill.ts +++ b/scripts/web-env/backfill.ts @@ -35,9 +35,7 @@ async function main(): Promise { const contexts = resolveVercelContexts(tempDirectory); const vaultId = apply ? resolveVault() : undefined; const production = contexts.map(context => listVariables(context, 'production')); - const staging = contexts.map(context => listVariables(context, 'staging')); const productionValues = contexts.map(context => pullValues(context, 'production')); - const stagingValues = contexts.map(context => pullValues(context, 'staging')); const names = [...new Set(production.flatMap(variables => [...variables.keys()]))].sort(); for (const name of names) { @@ -61,38 +59,21 @@ async function main(): Promise { continue; } - const stagingTypes = staging.map(variables => variables.get(name)); - let stagingValue: string | undefined; - if (stagingTypes.every(type => type === 'sensitive')) { - stagingValue = undefined; - } else { - const projectStagingValues = stagingValues.map(values => values.get(name)); - if ( - !projectStagingValues[0] || - projectStagingValues.some(value => value !== projectStagingValues[0]) - ) { - unresolved.push(`${name} (Staging values differ or are unavailable)`); - continue; - } - stagingValue = projectStagingValues[0]; - } - - console.log(`${apply ? 'Migrating' : 'Would migrate'} ${name}...`); + console.log( + `${apply ? 'Adding' : 'Would add'} ${name} to 1Password and mark Production sensitive...` + ); if (apply) { if (!vaultId) throw new Error('Could not resolve the 1Password vault.'); setVaultValue(vaultId, name, projectProductionValues[0]); for (const context of contexts) { setVariable(context, 'production', name, projectProductionValues[0], true); } - if (stagingValue) { - for (const context of contexts) setVariable(context, 'staging', name, stagingValue, true); - } } migrated.push(name); } } finally { rmSync(tempDirectory, { recursive: true, force: true }); - console.log(`\n${apply ? 'Migrated' : 'Would migrate'}:`); + console.log(`\n${apply ? 'Migrated' : 'Would migrate'} Production secrets:`); console.log(migrated.length ? migrated.map(name => `- ${name}`).join('\n') : '- None'); console.log('\nUnresolved:'); console.log(unresolved.length ? unresolved.map(name => `- ${name}`).join('\n') : '- None'); From 735fb05d4bc8f1a4eb2798c5c6ca58fa633175a8 Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 12:14:48 +0200 Subject: [PATCH 21/22] chore(web): remove completed env backfill --- scripts/web-env/backfill.ts | 92 ------------------------------------- scripts/web-env/shared.ts | 27 ----------- 2 files changed, 119 deletions(-) delete mode 100644 scripts/web-env/backfill.ts diff --git a/scripts/web-env/backfill.ts b/scripts/web-env/backfill.ts deleted file mode 100644 index ddab869ae..000000000 --- a/scripts/web-env/backfill.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import { - PROJECTS, - confirm, - listVariables, - pullValues, - resolveVault, - resolveVercelContexts, - setVariable, - setVaultValue, -} from './shared.js'; - -async function main(): Promise { - const args = process.argv.slice(2); - if (args.some(argument => argument !== '--apply')) { - throw new Error('Usage: tsx scripts/web-env/backfill.ts [--apply]'); - } - const apply = args.includes('--apply'); - if (!apply) { - console.log('DRY RUN: no 1Password or Vercel values will be changed.'); - } - if (!(await confirm(`${apply ? 'Run' : 'Preview'} the Production secret backfill?`))) { - console.log('Cancelled.'); - return; - } - - const tempDirectory = mkdtempSync(path.join(os.tmpdir(), 'kilo-web-env-backfill-')); - const migrated: string[] = []; - const unresolved: string[] = []; - const skipped: string[] = []; - - try { - const contexts = resolveVercelContexts(tempDirectory); - const vaultId = apply ? resolveVault() : undefined; - const production = contexts.map(context => listVariables(context, 'production')); - const productionValues = contexts.map(context => pullValues(context, 'production')); - const names = [...new Set(production.flatMap(variables => [...variables.keys()]))].sort(); - - for (const name of names) { - const types = production.map(variables => variables.get(name)); - if (types.includes('system')) continue; - if (types.some(type => !type) || types.includes('sensitive')) { - unresolved.push(`${name} (missing or already sensitive)`); - continue; - } - if (!(await confirm(`Treat ${name} as a secret?`))) { - skipped.push(name); - continue; - } - - const projectProductionValues = productionValues.map(values => values.get(name)); - if ( - !projectProductionValues[0] || - projectProductionValues.some(value => value !== projectProductionValues[0]) - ) { - unresolved.push(`${name} (Production values differ)`); - continue; - } - - console.log( - `${apply ? 'Adding' : 'Would add'} ${name} to 1Password and mark Production sensitive...` - ); - if (apply) { - if (!vaultId) throw new Error('Could not resolve the 1Password vault.'); - setVaultValue(vaultId, name, projectProductionValues[0]); - for (const context of contexts) { - setVariable(context, 'production', name, projectProductionValues[0], true); - } - } - migrated.push(name); - } - } finally { - rmSync(tempDirectory, { recursive: true, force: true }); - console.log(`\n${apply ? 'Migrated' : 'Would migrate'} Production secrets:`); - console.log(migrated.length ? migrated.map(name => `- ${name}`).join('\n') : '- None'); - console.log('\nUnresolved:'); - console.log(unresolved.length ? unresolved.map(name => `- ${name}`).join('\n') : '- None'); - console.log('\nSkipped:'); - console.log(skipped.length ? skipped.map(name => `- ${name}`).join('\n') : '- None'); - console.log(`\nProjects checked: ${PROJECTS.join(', ')}`); - } - if (!apply) { - console.log('\nDry run complete. Re-run with --apply to perform the migration.'); - } -} - -main().catch(error => { - console.error(error instanceof Error ? error.message : 'Backfill failed.'); - process.exitCode = 1; -}); diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index fbee4e967..9edfb8152 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -106,21 +106,6 @@ export function resolveVercelContexts(tempDirectory: string): VercelContext[] { return PROJECTS.map(project => ({ project, orgId, cwd: tempDirectory })); } -export function listVariables( - context: VercelContext, - environment: Environment -): Map { - const response = parseJson( - vercel(context, ['env', 'list', environment, '--format=json']), - `List ${context.project}/${environment}` - ); - return new Map( - records(response.envs) - .map(variable => [stringValue(variable, 'key'), stringValue(variable, 'type')] as const) - .filter((entry): entry is [string, string] => Boolean(entry[0] && entry[1])) - ); -} - export function setVariable( context: VercelContext, environment: Environment, @@ -144,18 +129,6 @@ export function setVariable( ); } -export function pullValues(context: VercelContext, environment: Environment): Map { - const endpoint = `/v3/env/pull/${encodeURIComponent(context.project)}/${encodeURIComponent(environment)}?source=vercel-cli%3Aenv%3Apull`; - const response = parseJson(vercel(context, ['api', endpoint, '--raw']), 'Pull Vercel values'); - const values = isRecord(response.env) ? response.env : undefined; - if (!values) throw new Error(`Could not pull ${context.project}/${environment} values.`); - return new Map( - Object.entries(values).filter( - (entry): entry is [string, string] => typeof entry[1] === 'string' - ) - ); -} - export function resolveVault(): string { const vault = parseJson(run('op', ['vault', 'get', VAULT, '--format=json']), 'Resolve vault'); const vaultId = stringValue(vault, 'id'); From 1cf082e5680d5dc47958389f8fc979cb4ea46d2d Mon Sep 17 00:00:00 2001 From: Remon Oldenbeuving Date: Wed, 17 Jun 2026 17:57:08 +0200 Subject: [PATCH 22/22] fix(web): harden environment value synchronization --- DEVELOPMENT.md | 2 +- scripts/web-env/index.ts | 36 +++++++++++++++++++++++++++--------- scripts/web-env/shared.ts | 4 ++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 26b1897cc..8b7ccf516 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -168,7 +168,7 @@ The command asks whether the variable is sensitive, defaulting to yes. Sensitive Answer no for public or otherwise non-secret configuration. `NEXT_PUBLIC_*` variables must be non-sensitive because Next.js exposes them to browsers. Non-sensitive values are not copied to 1Password. -The command prompts for single-line values without echoing them, then asks for a default value for each tracked root and `apps/web` dotenv file. Enter a value directly, or press Return to skip that file. If every file is skipped, the command warns that the application must work without the variable so external contributors can still run it. If a tracked value matches a remote value, the command highlights the collision but allows it. Invalid yes/no answers and empty remote values are prompted again instead of terminating the command. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. +The command prompts for single-line values without echoing them, then asks for a default value for each tracked root and `apps/web` dotenv file. Enter a value directly, or press Return to skip that file. If every file is skipped, the command warns that the application must work without the variable so external contributors can still run it. A tracked default cannot match a remote value; use a non-secret local default instead. Invalid yes/no answers and empty remote values are prompted again instead of terminating the command. For multiline values, use `--development-file`, `--staging-file`, and `--production-file`. Use `--dry-run` to preview the redacted plan. Remote updates are sequential rather than transactional. If a provider fails partway through, fix the problem and rerun the same command; it safely upserts every target. The workflow does not deploy, so trigger the appropriate deployment separately. diff --git a/scripts/web-env/index.ts b/scripts/web-env/index.ts index 13c66e3c1..ab7c31078 100644 --- a/scripts/web-env/index.ts +++ b/scripts/web-env/index.ts @@ -76,12 +76,19 @@ async function askSensitivity(name: string): Promise { } } +function normalizeFileValue(value: string): string { + const trailingNewlineLength = value.endsWith('\r\n') ? 2 : value.endsWith('\n') ? 1 : 0; + if (trailingNewlineLength === 0) return value; + const valueWithoutTrailingNewline = value.slice(0, -trailingNewlineLength); + return /[\r\n]/.test(valueWithoutTrailingNewline) ? value : valueWithoutTrailingNewline; +} + async function collectValues(options: Options): Promise { const values: Partial = {}; for (const environment of ENVIRONMENTS) { const file = options.valueFiles[environment]; if (file) { - const value = readFileSync(path.resolve(file), 'utf8'); + const value = normalizeFileValue(readFileSync(path.resolve(file), 'utf8')); if (!value) throw new Error(`${environment} value file cannot be empty.`); values[environment] = value; continue; @@ -121,20 +128,31 @@ ${border}\x1b[0m `); } -function warnAboutMatchingTrackedValues( +function assignmentValue(content: string, name: string): string | undefined { + const assignment = content.split('\n').find(line => line.startsWith(`${name}=`)); + if (!assignment) return undefined; + const value = assignment.slice(name.length + 1); + try { + const parsed: unknown = JSON.parse(value); + return typeof parsed === 'string' ? parsed : value; + } catch { + return value; + } +} + +function rejectMatchingTrackedValues( repoRoot: string, + name: string, values: Values, defaults: Map ): void { for (const relativeFile of trackedEnvFiles(repoRoot)) { const content = readFileSync(path.join(repoRoot, relativeFile), 'utf8'); - const defaultValue = defaults.get(relativeFile); - const matchesRemoteValue = Object.values(values).some( - value => content.includes(value) || defaultValue === value - ); + const trackedValue = defaults.get(relativeFile) ?? assignmentValue(content, name); + const matchesRemoteValue = Object.values(values).some(value => trackedValue === value); if (matchesRemoteValue) { - console.warn( - `\x1b[1;33mWARNING:\x1b[0m ${relativeFile} contains or will contain a value also used in a remote environment. This may be intentional.` + throw new Error( + `${relativeFile} contains or would contain a remote environment value. Use a non-secret local default instead.` ); } } @@ -153,7 +171,7 @@ async function main(): Promise { const values = await collectValues(options); const defaults = await collectDefaults(repoRoot, options.name); if (defaults.size === 0) warnAboutMissingTrackedDefault(options.name); - warnAboutMatchingTrackedValues(repoRoot, values, defaults); + rejectMatchingTrackedValues(repoRoot, options.name, values, defaults); console.log('\nPlan'); for (const environment of ENVIRONMENTS) { diff --git a/scripts/web-env/shared.ts b/scripts/web-env/shared.ts index 9edfb8152..9c7e27746 100644 --- a/scripts/web-env/shared.ts +++ b/scripts/web-env/shared.ts @@ -200,7 +200,7 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi sections: [], }; const created = parseJson( - run('op', ['item', 'create', '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { + run('op', ['item', 'create', '-', '--vault', vaultId, '--format=json'], { input: JSON.stringify(item), }), `Create ${name}` @@ -230,7 +230,7 @@ export function setVaultValue(vaultId: string, name: string, value: string): voi 'value' ); const updated = parseJson( - run('op', ['item', 'edit', id, '--template=/dev/stdin', '--vault', vaultId, '--format=json'], { + run('op', ['item', 'edit', id, '--vault', vaultId, '--format=json'], { input: JSON.stringify(item), }), `Update ${name}`