diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index ce73c361..84b1dd94 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -57,9 +57,11 @@ Garena gemini genai generativeai +genkit genproto glog gofmt +googleai gopkg gradletasknamecache gradlew @@ -169,6 +171,7 @@ Truelayer Trulioo udpa unmarshal +uuidv viewmodel vulnz Wallex diff --git a/.github/linters/.eslintrc.json b/.github/linters/.eslintrc.json new file mode 100644 index 00000000..c60a1857 --- /dev/null +++ b/.github/linters/.eslintrc.json @@ -0,0 +1,39 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "env": { + "node": true, + "es2022": true + }, + "rules": { + "@typescript-eslint/no-explicit-any": "error" + }, + "overrides": [ + { + "files": ["code/samples/**/*.ts"], + "parserOptions": { + "project": "./code/samples/typescript/tsconfig.json" + }, + "settings": { + "import/resolver": { + "typescript": { + "alwaysTryTypes": true, + "project": "./code/samples/typescript/tsconfig.json" + } + } + }, + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } + } + ] +} diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index fea1b9c1..3987af44 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -15,6 +15,15 @@ jobs: with: fetch-depth: 0 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install TypeScript Sample Dependencies + working-directory: code/samples/typescript + run: npm ci + - name: Lint Code Base uses: super-linter/super-linter/slim@v8 env: @@ -23,7 +32,7 @@ jobs: LOG_LEVEL: WARN SHELLCHECK_OPTS: -e SC1091 -e 2086 VALIDATE_ALL_CODEBASE: false - FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" + FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/(python|go|android|certs)/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" VALIDATE_BIOME_FORMAT: false VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_FLAKE8: false diff --git a/code/samples/typescript/.env.example b/code/samples/typescript/.env.example new file mode 100644 index 00000000..aaf46d93 --- /dev/null +++ b/code/samples/typescript/.env.example @@ -0,0 +1,10 @@ +# Copy this file to .env and fill in your own values. + +# --- Google AI Studio (Option 1, recommended for development) --- +# Obtain a key from https://aistudio.google.com/apikey +GOOGLE_API_KEY=your_google_api_key_here + +# --- Vertex AI (Option 2, recommended for production) --- +# GOOGLE_GENAI_USE_VERTEXAI=true +# GOOGLE_CLOUD_PROJECT=your-project-id +# GOOGLE_CLOUD_LOCATION=global diff --git a/code/samples/typescript/.gitignore b/code/samples/typescript/.gitignore new file mode 100644 index 00000000..80082e8c --- /dev/null +++ b/code/samples/typescript/.gitignore @@ -0,0 +1,32 @@ +# Dependencies +node_modules/ + +# Build output +dist/ + +# Environment +.env +.env.* +!.env.example + +# Source maps +*.js.map + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db + +# Test coverage +coverage/ + +# Debug logs +*.log + +# Runtime state +.temp-db/ +scenarios/**/.logs/ +scenarios/**/.temp-db/ diff --git a/code/samples/typescript/BACKLOG.md b/code/samples/typescript/BACKLOG.md new file mode 100644 index 00000000..1eaf2fa1 --- /dev/null +++ b/code/samples/typescript/BACKLOG.md @@ -0,0 +1,36 @@ +# Verifiable Intent TS integration — improvement backlog + +`improve-loop.sh` works ONE unchecked item at a time. Keep items small and +independently verifiable (`npx tsc --noEmit` + `npm run lint` + +`npx vitest run test/unit` all green). Check items off (`- [x]`) when done. + +> **Status (after 10 improve-loop iterations):** the unit-testable security + +> coverage + docs backlog is essentially complete — `src/common/vi` ≈96% stmts / +> 91% funcs, 30 unit tests, all gates green. The remaining open items below are +> **e2e-only** (need the running MCP/A2A servers + a Gemini key to fix *and* +> verify): payment-token↔checkout binding, replay/nonce dedup, checkout-side +> constraint enforcement, the MCP-tool-extraction refactor, and live validation +> of the item-id consent fix. These should be done in a fresh, bounded session +> with the servers running — not this unbounded unit-only loop. + +## Test coverage & hardening +- [x] Enable coverage: `@vitest/coverage-v8` + `test:coverage:unit` script + a coverage block in `vitest.config.ts` (scoped to `src/common/vi`). Baseline: **85.7% stmts / 82.5% branch / 73.9% funcs / 85.6% lines**. +- [x] **Coverage gap closed:** `keys.ts` now **100%** — round-trip persist/reload, per-role kids + fallback, legacy (no-kid) format, `loadViPublicJwk` missing→null + no private-scalar leak, and a persisted key signing a verifiable credential (`test/unit/vi-keys.test.ts`). Overall `src/common/vi` now **96.2% stmts / 91.3% funcs**. (`fixtures.ts` `getCatalog` still uncovered — minor.) +- [x] Strengthen `src/common/vi` negative-path tests: impostor-agent case (L3 signed by a non-delegated key whose kid matches but whose signature can't verify against L2 `cnf.jwk` → invalid) and tampered-L2 case (mutated L2 signature → invalid). In `test/unit/vi-chain-negative.test.ts`. +- [x] Add immediate-flow rejection tests: wrong issuer key, and an L2 whose `sd_hash` does not match L1 (verified against a different L1) → `verifyChain` invalid. In `test/unit/vi-chain-negative.test.ts`. +- [x] Constraint amount/currency boundaries: at-cap allowed, +1 minor unit rejected, currency mismatch rejected (`test/unit/vi-constraints.test.ts`). (Empty `acceptable_items` line-items wildcard still untested — minor.) + +## Make the MCP role logic testable without servers +- [ ] Extract the pure logic of merchant-agent-mcp `complete_checkout`, credentials-provider-mcp `issue_payment_credential`, and merchant `create_checkout` into small exported functions (no `McpServer`/stdio), and unit-test their happy + error paths against the persisted-file contract in a temp `TEMP_DB`. +- [x] Add a deterministic cross-role integration test via the persisted-file contract (`test/unit/vi-integration.test.ts`): agent writes `l1/l2/chk_*/pay_*` to a temp dir, merchant + network read them back and verify with aud pinning; asserts a valid purchase and an over-budget rejection. No Gemini/servers. (Tool-level tests of the actual `*.execute` handlers are still worth adding — see item above.) +- [~] **Gap (flow):** merchant MCP serves generated slug item ids (`_0`) but L2 `acceptable_items` defaulted to VI skus, so `createAgentFulfillment` couldn't match the item. **Mitigated (iter 7):** consent prompt now calls `search_inventory` FIRST and threads the resolved `item_id` into `assembleAndSignMandates` (REQUIRED), so L2 binds the exact merchant item. Prompt audit also confirmed all v2 prompts match the current tool signatures. **Still needs e2e validation** (prompt behavior isn't unit-verifiable); a `merchant-serves-VI-catalog` alternative remains an option. + +## Robustness +- [x] Pin `expectedL3*Aud` in the role `verifyChain` calls so a presentation addressed to a different party is rejected — merchant pins `MERCHANT_AUD`, CP pins `NETWORK_AUD`, agent stamps both via shared fixtures constants. Test in `test/unit/vi-chain-negative.test.ts`. +- [ ] Replay protection: verifiers don't pin nonce/`transaction_id`, and used payment tokens / mandates aren't deduped — the same authorization could be replayed. Track spent nonces/tokens across the role servers (the VI lib leaves replay to the caller) + add a test. +- [ ] **Gap (binding):** credentials-provider mints `pay_token_*` after verifying the payment chain, but the token isn't cryptographically bound to `checkout_jwt_hash`, and `complete_checkout` / the PSP don't re-verify the chain — a minted token could be presented for a different settlement. Bind the token to the checkout hash (and/or have the PSP re-verify) + add a test. +- [ ] **Gap (enforcement asymmetry, found iter 10):** `verifyCheckoutChain` (merchant) only verifies chain structure + aud — it does NOT run `checkConstraints` on the checkout-side constraints (`allowed_merchants`, `line_items`/`acceptable_items`); only `verifyPaymentChainAndConstraints` (network) enforces constraints (amount/payee). So the merchant trusts the agent's self-enforcement in `createAgentFulfillment` that the checked-out item is acceptable. Fix: enforce checkout constraints in the merchant path — decode the L3b `checkout_jwt` cart, resolve `acceptable_items` SD-refs, run `checkConstraints` (line_items max-flow). Needs careful design + e2e validation. +- [ ] `verifyPaymentChainAndConstraints`: surface a clear error when the issuer key is missing, and test it. + +## Docs +- [x] Add `src/common/vi/README.md` documenting the L1→L2→L3 flow (layer model, role→layer mapping diagram, file contract, public API, and the security properties the tests enforce). diff --git a/code/samples/typescript/README.md b/code/samples/typescript/README.md new file mode 100644 index 00000000..97af14e1 --- /dev/null +++ b/code/samples/typescript/README.md @@ -0,0 +1,74 @@ +# TypeScript Samples for the Agent Payments Protocol (AP2) + +This directory contains TypeScript samples demonstrating how to build AP2 +agents using the [Agent Development Kit (ADK)](https://google.github.io/adk-docs/) +and the [A2A SDK](https://www.npmjs.com/package/@a2a-js/sdk). + +## Available Scenarios + +- **[Human-Present Card Payment](./scenarios/a2a/human-present/cards/README.md)** + - Complete card payment flow with all four agents implemented in TypeScript. + +See the [scenario README](./scenarios/a2a/human-present/cards/README.md) for +detailed setup and usage instructions. + +## Why TypeScript for AP2 Agents? + +TypeScript is a natural fit for AP2 agents that are deployed alongside web, +Node.js, or edge runtimes: + +- **Type Safety**: Compile-time validation of protocol structures via Zod + schemas mirrored from the AP2 reference types. +- **Ecosystem**: Direct access to the npm ecosystem and the official + `@a2a-js/sdk` and `@google/adk` packages. +- **Portability**: Run on any Node.js 18+ runtime, including serverless and + container platforms. + +## Project Structure + +```text +code/samples/typescript/ +├── src/ +│ ├── roles/ # Agent role implementations and entry points +│ │ ├── shopping/ # Shopping Agent (root orchestrator) +│ │ │ └── subagents/ # shopper, shipping-collector, payment-collector +│ │ ├── merchant/ # Merchant Agent +│ │ ├── credentials-provider/ +│ │ └── payment-processor/ +│ └── common/ # Shared modules used across roles +│ ├── server/ # A2A server bootstrap, executor, middleware +│ ├── utils/ # Message and artifact helpers +│ ├── types/ # AP2 protocol object types +│ ├── schemas/ # Zod schemas mirroring the protocol +│ ├── vc/ # W3C Verifiable Credential helpers +│ ├── config/ # Session and runtime configuration +│ └── constants/ # Shared constants +├── test/ +│ └── e2e/ # End-to-end smoke tests +└── scenarios/ + └── a2a/ + └── human-present/ + └── cards/ # Card payment scenario +``` + +## Development + +```sh +# Install dependencies +npm install + +# Type-check and build +npm run build + +# Start all four agents plus the ADK web UI +npm run dev + +# Run the e2e smoke tests against running agents +npm test +``` + +See the scenario README for a full walkthrough. + +## License + +Copyright 2025 Google LLC. Licensed under the Apache License, Version 2.0. diff --git a/code/samples/typescript/eslint.config.js b/code/samples/typescript/eslint.config.js new file mode 100644 index 00000000..8188c131 --- /dev/null +++ b/code/samples/typescript/eslint.config.js @@ -0,0 +1,50 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import importPlugin from 'eslint-plugin-import'; +import globals from 'globals'; + +export default [ + { ignores: ['dist/**', 'node_modules/**', 'coverage/**'] }, + js.configs.recommended, + ...tseslint.configs.recommended, + { + files: ['src/**/*.ts', 'test/**/*.ts'], + languageOptions: { + ecmaVersion: 2022, + sourceType: 'module', + globals: { ...globals.node }, + parserOptions: { + project: './tsconfig.json', + }, + }, + plugins: { import: importPlugin }, + rules: { + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }, + ], + 'import/no-unresolved': 'off', + }, + }, +]; diff --git a/code/samples/typescript/improve-loop.prompt.md b/code/samples/typescript/improve-loop.prompt.md new file mode 100644 index 00000000..be22caa1 --- /dev/null +++ b/code/samples/typescript/improve-loop.prompt.md @@ -0,0 +1,35 @@ +# Autonomous improve + test loop — Verifiable Intent TypeScript integration + +You are running headless inside `code/samples/typescript` (the AP2 TypeScript +sample). Your job: make ONE small, fully-verified improvement per run that +hardens or tests the Verifiable Intent integration (`src/common/vi` and the role +wiring in `src/roles`). Then stop. + +## Procedure (do this exactly, once) + +1. Read `BACKLOG.md`. Choose the single highest-priority unchecked item `- [ ]`. + If every item is already checked, pick the most valuable NEW hardening/test + task you can find and add it. +2. Make a small, focused change. Strongly prefer ADDING or STRENGTHENING tests + over changing production code. If you change production code, it must be to + fix a real bug that a test now proves. +3. Verify — ALL of these must pass before you keep the change: + - `npx tsc --noEmit` (this sample has no `typecheck` script) + - `npm run lint` + - `npx vitest run test/unit` + Do NOT run `npm test` or anything in `test/e2e/` — e2e needs a live Gemini + API key and running servers, and will fail or hang here. +4. If green: tick the item in `BACKLOG.md` (`- [x]`), then `git add -A` and + `git commit -m "loop: "`. If you discovered new useful work, + append new `- [ ]` items to `BACKLOG.md`. +5. If you cannot get to green: run `git checkout -- .` to revert your changes, + leave the item unchecked, and append a short `blocked:` note under it. + +## Hard rules + +- Never delete, skip, weaken, or loosen an assertion just to make tests pass. +- Never edit files under `.git/`, `.github/`, `.claude/`, or the npm-linked + `node_modules/@verifiable-intent` package. Only touch this sample. +- Keep each change minimal and reversible. One backlog item per run, then stop. +- Amounts are in minor units (cents). Scenario fixtures live in + `src/common/vi/fixtures.ts`; the layer model lives in `src/common/vi/flow.ts`. diff --git a/code/samples/typescript/improve-loop.sh b/code/samples/typescript/improve-loop.sh new file mode 100755 index 00000000..a1a434da --- /dev/null +++ b/code/samples/typescript/improve-loop.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# +# Autonomous improve + test loop for the Verifiable Intent TS integration. +# +# Each iteration runs Claude Code headless against improve-loop.prompt.md, which +# completes ONE backlog item, verifies it (typecheck + lint + unit tests), and +# commits it. The loop stops when all gates are green AND BACKLOG.md has no +# unchecked items, or after MAX_ITERS iterations. +# +# Guardrails: --bare (no hooks/plugins), acceptEdits, a scoped tool allowlist +# (only npm/npx/git/node + file tools — no network), and a git commit per +# iteration so any step is one `git reset` away from rollback. e2e tests are +# never run here (they need a Gemini key + live servers). +# +# Usage: ./improve-loop.sh [max_iterations] # default 12 +# LOOP_MODEL=opus ./improve-loop.sh 5 # override model +# +set -uo pipefail +cd "$(dirname "$0")" + +MAX_ITERS="${1:-12}" +MODEL="${LOOP_MODEL:-sonnet}" +PROMPT_FILE="improve-loop.prompt.md" +ALLOWED="Read,Edit,Write,Glob,Grep,Bash(npm:*),Bash(npx:*),Bash(git:*),Bash(node:*)" + +if [ ! -f "$PROMPT_FILE" ]; then + echo "error: $PROMPT_FILE not found (run from code/samples/typescript)" >&2 + exit 1 +fi + +gates_green() { + npx tsc --noEmit >/dev/null 2>&1 \ + && npm run lint >/dev/null 2>&1 \ + && npx vitest run test/unit >/dev/null 2>&1 +} + +# No unchecked "- [ ]" items remain in the backlog. +backlog_done() { + ! grep -qE '^[[:space:]]*-[[:space:]]\[ \]' BACKLOG.md +} + +for i in $(seq 1 "$MAX_ITERS"); do + echo "──────────────────────────────────────────────────────────" + echo " iteration $i / $MAX_ITERS" + echo "──────────────────────────────────────────────────────────" + + claude --bare -p "$(cat "$PROMPT_FILE")" \ + --model "$MODEL" \ + --permission-mode acceptEdits \ + --allowedTools "$ALLOWED" + + if gates_green && backlog_done; then + echo "✅ all gates green and BACKLOG.md fully checked — stopping." + break + fi + echo "… not done yet; continuing to next iteration." +done + +echo "" +echo "Loop finished. Recent commits:" +git --no-pager log --oneline -"$MAX_ITERS" 2>/dev/null || true diff --git a/code/samples/typescript/package-lock.json b/code/samples/typescript/package-lock.json new file mode 100644 index 00000000..1495a0df --- /dev/null +++ b/code/samples/typescript/package-lock.json @@ -0,0 +1,14806 @@ +{ + "name": "ap2-typescript-samples", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ap2-typescript-samples", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@a2a-js/sdk": "^0.3.13", + "@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0", + "@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0", + "@google-cloud/storage": "^7.19.0", + "@google/adk": "^1.1.0", + "@google/genai": "^1.37.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/api-logs": "^0.205.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.205.0", + "@opentelemetry/exporter-metrics-otlp-http": "^0.205.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.205.0", + "@opentelemetry/resource-detector-gcp": "^0.40.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-logs": "^0.205.0", + "@opentelemetry/sdk-metrics": "^2.1.0", + "@opentelemetry/sdk-node": "^0.205.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "@sd-jwt/core": "^0.19.0", + "@sd-jwt/crypto-nodejs": "^0.19.0", + "@verifiable-intent/core": "file:../../../../verifiable-intent/typescript", + "dotenv": "^17.4.2", + "express": "^5.1.0", + "uuid": "^13.0.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@eslint/js": "^9.39.4", + "@google/adk-devtools": "^1.1.0", + "@types/express": "^5.0.6", + "@types/node": "^25.0.10", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.53.1", + "@typescript-eslint/parser": "^8.53.1", + "@vitest/coverage-v8": "^4.1.8", + "concurrently": "^9.1.2", + "eslint": "^9.39.4", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", + "globals": "^17.5.0", + "tsx": "^4.21.0", + "typescript": "^5.7.2", + "typescript-eslint": "^8.58.2", + "vitest": "^4.1.4" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "../../../../verifiable-intent/typescript": { + "name": "@verifiable-intent/core", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/core": "^0.19.0", + "@sd-jwt/crypto-nodejs": "^0.19.0", + "@sd-jwt/types": "^0.19.0" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@types/node": "^22.7.0", + "eslint": "^9.13.0", + "publint": "^0.3.21", + "tsdown": "^0.22.1", + "typescript": "^5.6.0", + "typescript-eslint": "^8.10.0", + "unrun": "^0.2.39", + "vitest": "^4.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@a2a-js/sdk": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@a2a-js/sdk/-/sdk-0.3.13.tgz", + "integrity": "sha512-BZr0f9JVNQs3GKOM9xINWCh6OKIJWZFPyqqVqTym5mxO2Eemc6I/0zL7zWnljHzGdaf5aZQyQN5xa6PSH62q+A==", + "license": "Apache-2.0", + "dependencies": { + "uuid": "^11.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@bufbuild/protobuf": "^2.10.2", + "@grpc/grpc-js": "^1.11.0", + "express": "^4.21.2 || ^5.1.0" + }, + "peerDependenciesMeta": { + "@bufbuild/protobuf": { + "optional": true + }, + "@grpc/grpc-js": { + "optional": true + }, + "express": { + "optional": true + } + } + }, + "node_modules/@a2a-js/sdk/node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/@azure-rest/core-client": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.6.0.tgz", + "integrity": "sha512-iuFKDm8XPzNxPfRjhyU5/xKZmcRDzSuEghXDHHk4MjBV/wFL34GmYVBZnn9wmuoLBeS1qAw9ceMdaeJBPcB1QQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", + "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-http-compat": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.4.0.tgz", + "integrity": "sha512-f1P96IB399YiN2ARYHP7EpZi3Bf3wH4SN2lGzrw7JVwm7bbsVYtf2iKSBwTywD2P62NOPZGHFSZi+6jjb75JuA==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@azure/core-client": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.23.0.tgz", + "integrity": "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", + "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/keyvault-common": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-common/-/keyvault-common-2.1.0.tgz", + "integrity": "sha512-aCDidWuKY06LWQ4x7/8TIXK6iRqTaRWRL3t7T+LC+j1b07HtoIsOxP/tU90G4jCSBn5TAyUTCtA4MS/y5Hudaw==", + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.3.3", + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-rest-pipeline": "^1.8.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.10.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/keyvault-keys": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.10.0.tgz", + "integrity": "sha512-eDT7iXoBTRZ2n3fLiftuGJFD+yjkiB1GNqzU2KbY1TLYeXeSPVTVgn2eJ5vmRTZ11978jy2Kg2wI7xa9Tyr8ag==", + "license": "MIT", + "dependencies": { + "@azure-rest/core-client": "^2.3.3", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-lro": "^2.7.2", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.19.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/keyvault-common": "^2.0.0", + "@azure/logger": "^1.1.4", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.6.3.tgz", + "integrity": "sha512-sTjMtUm+bJpENU/1WlRzHEsgEHppZDZ1EtNyaOODg/sQBtMxxJzGB+MOCM+T2Q5Qe1fKBrdxUmjyRxm0r7Ez9w==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.4.1.tgz", + "integrity": "sha512-Bl8f+w37xkXsYh7QRkAKCFGYtWMYuOVO7Lv+BxILrvGz3HbIEF22Pt0ugyj0QPOl6NLrHcnNUQ9yeew98P/5iw==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.1.2.tgz", + "integrity": "sha512-DoeSJ9U5KPAIZoHsPywvfEj2MhBniQe0+FSpjLUTdWoIkI999GB5USkW6nNEHnIaLVxROHXvprWA1KzdS1VQ4A==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@clack/core": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.5.0.tgz", + "integrity": "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.11.0.tgz", + "integrity": "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "0.5.0", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.8.tgz", + "integrity": "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==", + "license": "MIT", + "dependencies": { + "@so-ric/colorspace": "^1.1.6", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT", + "optional": true + }, + "node_modules/@google-cloud/opentelemetry-cloud-monitoring-exporter": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@google-cloud/opentelemetry-cloud-monitoring-exporter/-/opentelemetry-cloud-monitoring-exporter-0.21.0.tgz", + "integrity": "sha512-+lAew44pWt6rA4l8dQ1gGhH7Uo95wZKfq/GBf9aEyuNDDLQ2XppGEEReu6ujesSqTtZ8ueQFt73+7SReSHbwqg==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/opentelemetry-resource-util": "^3.0.0", + "@google-cloud/precise-date": "^4.0.0", + "google-auth-library": "^9.0.0", + "googleapis": "^137.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-metrics": "^2.0.0" + } + }, + "node_modules/@google-cloud/opentelemetry-cloud-trace-exporter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/opentelemetry-cloud-trace-exporter/-/opentelemetry-cloud-trace-exporter-3.0.0.tgz", + "integrity": "sha512-mUfLJBFo+ESbO0dAGboErx2VyZ7rbrHcQvTP99yH/J72dGaPbH2IzS+04TFbTbEd1VW5R9uK3xq2CqawQaG+1Q==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/opentelemetry-resource-util": "^3.0.0", + "@grpc/grpc-js": "^1.1.8", + "@grpc/proto-loader": "^0.8.0", + "google-auth-library": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-trace-base": "^2.0.0" + } + }, + "node_modules/@google-cloud/opentelemetry-resource-util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/opentelemetry-resource-util/-/opentelemetry-resource-util-3.0.0.tgz", + "integrity": "sha512-CGR/lNzIfTKlZoZFfS6CkVzx+nsC9gzy6S8VcyaLegfEJbiPjxbMLP7csyhJTvZe/iRRcQJxSk0q8gfrGqD3/Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.22.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0" + } + }, + "node_modules/@google-cloud/paginator": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", + "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", + "license": "Apache-2.0", + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/precise-date": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-4.0.0.tgz", + "integrity": "sha512-1TUx3KdaU3cN7nfCdNf+UVqA/PSX29Cjcox3fZZBtINlRrXVTmUkQnCKv2MbBUbCopbK4olAT1IHl76uZyCiVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", + "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", + "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-cloud/storage": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-7.19.0.tgz", + "integrity": "sha512-n2FjE7NAOYyshogdc7KQOl/VZb4sneqPjWouSyia9CMDdMhRX5+RIbqalNmC7LOLzuLAN89VlF2HvG8na9G+zQ==", + "license": "Apache-2.0", + "dependencies": { + "@google-cloud/paginator": "^5.0.0", + "@google-cloud/projectify": "^4.0.0", + "@google-cloud/promisify": "<4.1.0", + "abort-controller": "^3.0.0", + "async-retry": "^1.3.3", + "duplexify": "^4.1.3", + "fast-xml-parser": "^5.3.4", + "gaxios": "^6.0.2", + "google-auth-library": "^9.6.3", + "html-entities": "^2.5.2", + "mime": "^3.0.0", + "p-limit": "^3.0.1", + "retry-request": "^7.0.0", + "teeny-request": "^9.0.0", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@google-cloud/storage/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@google/adk": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@google/adk/-/adk-1.1.0.tgz", + "integrity": "sha512-uB6ieMtif2hHsvTMB4WgGaYbwiK5tDDpm0R5pCdruUtMk+TTPDgJnVm8cpkXpOsutuEX5kg+1H6vQlw/CPqgfg==", + "license": "Apache-2.0", + "dependencies": { + "@a2a-js/sdk": "^0.3.10", + "@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0", + "@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0", + "@google-cloud/storage": "^7.17.1", + "@google/genai": "^1.37.0", + "@mikro-orm/core": "^6.6.10", + "@mikro-orm/reflection": "^6.6.6", + "@modelcontextprotocol/sdk": "^1.26.0", + "@opentelemetry/api": "1.9.0", + "@opentelemetry/api-logs": "^0.205.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.205.0", + "@opentelemetry/exporter-metrics-otlp-http": "^0.205.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.205.0", + "@opentelemetry/resource-detector-gcp": "^0.40.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-logs": "^0.205.0", + "@opentelemetry/sdk-metrics": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "express": "^4.22.1", + "google-auth-library": "^10.3.0", + "js-yaml": "^4.1.1", + "jsonpath-plus": "^10.4.0", + "lodash-es": "^4.18.1", + "winston": "^3.19.0", + "zod": "^4.2.1", + "zod-to-json-schema": "^3.25.1" + }, + "peerDependencies": { + "@mikro-orm/mariadb": "^6.6.6", + "@mikro-orm/mssql": "^6.6.6", + "@mikro-orm/mysql": "^6.6.6", + "@mikro-orm/postgresql": "^6.6.6", + "@mikro-orm/sqlite": "^6.6.6" + } + }, + "node_modules/@google/adk-devtools": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@google/adk-devtools/-/adk-devtools-1.1.0.tgz", + "integrity": "sha512-td2yXcexJi2FRxbCQLFekry+y3Idl5oM3MpWmZVMO3qyhMCc5z1W50ShYF5UxQgZQrp/JHy9+nma41Z5eGBBrg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@clack/prompts": "^0.11.0", + "@google/adk": "^1.1.0", + "@mikro-orm/mariadb": "^6.6.6", + "@mikro-orm/mssql": "^6.6.6", + "@mikro-orm/mysql": "^6.6.6", + "@mikro-orm/postgresql": "^6.6.6", + "@mikro-orm/sqlite": "^6.6.6", + "camelcase-keys": "^6.2.2", + "commander": "^14.0.0", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "esbuild": "^0.25.9", + "esbuild-shim-plugin": "^1.0.3", + "express": "^4.21.2", + "fast-glob": "^3.3.3", + "js-yaml": "^4.1.1", + "ts-graphviz": "^1.0.1", + "winston": "^3.19.0", + "zod": "^4.2.1" + }, + "bin": { + "adk": "dist/esm/cli_entrypoint.js" + } + }, + "node_modules/@google/adk-devtools/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@google/adk-devtools/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@google/adk-devtools/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@google/adk-devtools/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@google/adk-devtools/node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@google/adk-devtools/node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@google/adk-devtools/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@google/adk-devtools/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@google/adk-devtools/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@google/adk-devtools/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk-devtools/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@google/adk-devtools/node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@google/adk-devtools/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@google/adk-devtools/node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@google/adk-devtools/node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@google/adk-devtools/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/@google/adk/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/@google/adk/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@google/adk/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/@google/adk/node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@google/adk/node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@google/adk/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/adk/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/adk/node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/adk/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google/adk/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@google/adk/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@google/adk/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@google/adk/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/adk/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@google/adk/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/@google/adk/node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@google/adk/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@google/adk/node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@google/adk/node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@google/adk/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@google/genai": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.50.1.tgz", + "integrity": "sha512-YbkX7H9+1Pt8wOt7DDREy8XSoiL6fRDzZQRyaVBarFf8MR3zHGqVdvM4cLbDXqPhxqvegZShgfxb8kw9C7YhAQ==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@google/genai/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/genai/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/genai/node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/genai/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@google/genai/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@js-joda/core": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.7.0.tgz", + "integrity": "sha512-WBu4ULVVxySLLzK1Ppq+OdfP+adRS4ntmDQT915rzDJ++i95gc2jZkM5B6LWEAwN3lGXpfie3yPABozdD3K3Vg==", + "license": "BSD-3-Clause" + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@mikro-orm/core": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.6.13.tgz", + "integrity": "sha512-Zf00ZCUV1/fTCE60jJUDDbFb6dDYaojUWr0yoavNYJaFX+qoLdgKSj3tX6j2v//cGKfb/sLqs72FEEtSwvhviA==", + "license": "MIT", + "dependencies": { + "dataloader": "2.2.3", + "dotenv": "17.3.1", + "esprima": "4.0.1", + "fs-extra": "11.3.3", + "globby": "11.1.0", + "mikro-orm": "6.6.13", + "reflect-metadata": "0.2.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/b4nan" + } + }, + "node_modules/@mikro-orm/core/node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@mikro-orm/knex": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.6.13.tgz", + "integrity": "sha512-2pnGow7WvGhJlRxgIX3JvY6qLK58X/vVFCCbHIHGVv2STW0vexFYw6o++f53jybaSJcFjiMcWFWsnzlR80xv3g==", + "license": "MIT", + "dependencies": { + "fs-extra": "11.3.3", + "knex": "3.2.8", + "sqlstring": "2.3.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0", + "better-sqlite3": "*", + "libsql": "*", + "mariadb": "*" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "libsql": { + "optional": true + }, + "mariadb": { + "optional": true + } + } + }, + "node_modules/@mikro-orm/mariadb": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.6.13.tgz", + "integrity": "sha512-unKk0JjcFxUUPw6wm3lHm8dgHu17bTqTuFNIaXavv9useeIYD0DKpBHN1HZMfuXxrbyEwHXedQMdykp53W9Osg==", + "license": "MIT", + "dependencies": { + "@mikro-orm/knex": "6.6.13", + "mariadb": "3.4.5" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/mssql": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/mssql/-/mssql-6.6.13.tgz", + "integrity": "sha512-/GaDB/+CsbtFdtAuB1FxypS7U1ARkabFtkKpBLQOR2I/ixO84lbCZPUbt7yDRD+01Wtml+Zp5pkoQcN1/SGdng==", + "license": "MIT", + "dependencies": { + "@mikro-orm/knex": "6.6.13", + "tedious": "19.2.1", + "tsqlstring": "1.0.1" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/mysql": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.6.13.tgz", + "integrity": "sha512-OpLzpZKqGwLBJ8cnzJB/RejsKSv4vjvvjH9eJNVIl8Pjd+5UaBBn2HLLDaO3YJ8LE9RI1XEQZcXQ9lNiiPpzXw==", + "license": "MIT", + "dependencies": { + "@mikro-orm/knex": "6.6.13", + "mysql2": "3.20.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/postgresql": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/postgresql/-/postgresql-6.6.13.tgz", + "integrity": "sha512-kbQzwbQGTzNFe5IDcBQaaEVwJ0JnHDOprnIPxN1gYOFGmFa36bHPVf6jK+4hNhOJ1wUdSNj3EeDuadwtNpQgjg==", + "license": "MIT", + "dependencies": { + "@mikro-orm/knex": "6.6.13", + "pg": "8.20.0", + "postgres-array": "3.0.4", + "postgres-date": "2.1.0", + "postgres-interval": "4.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/reflection": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.6.13.tgz", + "integrity": "sha512-pH4jsGTRQ/jyC8WFhFtqvGWXUyNUqDUbPiL5DJU9lRKQH0AEeH15cYW1ZbfY85ECJSCAeR9qJsJo6gfFcl09vA==", + "license": "MIT", + "dependencies": { + "globby": "11.1.0", + "ts-morph": "27.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@mikro-orm/sqlite": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.6.13.tgz", + "integrity": "sha512-J3KHvosRxjQfC6NhUj8GrstLvdi/47yLgtGPXzpNXl3B62giecyRRLUxK+rCzBXlcP4aAyyNFVeEjGhpN0tLhg==", + "license": "MIT", + "dependencies": { + "@mikro-orm/knex": "6.6.13", + "fs-extra": "11.3.3", + "sqlite3": "5.1.7", + "sqlstring-sqlite": "0.1.1" + }, + "engines": { + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@nodable/entities": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-1.1.0.tgz", + "integrity": "sha512-bidpxmTBP0pOsxULw6XlxzQpTgrAGLDHGBK/JuWhPDL6ZV0GZ/PmN9CA9do6e+A9lYI6qx6ikJUtJYRxup141g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.205.0.tgz", + "integrity": "sha512-wBlPk1nFB37Hsm+3Qy73yQSobVn28F4isnWIBvKpd5IUH/eat8bwcL02H9yzmHyyPmukeccSl2mbN5sDQZYnPg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.6.1.tgz", + "integrity": "sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.1.tgz", + "integrity": "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.205.0.tgz", + "integrity": "sha512-jQlw7OHbqZ8zPt+pOrW2KGN7T55P50e3NXBMr4ckPOF+DWDwSy4W7mkG09GpYWlQAQ5C9BXg5gfUlv5ldTgWsw==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/sdk-logs": "0.205.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.205.0.tgz", + "integrity": "sha512-5JteMyVWiro4ghF0tHQjfE6OJcF7UBUcoEqX3UIQ5jutKP1H+fxFdyhqjjpmeHMFxzOHaYuLlNR1Bn7FOjGyJg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/sdk-logs": "0.205.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.205.0.tgz", + "integrity": "sha512-q3VS9wS+lpZ01txKxiDGBtBpTNge3YhbVEFDgem9ZQR9eI3EZ68+9tVZH9zJcSxI37nZPJ6lEEZO58yEjYZsVA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-logs": "0.205.0", + "@opentelemetry/sdk-trace-base": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.205.0.tgz", + "integrity": "sha512-1Vxlo4lUwqSKYX+phFkXHKYR3DolFHxCku6lVMP1H8sVE3oj4wwmwxMzDsJ7zF+sXd8M0FCr+ckK4SnNNKkV+w==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.205.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-metrics": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.205.0.tgz", + "integrity": "sha512-fFxNQ/HbbpLmh1pgU6HUVbFD1kNIjrkoluoKJkh88+gnmpFD92kMQ8WFNjPnSbjg2mNVnEkeKXgCYEowNW+p1w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-metrics": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.205.0.tgz", + "integrity": "sha512-qIbNnedw9QfFjwpx4NQvdgjK3j3R2kWH/2T+7WXAm1IfMFe9fwatYxE61i7li4CIJKf8HgUC3GS8Du0C3D+AuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.205.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-metrics": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.205.0.tgz", + "integrity": "sha512-xsot/Qm9VLDTag4GEwAunD1XR1U8eBHTLAgO7IZNo2JuD/c/vL7xmDP7mQIUr6Lk3gtj/yGGIR2h3vhTeVzv4w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-metrics": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.205.0.tgz", + "integrity": "sha512-ZBksUk84CcQOuDJB65yu5A4PORkC4qEsskNwCrPZxDLeWjPOFZNSWt0E0jQxKCY8PskLhjNXJYo12YaqsYvGFA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.205.0.tgz", + "integrity": "sha512-vr2bwwPCSc9u7rbKc74jR+DXFvyMFQo9o5zs+H/fgbK672Whw/1izUKVf+xfWOdJOvuwTnfWxy+VAY+4TSo74Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.205.0.tgz", + "integrity": "sha512-bGtFzqiENO2GpJk988mOBMe0MfeNpTQjbLm/LBijas6VRyEDQarUzdBHpFlu89A25k1+BCntdWGsWTa9Ai4FyA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.1.0.tgz", + "integrity": "sha512-0mEI0VDZrrX9t5RE1FhAyGz+jAGt96HSuXu73leswtY3L5YZD11gtcpARY2KAx/s6Z2+rj5Mhj566JsI2C7mfA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.205.0.tgz", + "integrity": "sha512-cgvm7tvQdu9Qo7VurJP84wJ7ZV9F6WqDDGZpUc6rUEXwjV7/bXWs0kaYp9v+1Vh1+3TZCD3i6j/lUBcPhu8NhA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.205.0.tgz", + "integrity": "sha512-2MN0C1IiKyo34M6NZzD6P9Nv9Dfuz3OJ3rkZwzFmF6xzjDfqqCTatc9v1EpNfaP55iDOCLHFyYNCgs61FFgtUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-transformer": "0.205.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.205.0.tgz", + "integrity": "sha512-AeuLfrciGYffqsp4EUTdYYc6Ee2BQS+hr08mHZk1C524SFWx0WnfcTnV0NFXbVURUNU6DZu1DhS89zRRrcx/hg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/otlp-exporter-base": "0.205.0", + "@opentelemetry/otlp-transformer": "0.205.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.205.0.tgz", + "integrity": "sha512-KmObgqPtk9k/XTlWPJHdMbGCylRAmMJNXIRh6VYJmvlRDMfe+DonH41G7eenG8t4FXn3fxOGh14o/WiMRR6vPg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-logs": "0.205.0", + "@opentelemetry/sdk-metrics": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.1.0.tgz", + "integrity": "sha512-yOdHmFseIChYanddMMz0mJIFQHyjwbNhoxc65fEAA8yanxcBPwoFDoh1+WBUWAO/Z0NRgk+k87d+aFIzAZhcBw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.1.0.tgz", + "integrity": "sha512-QYo7vLyMjrBCUTpwQBF/e+rvP7oGskrSELGxhSvLj5gpM0az9oJnu/0O4l2Nm7LEhAff80ntRYKkAcSwVgvSVQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resource-detector-gcp": { + "version": "0.40.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.40.3.tgz", + "integrity": "sha512-C796YjBA5P1JQldovApYfFA/8bQwFfpxjUbOtGhn1YZkVTLoNQN+kvBwgALfTPWzug6fWsd0xhn9dzeiUcndag==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.1.tgz", + "integrity": "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.6.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.205.0.tgz", + "integrity": "sha512-nyqhNQ6eEzPWQU60Nc7+A5LIq8fz3UeIzdEVBQYefB4+msJZ2vuVtRuk9KxPMw1uHoHDtYEwkr2Ct0iG29jU8w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.6.1.tgz", + "integrity": "sha512-9t9hJHX15meBy2NmTJxL+NJfXmnausR2xUDvE19XQce0Qi/GBtDGamU8nS1RMbdgDmhgpm3VaOu2+fiS/SfTpQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.6.1", + "@opentelemetry/resources": "2.6.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.205.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.205.0.tgz", + "integrity": "sha512-Y4Wcs8scj/Wy1u61pX1ggqPXPtCsGaqx/UnFu7BtRQE1zCQR+b0h56K7I0jz7U2bRlPUZIFdnNLtoaJSMNzz2g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.205.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/exporter-logs-otlp-grpc": "0.205.0", + "@opentelemetry/exporter-logs-otlp-http": "0.205.0", + "@opentelemetry/exporter-logs-otlp-proto": "0.205.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.205.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.205.0", + "@opentelemetry/exporter-metrics-otlp-proto": "0.205.0", + "@opentelemetry/exporter-prometheus": "0.205.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.205.0", + "@opentelemetry/exporter-trace-otlp-http": "0.205.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.205.0", + "@opentelemetry/exporter-zipkin": "2.1.0", + "@opentelemetry/instrumentation": "0.205.0", + "@opentelemetry/propagator-b3": "2.1.0", + "@opentelemetry/propagator-jaeger": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/sdk-logs": "0.205.0", + "@opentelemetry/sdk-metrics": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0", + "@opentelemetry/sdk-trace-node": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/context-async-hooks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.1.0.tgz", + "integrity": "sha512-zOyetmZppnwTyPrt4S7jMfXiSX9yyfF0hxlA8B5oo2TtKl+/RGCy7fi4DrBfIf3lCPrkKsRBWZZD7RFojK7FDg==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.1.0.tgz", + "integrity": "sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.1.0.tgz", + "integrity": "sha512-1CJjf3LCvoefUOgegxi8h6r4B/wLSzInyhGP2UmIBYNlo4Qk5CZ73e1eEyWmfXvFtm1ybkmfb2DqWvspsYLrWw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.1.0.tgz", + "integrity": "sha512-J9QX459mzqHLL9Y6FZ4wQPRZG4TOpMCyPOh6mkr/humxE1W2S3Bvf4i75yiMW9uyed2Kf5rxmLhTm/UK8vNkAw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.1.0.tgz", + "integrity": "sha512-uTX9FBlVQm4S2gVQO1sb5qyBLq/FPjbp+tmGoxu4tIgtYGmBYB44+KX/725RFDe30yBSaA9Ml9fqphe1hbUyLQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/resources": "2.1.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.1.0.tgz", + "integrity": "sha512-SvVlBFc/jI96u/mmlKm86n9BbTCbQ35nsPoOohqJX6DXH92K0kTe73zGY5r8xoI1QkjR9PizszVJLzMC966y9Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.1.0", + "@opentelemetry/core": "2.1.0", + "@opentelemetry/sdk-trace-base": "2.1.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.1.tgz", + "integrity": "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.6.1", + "@opentelemetry/resources": "2.6.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.6.1.tgz", + "integrity": "sha512-Hh2i4FwHWRFhnO2Q/p6svMxy8MPsNCG0uuzUY3glqm0rwM0nQvbTO1dXSp9OqQoTKXcQzaz9q1f65fsurmOhNw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.6.1", + "@opentelemetry/core": "2.6.1", + "@opentelemetry/sdk-trace-base": "2.6.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz", + "integrity": "sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sd-jwt/core": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/core/-/core-0.19.0.tgz", + "integrity": "sha512-/FeuQjzQFtnxDsHF64Bw+3uixVogNkXlMGBo1CKWrxB/OLNqtGXQZplKBRZMJWgnOJEqDwD6750wrOxsVly6mg==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/decode": "0.19.0", + "@sd-jwt/present": "0.19.0", + "@sd-jwt/types": "0.19.0", + "@sd-jwt/utils": "0.19.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sd-jwt/crypto-nodejs": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/crypto-nodejs/-/crypto-nodejs-0.19.0.tgz", + "integrity": "sha512-mRUZ5pgMBqisXIJyq9vzNH0p4szHV7Dg87Mzm7mI7pgPjIkx9g8R1gRBWaRNzy6mblrTvEpcziPe6bnTY04Lqw==", + "license": "Apache-2.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/@sd-jwt/decode": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/decode/-/decode-0.19.0.tgz", + "integrity": "sha512-gRfpJseFRy3bFMdlmJjVjuEcLNuekpiZJD2F2luJIKVlk26AEjZSJf6377vwNySa8hb+i4MZDwdy14lcTTmqtA==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/types": "0.19.0", + "@sd-jwt/utils": "0.19.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sd-jwt/present": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/present/-/present-0.19.0.tgz", + "integrity": "sha512-WXDwqwUXmtyj7YZ5c+wb26ZBeVOsKXCbCI7s1pRH9ngIjFNDGgAZoVCOmLq8pPgWSJzOTgJe3ErO2k63ZwhyeQ==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/decode": "0.19.0", + "@sd-jwt/types": "0.19.0", + "@sd-jwt/utils": "0.19.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sd-jwt/types": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/types/-/types-0.19.0.tgz", + "integrity": "sha512-nfuC9zRLKe7o4HSvc+N4ojWRAxo4JGfgcNWpR7bJloLUlnE9eQuu9h9pEaJZht7KRwMpGorNTIdYpoi1btuiew==", + "license": "Apache-2.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/@sd-jwt/utils": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@sd-jwt/utils/-/utils-0.19.0.tgz", + "integrity": "sha512-bDwDRjfxMBNOsAXY8q8hnxQq7jdOWxrdqTK926Mxt8DN+ttXbXbZIPLwSh84M90WP0V7+WdkXlZD31iISzUR3w==", + "license": "Apache-2.0", + "dependencies": { + "@sd-jwt/types": "0.19.0", + "js-base64": "^3.7.8" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@so-ric/colorspace": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@so-ric/colorspace/-/colorspace-1.1.6.tgz", + "integrity": "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==", + "license": "MIT", + "dependencies": { + "color": "^5.0.2", + "text-hex": "1.0.x" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.28.1.tgz", + "integrity": "sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==", + "license": "MIT", + "dependencies": { + "minimatch": "^10.0.1", + "path-browserify": "^1.0.1", + "tinyglobby": "^0.2.14" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/caseless": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", + "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/readable-stream": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz", + "integrity": "sha512-wwXrtQvbMHxCbBgjHaMGEmImFTQxxpfMOR/ZoQnXxB1woqkUbdLGFDgauo00Py9IudiaqSeiBiulSV9i6XIPig==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/request": { + "version": "2.48.13", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.13.tgz", + "integrity": "sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==", + "license": "MIT", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.5" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "license": "MIT" + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz", + "integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/type-utils": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz", + "integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz", + "integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.2", + "@typescript-eslint/types": "^8.58.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz", + "integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz", + "integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz", + "integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz", + "integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz", + "integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.2", + "@typescript-eslint/tsconfig-utils": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/visitor-keys": "8.58.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", + "integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.2", + "@typescript-eslint/types": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz", + "integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.5.tgz", + "integrity": "sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw==", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@verifiable-intent/core": { + "resolved": "../../../../verifiable-intent/typescript", + "link": true + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.8.tgz", + "integrity": "sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.8", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.8", + "vitest": "4.1.8" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.3.tgz", + "integrity": "sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "license": "MIT", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/code-block-writer": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", + "license": "MIT" + }, + "node_modules/color": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.3.tgz", + "integrity": "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==", + "license": "MIT", + "dependencies": { + "color-convert": "^3.1.3", + "color-string": "^2.1.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.1.4.tgz", + "integrity": "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz", + "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz", + "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dataloader": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", + "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", + "optional": true + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esbuild-shim-plugin": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/esbuild-shim-plugin/-/esbuild-shim-plugin-1.0.3.tgz", + "integrity": "sha512-FEwQnCEk6tWw+27QYCBSICrfMcaENFiX75MGsYPKM+FG6aw6dihJ3TNJGAiMPOcVb9bqycZkcCTe+DurBNW9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.9" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "dev": true, + "license": "ISC", + "dependencies": { + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", + "is-bun-module": "^2.0.0", + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^16.17.0 || >=18.6.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", + "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", + "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-xml-builder": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", + "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.6.0.tgz", + "integrity": "sha512-5G+uaEBbOm9M4dgMOV3K/rBzfUNGqGqoUTaYJM3hBwM8t71w07gxLQZoTsjkY8FtfjabqgQHEkeIySBDYeBmJw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^1.1.0", + "fast-xml-builder": "^1.1.4", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==", + "license": "MIT" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT", + "optional": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz", + "integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/googleapis": { + "version": "137.1.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-137.1.0.tgz", + "integrity": "sha512-2L7SzN0FLHyQtFmyIxrcXhgust77067pkkduqkbIpDuj9JzVnByxsRrcRfUMFQam3rQkWW2B0f1i40IwKDWIVQ==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^9.0.0", + "googleapis-common": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/googleapis-common": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.2.0.tgz", + "integrity": "sha512-/fhDZEJZvOV3X5jmD+fKxMqma5q2Q9nZNSF3kn1F18tpxmA86BcTxAGBQdM0N89Z3bEaIs+HVznSmFJEAmMTjA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "gaxios": "^6.0.3", + "google-auth-library": "^9.7.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/googleapis-common/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.14", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.14.tgz", + "integrity": "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", + "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", + "optional": true + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpath-plus": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.4.0.tgz", + "integrity": "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/knex": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/knex/-/knex-3.2.8.tgz", + "integrity": "sha512-ElXXxu9Nq+5hWYdBUddYIWIT5yKKs5KNCsmKGbJSHPyaMpAABp3xs4L55GgdQoAs6QQ7dv72ai3M4pxYQ8utEg==", + "license": "MIT", + "dependencies": { + "colorette": "2.0.19", + "commander": "^10.0.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.6.2", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "bin": { + "knex": "bin/cli.js" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "pg-query-stream": "^4.14.0" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "mysql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/knex/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", + "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru.min": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", + "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mariadb": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.4.5.tgz", + "integrity": "sha512-gThTYkhIS5rRqkVr+Y0cIdzr+GRqJ9sA2Q34e0yzmyhMCwyApf3OKAC1jnF23aSlIOqJuyaUFUcj7O1qZslmmQ==", + "license": "LGPL-2.1-or-later", + "dependencies": { + "@types/geojson": "^7946.0.16", + "@types/node": "^24.0.13", + "denque": "^2.1.0", + "iconv-lite": "^0.6.3", + "lru-cache": "^10.4.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/mariadb/node_modules/@types/node": { + "version": "24.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz", + "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/mariadb/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mariadb/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/mariadb/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mikro-orm": { + "version": "6.6.13", + "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.6.13.tgz", + "integrity": "sha512-o7HtpBllUIjWwBQB8sQ/0MBJ90vqBM4fzmb2IeRScgWVtZgpcqDOEscuOgfxMFfaaUfA14meNdE8mxsre8JjKg==", + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", + "license": "BlueOak-1.0.0", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mysql2": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.20.0.tgz", + "integrity": "sha512-eCLUs7BNbgA6nf/MZXsaBO1SfGs0LtLVrJD3WeWq+jPLDWkSufTD+aGMwykfUVPdZnblaUK1a8G/P63cl9FkKg==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.2", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.2", + "long": "^5.3.2", + "lru.min": "^1.1.4", + "named-placeholders": "^1.1.6", + "sql-escaper": "^1.3.3" + }, + "engines": { + "node": ">= 8.0" + }, + "peerDependencies": { + "@types/node": ">= 8" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "license": "MIT", + "dependencies": { + "lru.min": "^1.1.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/native-duplexpair": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", + "integrity": "sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.89.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", + "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg-types/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-interval": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-4.0.2.tgz", + "integrity": "sha512-EMsphSQ1YkQqKZL2cuG0zHkmjCCzQqQ71l2GXITqRwjhRleCdv00bDk/ktaSi0LnlaPzAc3535KTrjXsTdtx7A==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/protobufjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rechoir/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/require-in-the-middle/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", + "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", + "license": "MIT", + "dependencies": { + "@types/request": "^2.48.8", + "extend": "^3.0.2", + "teeny-request": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/sql-escaper": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.3.3.tgz", + "integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=2.0.0", + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/mysqljs/sql-escaper?sponsor=1" + } + }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/sqlstring-sqlite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sqlstring-sqlite/-/sqlstring-sqlite-0.1.1.tgz", + "integrity": "sha512-9CAYUJ0lEUPYJrswqiqdINNSfq3jqWo/bFJ7tufdoNeSK0Fy+d1kFTxjqO9PIqza0Kri+ZtYMfPVf1aZaFOvrQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "license": "MIT", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "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", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/tedious": { + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-19.2.1.tgz", + "integrity": "sha512-pk1Q16Yl62iocuQB+RWbg6rFUFkIyzqOFQ6NfysCltRvQqKwfurgj8v/f2X+CKvDhSL4IJ0cCOfCHDg9PWEEYA==", + "license": "MIT", + "dependencies": { + "@azure/core-auth": "^1.7.2", + "@azure/identity": "^4.2.1", + "@azure/keyvault-keys": "^4.4.0", + "@js-joda/core": "^5.6.5", + "@types/node": ">=18", + "bl": "^6.1.4", + "iconv-lite": "^0.7.0", + "js-md4": "^0.3.2", + "native-duplexpair": "^1.0.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">=18.17" + } + }, + "node_modules/tedious/node_modules/bl": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz", + "integrity": "sha512-jLsPgN/YSvPUg9UX0Kd73CXpm2Psg9FxMeCSXnk3WBO3CMT10JMwijubhGfHCnFu6TPn1ei3b975dxv7K2pWVg==", + "license": "MIT", + "dependencies": { + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, + "node_modules/tedious/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/tedious/node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/teeny-request": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", + "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", + "license": "Apache-2.0", + "dependencies": { + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.9", + "stream-events": "^1.0.5", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/teeny-request/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/teeny-request/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/teeny-request/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/teeny-request/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/teeny-request/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-graphviz": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/ts-graphviz/-/ts-graphviz-1.8.2.tgz", + "integrity": "sha512-5YhbFoHmjxa7pgQLkB07MtGnGJ/yhvjmc9uhsnDBEICME6gkPf83SBwLDQqGDoCa3XzUMWLk1AU2Wn1u1naDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ts-graphviz" + } + }, + "node_modules/ts-morph": { + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-27.0.2.tgz", + "integrity": "sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==", + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.28.1", + "code-block-writer": "^13.0.3" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsqlstring": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tsqlstring/-/tsqlstring-1.0.1.tgz", + "integrity": "sha512-6Nzj/SrVg1SF+egwP4OMAgEa83nLKXIE3EHn+6YKinMUeMj8bGIeLuDCkDC3Cc4OIM+xhw4CD0oXKxal8J/Y6A==", + "license": "MIT", + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.58.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz", + "integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.2", + "@typescript-eslint/parser": "8.58.2", + "@typescript-eslint/typescript-estree": "8.58.2", + "@typescript-eslint/utils": "8.58.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==", + "license": "BSD" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vitest": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.19.0.tgz", + "integrity": "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.8", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.7.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.9.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", + "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", + "license": "MIT", + "dependencies": { + "logform": "^2.7.0", + "readable-stream": "^3.6.2", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/code/samples/typescript/package.json b/code/samples/typescript/package.json new file mode 100644 index 00000000..c6555088 --- /dev/null +++ b/code/samples/typescript/package.json @@ -0,0 +1,76 @@ +{ + "name": "ap2-typescript-samples", + "version": "0.1.0", + "description": "TypeScript samples for the Agent Payments Protocol (AP2).", + "type": "module", + "scripts": { + "build": "tsc", + "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "test:coverage:unit": "vitest run test/unit --coverage", + "cli": "npx adk run src/roles/shopping-agent/agent.ts", + "dev": "concurrently \"npx tsx src/roles/shopping-agent/server.ts\" \"npx tsx src/roles/credentials-provider-agent/server.ts\" \"npx tsx src/roles/merchant-payment-processor-agent/server.ts\" \"npx tsx src/roles/merchant-agent/server.ts\" \"npx adk web src/web-agents --host localhost -p 3001\"" + }, + "keywords": [ + "ap2", + "agent-payments-protocol", + "a2a", + "adk", + "agents" + ], + "author": "Google LLC", + "license": "Apache-2.0", + "engines": { + "node": ">=20.0.0" + }, + "dependencies": { + "@a2a-js/sdk": "^0.3.13", + "@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0", + "@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0", + "@google-cloud/storage": "^7.19.0", + "@google/adk": "^1.1.0", + "@google/genai": "^1.37.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/api-logs": "^0.205.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.205.0", + "@opentelemetry/exporter-metrics-otlp-http": "^0.205.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.205.0", + "@opentelemetry/resource-detector-gcp": "^0.40.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-logs": "^0.205.0", + "@opentelemetry/sdk-metrics": "^2.1.0", + "@opentelemetry/sdk-node": "^0.205.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "@sd-jwt/core": "^0.19.0", + "@sd-jwt/crypto-nodejs": "^0.19.0", + "@verifiable-intent/core": "file:../../../../verifiable-intent/typescript", + "dotenv": "^17.4.2", + "express": "^5.1.0", + "uuid": "^13.0.0", + "zod": "^4.4.3" + }, + "devDependencies": { + "@eslint/js": "^9.39.4", + "@google/adk-devtools": "^1.1.0", + "@types/express": "^5.0.6", + "@types/node": "^25.0.10", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^8.53.1", + "@typescript-eslint/parser": "^8.53.1", + "@vitest/coverage-v8": "^4.1.8", + "concurrently": "^9.1.2", + "eslint": "^9.39.4", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.32.0", + "globals": "^17.5.0", + "tsx": "^4.21.0", + "typescript": "^5.7.2", + "typescript-eslint": "^8.58.2", + "vitest": "^4.1.4" + } +} diff --git a/code/samples/typescript/scenarios/a2a/human-not-present/cards/README.md b/code/samples/typescript/scenarios/a2a/human-not-present/cards/README.md new file mode 100644 index 00000000..c0d0d9fd --- /dev/null +++ b/code/samples/typescript/scenarios/a2a/human-not-present/cards/README.md @@ -0,0 +1,115 @@ +# Agent Payments Protocol Sample (TS): Human-Not-Present with a Card + +This sample is a TypeScript port of the v0.2 Python HNP cards scenario. + +## Scenario + +In a **Human-Not-Present (HNP)** flow the user is not actively present at the +moment of purchase. The user signs an open mandate up front; the agent then +monitors for a triggering condition (price drop, item drop, etc.) and +autonomously completes the purchase when the constraint is satisfied. + +This sample fires a mock price-drop event via HTTP to the merchant trigger +server. The `shopping_agent_v2` polls `check_product`, evaluates the open +mandate constraints, and — when satisfied — runs the closed-mandate / checkout +/ payment / receipt pipeline against three MCP servers without further user +input. + +## Key actors + +- **Shopping Agent v2** (`src/roles/shopping-agent-v2/`) — orchestrator (LLM). + Owns three stdio MCP clients pointed at the role MCP servers below. +- **Merchant MCP** (`src/roles/merchant-agent-mcp/server.ts`) — exposes + `search_inventory`, `check_product`, `assemble_cart`, `create_checkout`, + `complete_checkout` over stdio. +- **Credentials Provider MCP** (`src/roles/credentials-provider-mcp/server.ts`) + — exposes `issue_payment_credential`, `revoke_payment_credential`, + `verify_payment_receipt`. +- **Merchant Payment Processor MCP** + (`src/roles/merchant-payment-processor-mcp/server.ts`) — exposes + `initiate_payment`. +- **Trigger HTTP servers** (one per MCP role) — fire external events such as + `POST /trigger-price-drop` to drive the autonomous loop. + +## Status + +This is a **minimum-viable port** of the v0.2 Python `*_mcp` roles. The MCP +tool *contracts* (names, args, response shapes) are 1:1 with Python, but the +cryptographic primitives (SD-JWT mandate chain verification, ES256 signing, +disclosure-metadata canonicalization, real receipt verification) are +**stubbed**. The flow runs end-to-end and is wire-compatible with the v0.2 +web-client, but it is not a production-grade implementation of AP2 v0.2. + +## Setup + +You need a Google API key from [Google AI Studio](https://aistudio.google.com/apikey). +Put it in a `.env` at the repository root: + +```sh +echo "GOOGLE_API_KEY=your_key" > .env +``` + +## Execution + +```sh +bash code/samples/typescript/scenarios/a2a/human-not-present/cards/run.sh +``` + +Ports: + +- Shopping Agent v2 — `http://localhost:8080` +- Merchant trigger — `http://localhost:8081` +- Credentials Provider trigger — `http://localhost:8082` +- Payment Processor trigger — `http://localhost:8083` +- Web client — `http://localhost:5173` (only if `/tmp/ap2-v02/code/web-client` + exists; otherwise skipped — set `WEB_CLIENT_DIR` to override) + +## Driving the flow from the CLI + +1. Start the stack: + + ```sh + bash code/samples/typescript/scenarios/a2a/human-not-present/cards/run.sh + ``` + +2. Send the initial intent to the shopping agent over A2A (the agent runs + `search_inventory` and signs the open mandate): + + ```sh + curl -X POST http://localhost:8080/a2a/shopping_agent \ + -H "Content-Type: application/json" \ + -d '{ + "jsonrpc": "2.0", + "id": "1", + "method": "message/send", + "params": { + "configuration": {"acceptedOutputModes": [], "blocking": true}, + "message": { + "kind": "message", + "messageId": "msg-1", + "role": "user", + "parts": [{"kind": "text", "text": "When does the SuperShoe drop? Size 9 womens, max $200."}] + } + } + }' + ``` + +3. Inspect the chosen `item_id` (printed in the response or in + `.logs/shopping-agent-v2.log`). + +4. Fire the price-drop trigger: + + ```sh + curl -X POST "http://localhost:8081/trigger-price-drop?item_id=supershoe_size_9_0&price=150&stock=10" + ``` + +5. Nudge the agent to re-check (or wait for the next poll): + + ```sh + curl -X POST http://localhost:8080/a2a/shopping_agent \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":"2","method":"message/send","params":{"configuration":{"acceptedOutputModes":[],"blocking":true},"message":{"kind":"message","messageId":"msg-2","role":"user","parts":[{"kind":"text","text":"Check the price now."}]}}}' + ``` + + The agent should now see the drop, run the closed-mandate + checkout + + payment pipeline, and surface a receipt. diff --git a/code/samples/typescript/scenarios/a2a/human-not-present/cards/run.sh b/code/samples/typescript/scenarios/a2a/human-not-present/cards/run.sh new file mode 100755 index 00000000..6f6664f0 --- /dev/null +++ b/code/samples/typescript/scenarios/a2a/human-not-present/cards/run.sh @@ -0,0 +1,143 @@ +#!/bin/bash +# --------------------------------------------------------------------------- +# Run all servers for the TypeScript A2A human-not-present flow (Card) and +# open the web-client (reused from the v0.2 Python tree). +# +# Prerequisites: Node.js >= 20, npm +# Usage: ./run.sh (run from anywhere) +# --------------------------------------------------------------------------- + +set -eu + +readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly TS_SAMPLES_ROOT="$(cd "$SCRIPT_DIR/../../../../" && pwd)" +readonly REPO_ROOT="$(cd "$TS_SAMPLES_ROOT/../../../" && pwd)" +readonly LOG_DIR="$SCRIPT_DIR/.logs" +readonly TEMP_DB_DIR="$SCRIPT_DIR/.temp-db" + +readonly WEB_CLIENT_PORT=5173 +readonly AGENT_PORT=8080 +readonly MERCHANT_TRIGGER_PORT=8081 +readonly CREDENTIALS_PROVIDER_PORT=8082 +readonly PAYMENT_PROCESSOR_PORT=8083 + +mkdir -p "$LOG_DIR" "$TEMP_DB_DIR" + +if [ -f "$REPO_ROOT/.env" ]; then + set -a + source "$REPO_ROOT/.env" + set +a +fi + +export LOGS_DIR="$LOG_DIR" +export TEMP_DB_DIR +export MERCHANT_TRIGGER_STATE_PATH="$TEMP_DB_DIR/merchant_trigger_state.json" +export AGENT_PORT MERCHANT_TRIGGER_PORT CREDENTIALS_PROVIDER_PORT PAYMENT_PROCESSOR_PORT + +rm -f "$LOG_DIR"/*.log "$TEMP_DB_DIR"/*.json 2>/dev/null || true + +pids=() + +cleanup() { + echo "" + echo "Shutting down..." + if [[ ${#pids[@]} -gt 0 ]]; then + kill -TERM "${pids[@]}" 2>/dev/null || true + sleep 1 + kill -KILL "${pids[@]}" 2>/dev/null || true + fi + echo "Done." +} +trap cleanup EXIT + +kill_port() { + local port="$1" + local pid + pid=$(lsof -ti tcp:"${port}" || true) + if [ -n "$pid" ]; then + echo "Killing process $pid on port $port" + kill -9 $pid 2>/dev/null || true + fi +} + +start_service() { + local name="$1" cmd="$2" port="$3" + echo "Starting ${name} (port ${port})..." + (cd "$TS_SAMPLES_ROOT" && eval "$cmd") >"$LOG_DIR/${name}.log" 2>&1 & + pids+=("$!") +} + +wait_for_url() { + local url="$1" + local timeout="${2:-30}" + local attempts=$(( timeout * 2 )) + for (( i = 1; i <= attempts; i++ )); do + if curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null | grep -q "200\|404"; then + return 0 + fi + sleep 0.5 + done + echo "ERROR: Timed out after ${timeout}s waiting for $url" >&2 + exit 1 +} + +echo "Ensuring TypeScript deps are installed..." +(cd "$TS_SAMPLES_ROOT" && npm install --no-fund --no-audit --silent) + +export FLOW=card + +kill_port $MERCHANT_TRIGGER_PORT +start_service "merchant-trigger" \ + "npx tsx src/roles/merchant-agent-mcp/trigger-server.ts" \ + $MERCHANT_TRIGGER_PORT + +kill_port $CREDENTIALS_PROVIDER_PORT +start_service "credentials-provider-trigger" \ + "npx tsx src/roles/credentials-provider-mcp/trigger-server.ts" \ + $CREDENTIALS_PROVIDER_PORT + +kill_port $PAYMENT_PROCESSOR_PORT +start_service "payment-processor-trigger" \ + "npx tsx src/roles/merchant-payment-processor-mcp/trigger-server.ts" \ + $PAYMENT_PROCESSOR_PORT + +kill_port $AGENT_PORT +start_service "shopping-agent-v2" \ + "npx tsx src/roles/shopping-agent-v2/server.ts" \ + $AGENT_PORT + +echo "Waiting for shopping agent..." +wait_for_url "http://localhost:$AGENT_PORT/a2a/shopping_agent/.well-known/agent-card.json" 60 + +# Optional: reuse the v0.2 web-client if present at sibling worktree. +WEB_CLIENT_DIR_DEFAULT="/tmp/ap2-v02/code/web-client" +WEB_CLIENT_DIR="${WEB_CLIENT_DIR:-$WEB_CLIENT_DIR_DEFAULT}" + +if [ -d "$WEB_CLIENT_DIR" ]; then + kill_port $WEB_CLIENT_PORT + echo "Installing web-client deps..." + (cd "$WEB_CLIENT_DIR" && npm install --no-fund --no-audit --silent) + echo "Starting web-client (port $WEB_CLIENT_PORT)..." + ( cd "$WEB_CLIENT_DIR" \ + && VITE_AGENT_URL="http://localhost:$AGENT_PORT/a2a/shopping_agent" \ + VITE_MERCHANT_TRIGGER_URL="http://localhost:$MERCHANT_TRIGGER_PORT" \ + VITE_FLOW=card \ + npm run dev -- --port $WEB_CLIENT_PORT \ + ) >"$LOG_DIR/web-client.log" 2>&1 & + pids+=("$!") + wait_for_url "http://localhost:$WEB_CLIENT_PORT" 30 + echo "" + echo "Opening http://localhost:$WEB_CLIENT_PORT" + command -v open >/dev/null 2>&1 && open "http://localhost:$WEB_CLIENT_PORT" || true +else + echo "" + echo "Web-client not found at $WEB_CLIENT_DIR — skipping." + echo "Set WEB_CLIENT_DIR or check out v0.2 (git worktree add /tmp/ap2-v02 v0.2.0)." +fi + +echo "" +echo "To simulate a drop:" +echo " curl -X POST \"http://localhost:$MERCHANT_TRIGGER_PORT/trigger-price-drop?item_id=&price=&stock=10\"" +echo "" +echo "Press Ctrl+C to stop all servers." +wait diff --git a/code/samples/typescript/scenarios/a2a/human-present/cards/README.md b/code/samples/typescript/scenarios/a2a/human-present/cards/README.md new file mode 100644 index 00000000..dcbc327c --- /dev/null +++ b/code/samples/typescript/scenarios/a2a/human-present/cards/README.md @@ -0,0 +1,125 @@ +# TypeScript Sample: Human-Present Card Payment (A2A) + +This scenario demonstrates the A2A `ap2-extension` for a human-present +transaction using a card as the payment method, implemented entirely in +TypeScript. + +## Scenario + +Human-Present flows refer to all commerce flows where the user is present to +confirm the details of what is being purchased and what payment method is to be +used. The user attesting to the details of the purchase allows all parties to +have high confidence of the transaction. + +The IntentMandate is leveraged to share the appropriate information with +Merchant Agents. All Human-Present purchases will have a user-signed +PaymentMandate authorizing the purchase. + +## Agents Implemented + +All four roles are implemented in TypeScript: + +- **Shopping Agent** (`http://localhost:8001`) + - Root orchestrator running on the ADK web UI. + - Coordinates `shopper`, `shipping_collector`, and `payment_collector` + sub_agents. +- **Merchant Agent** (`http://localhost:8004/a2a/merchant_agent`) + - Handles product catalog queries and creates signed CartMandates. +- **Credentials Provider** (`http://localhost:8002/a2a/credentials_provider`) + - Manages payment credentials and provides DPAN tokens. +- **Merchant Payment Processor** (`http://localhost:8003/a2a/merchant_payment_processor_agent`) + - Authorizes payments and runs the OTP challenge. + +## What This Sample Demonstrates + +1. **AP2 Protocol Features** + - Complete mandate lifecycle (Intent → Cart → Payment → Receipt) + - Card payment with DPAN tokens + - OTP challenge during payment authorization + - W3C Verifiable Credential signing of mandates +2. **TypeScript Patterns** + - Zod schemas mirroring the AP2 types + - ADK `LlmAgent` orchestration with `FunctionTool`s + - A2A request/response handling via `@a2a-js/sdk` + +## Setup + +### Prerequisites + +- Node.js 18+ +- npm + +### Configure credentials + +Obtain a Google API key from +[Google AI Studio](https://aistudio.google.com/apikey), then create a `.env` +file in `code/samples/typescript/`: + +```sh +cp code/samples/typescript/.env.example code/samples/typescript/.env +# Edit code/samples/typescript/.env and fill in GOOGLE_API_KEY +``` + +Alternatively, configure Vertex AI by setting `GOOGLE_GENAI_USE_VERTEXAI=true` +along with `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION`. + +### Install dependencies + +```sh +cd code/samples/typescript +npm install +``` + +## Execution + +### Option 1: Run everything with one command + +```sh +bash code/samples/typescript/scenarios/a2a/human-present/cards/run.sh +``` + +This starts the three backend agents and the Shopping Agent web UI. + +### Option 2: Run each agent in its own terminal + +```sh +# Terminal 1: Merchant Agent (port 8004) +npx tsx src/roles/merchant/server.ts + +# Terminal 2: Credentials Provider (port 8002) +npx tsx src/roles/credentials-provider/server.ts + +# Terminal 3: Payment Processor (port 8003) +npx tsx src/roles/payment-processor/server.ts + +# Terminal 4: Shopping Agent A2A server (port 8001) +npx tsx src/roles/shopping/server.ts + +# Terminal 5: ADK web UI (port 3001) +npx adk web src/roles/shopping --host localhost -p 3001 +``` + +Then open the ADK web UI at and select the +`shopping_agent`. + +## Interacting with the Shopping Agent + +1. **Initial request**: Type something like _"I want to buy running shoes."_ +2. **Product search**: The Shopping Agent delegates to the Merchant Agent, + which returns CartMandate options. +3. **Product selection**: Choose one of the offered carts. +4. **Shipping address**: The `shipping_collector` sub_agent prompts for an + address; the cart is then re-signed by the merchant. +5. **Payment method**: The `payment_collector` sub_agent fetches available + payment methods from the Credentials Provider. +6. **OTP challenge**: The Payment Processor issues an OTP challenge that you + complete in the chat. +7. **Receipt**: A signed `PaymentReceipt` is returned and displayed. + +## Smoke Tests + +After the agents are running, you can run end-to-end smoke tests: + +```sh +npm run test:e2e +``` diff --git a/code/samples/typescript/scenarios/a2a/human-present/cards/run.sh b/code/samples/typescript/scenarios/a2a/human-present/cards/run.sh new file mode 100755 index 00000000..0aab8e66 --- /dev/null +++ b/code/samples/typescript/scenarios/a2a/human-present/cards/run.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +SAMPLE_DIR="$(cd "$(dirname "$0")/../../../.." && pwd)" +cd "$SAMPLE_DIR" + +echo "==========================================" +echo "AP2 TypeScript Sample - Human-Present Cards" +echo "==========================================" + +if [ -f .env ]; then + set -a + # shellcheck disable=SC1091 + source .env + set +a +fi + +USE_VERTEXAI=$(printf "%s" "${GOOGLE_GENAI_USE_VERTEXAI}" | tr '[:upper:]' '[:lower:]') +if [ -z "${GOOGLE_API_KEY}" ] && [ "${USE_VERTEXAI}" != "true" ]; then + echo "Error: GOOGLE_API_KEY is not set." + echo "Either export GOOGLE_API_KEY or set GOOGLE_GENAI_USE_VERTEXAI=true." + echo "See ${SAMPLE_DIR}/.env.example for reference." + exit 1 +fi + +if [ ! -d node_modules ]; then + echo "Installing dependencies..." + npm install +fi + +echo "" +echo "Starting all agents (merchant, credentials, payment processor) and the" +echo "Shopping Agent web UI on http://localhost:3001 ..." +echo "Press Ctrl+C to stop." +echo "" + +exec npm run dev diff --git a/code/samples/typescript/src/common/config/session.ts b/code/samples/typescript/src/common/config/session.ts new file mode 100644 index 00000000..46f40855 --- /dev/null +++ b/code/samples/typescript/src/common/config/session.ts @@ -0,0 +1,28 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'dotenv/config'; +import { InMemorySessionService } from '@google/adk'; + +/** + * Global session service for ADK agents. + * + * Each agent server process gets its own instance (since ES modules are + * per-process). In ADK dev mode (`npm run dev`), all agents share this + * single instance within the same process, which is the intended behavior + * for local development. + */ +export const sessionService = new InMemorySessionService(); diff --git a/code/samples/typescript/src/common/constants/index.ts b/code/samples/typescript/src/common/constants/index.ts new file mode 100644 index 00000000..49b51f67 --- /dev/null +++ b/code/samples/typescript/src/common/constants/index.ts @@ -0,0 +1,48 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** AP2 mandate data keys */ +export const DATA_KEYS = { + CART_MANDATE: "ap2.mandates.CartMandate", + INTENT_MANDATE: "ap2.mandates.IntentMandate", + PAYMENT_MANDATE: "ap2.mandates.PaymentMandate", + PAYMENT_RECEIPT: "ap2.PaymentReceipt", + CONTACT_ADDRESS: "contact_picker.ContactAddress", +} as const; + +/** A2A protocol data part keys */ +export const A2A_DATA_KEYS = { + PAYMENT_METHOD_DATA: "payment_request.PaymentMethodData", + RISK_DATA: "risk_data", + USER_EMAIL: "user_email", + PAYMENT_METHOD_ALIAS: "payment_method_alias", + CHALLENGE_RESPONSE: "challenge_response", + CART_ID: "cart_id", + SHIPPING_ADDRESS: "shipping_address", + DPC_RESPONSE: "dpc_response", + DEBUG_MODE: "debug_mode", + SHOPPING_AGENT_ID: "shopping_agent_id", +} as const; + +export const DEBUG_MODE_INSTRUCTIONS = ` + This is really important! If the agent or user asks you to be verbose or if debug_mode is True, do the following: + 1. If this is the the start of a new task, explain who you are, what you are going to do, what tools you use, and what agents you delegate to. + 2. During the task, provide regular status updates on what you are doing, what you have done so far, and what you plan to do next. + 3. If you are delegating to another agent, ask the agent or tool to also be verbose. + 4. If at any point in the task you send or receive data, show the data in a clear, formatted way. Do not summarize it in english. Simple format the JSON objects. + 5. Step 4 is so important that I'm going to repeat it: + a. If at any point in the task you create, send or receive data, show the data in a clear, formatted way. Do not summarize it in english. Simple format the JSON objects. +`; diff --git a/code/samples/typescript/src/common/schemas/cart-mandate.ts b/code/samples/typescript/src/common/schemas/cart-mandate.ts new file mode 100644 index 00000000..6d4e75e4 --- /dev/null +++ b/code/samples/typescript/src/common/schemas/cart-mandate.ts @@ -0,0 +1,192 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from "zod"; +import { shippingAddressSchema } from "./shipping-address.js"; + +export const cartMandateSchema = z.object({ + contents: z.object({ + id: z.string().describe("The ID of the cart mandate."), + userCartConfirmationRequired: z + .boolean() + .describe("If the user must confirm the cart."), + paymentRequest: z + .object({ + methodData: z.array( + z.object({ + supportedMethods: z.string().describe("The supported methods."), + data: z.record(z.string(), z.any()).describe("The data of the method."), + }) + ), + details: z.object({ + id: z.string().describe("The ID of the payment request."), + displayItems: z.array( + z.object({ + label: z.string().describe("The label of the display item."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + pending: z + .boolean() + .optional() + .describe("If true, indicates the amount is not final."), + refundPeriod: z + .number() + .describe("The refund duration for this item, in days."), + }) + ), + shippingOptions: z.array( + z.object({ + id: z.string().describe("The ID of the shipping option."), + label: z.string().describe("The label of the shipping option."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + selected: z + .boolean() + .optional() + .describe("If the shipping option is selected."), + }) + ).optional(), + modifiers: z.array( + z.object({ + supportedMethods: z + .string() + .describe( + "The payment method ID that this modifier applies to." + ), + total: z.object({ + label: z.string().describe("The label of the total."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + pending: z + .boolean() + .optional() + .describe("If true, indicates the amount is not final."), + refundPeriod: z + .number() + .describe("The refund duration for this item, in days."), + }).optional(), + additionalDisplayItems: z.array( + z.object({ + label: z + .string() + .describe("The label of the additional display item."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + pending: z + .boolean() + .optional() + .describe("If true, indicates the amount is not final."), + refundPeriod: z + .number() + .describe("The refund duration for this item, in days."), + }) + ).optional(), + data: z.record(z.string(), z.any()).optional().describe("The data of the modifier."), + }) + ).optional(), + total: z.object({ + label: z + .string() + .describe("A human-readable description of the item."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + pending: z.boolean().optional().describe("If the amount is not final."), + refundPeriod: z + .number() + .default(30) + .describe("The refund duration for this item, in days."), + }), + }), + options: z.object({ + requestPayerName: z + .boolean() + .describe("If the payer's name should be collected.") + .optional(), + requestPayerEmail: z + .boolean() + .describe("If the payer's email should be collected.") + .optional(), + requestPayerPhone: z + .boolean() + .describe("If the payer's phone number should be collected.") + .optional(), + requestShipping: z + .boolean() + .describe("If the payer's shipping address should be collected.") + .optional(), + shippingType: z + .enum(["shipping", "delivery", "pickup"]) + .optional() + .describe("Can be `shipping`, `delivery`, or `pickup`."), + }), + shippingAddress: shippingAddressSchema + .optional() + .describe("The shipping address of the user."), + }) + .describe( + "The W3C PaymentRequest object to initiate payment. This contains the" + + "items being purchased, prices, and the set of payment methods" + + "accepted by the merchant for this cart." + ), + cartExpiry: z + .string() + .describe("When this cart expires, in ISO 8601 format."), + merchantName: z.string().describe("The name of the merchant."), + }), + merchantAuthorization: z + .string() + .describe( + ` + A base64url-encoded JSON Web Token (JWT) that digitally + signs the cart contents, guaranteeing its authenticity and integrity: + 1. Header includes the signing algorithm and key ID. + 2. Payload includes: + - iss, sub, aud: Identifiers for the merchant (issuer) + and the intended recipient (audience), like a payment processor. + - iat: iat, exp: Timestamps for the token's creation and its + short-lived expiration (e.g., 5-15 minutes) to enhance security. + - jti: Unique identifier for the JWT to prevent replay attacks. + - cart_hash: A secure hash of the CartMandate, ensuring + integrity. The hash is computed over the canonical JSON + representation of the CartContents object. + 3. Signature: A digital signature created with the merchant's private + key. It allows anyone with the public key to verify the token's + authenticity and confirm that the payload has not been tampered with. + The entire JWT is base64url encoded to ensure safe transmission. + ` + ) + .optional(), +}); diff --git a/code/samples/typescript/src/common/schemas/intent-mandate.ts b/code/samples/typescript/src/common/schemas/intent-mandate.ts new file mode 100644 index 00000000..ec9daa04 --- /dev/null +++ b/code/samples/typescript/src/common/schemas/intent-mandate.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from "zod"; + +export const intentMandateSchema = z.object({ + naturalLanguageDescription: z.string(), + userCartConfirmationRequired: z.boolean(), + merchants: z.array(z.string()).optional(), + skus: z.array(z.string()).optional(), + requiresRefundability: z.boolean().optional(), + intentExpiry: z.string(), +}); diff --git a/code/samples/typescript/src/common/schemas/payment-mandate.ts b/code/samples/typescript/src/common/schemas/payment-mandate.ts new file mode 100644 index 00000000..0761f8f4 --- /dev/null +++ b/code/samples/typescript/src/common/schemas/payment-mandate.ts @@ -0,0 +1,93 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from "zod"; +import { shippingAddressSchema } from "./shipping-address.js"; + +export const paymentMandateSchema = z.object({ + paymentMandateContents: z.object({ + paymentMandateId: z + .string() + .describe("A unique identifier for this payment mandate."), + paymentDetailsId: z + .string() + .describe("A unique identifier for the payment request."), + paymentDetailsTotal: z + .object({ + label: z.string().describe("A human-readable description of the item."), + amount: z.object({ + currency: z + .string() + .describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }), + pending: z + .boolean() + .optional() + .describe("If true, indicates the amount is not final."), + refundPeriod: z + .number() + .default(30) + .describe("The refund duration for this item, in days."), + }) + .describe("The total payment amount."), + paymentResponse: z + .object({ + requestId: z + .string() + .describe("The unique ID from the original PaymentRequest."), + methodName: z + .string() + .describe("The payment method chosen by the user."), + details: z + .record(z.string(), z.unknown()) + .optional() + .describe( + "A dictionary generated by a payment method that a merchant can use to process a transaction." + ), + shippingAddress: shippingAddressSchema.optional(), + shippingOption: z + .object({ + id: z.string(), + label: z.string(), + amount: z.object({ + currency: z.string(), + value: z.number(), + }), + selected: z.boolean().optional(), + }) + .optional(), + payerName: z.string().optional(), + payerEmail: z.string().optional(), + payerPhone: z.string().optional(), + }) + .describe( + "The payment response containing details of the payment method chosen by the user." + ), + merchantAgent: z.string().describe("Identifier for the merchant."), + timestamp: z + .string() + .describe( + "The date and time the mandate was created, in ISO 8601 format." + ), + }), + userAuthorization: z + .string() + .optional() + .describe( + "A base64url-encoded verifiable presentation signing over the cart and payment mandate hashes." + ), +}); diff --git a/code/samples/typescript/src/common/schemas/payment-receipt.ts b/code/samples/typescript/src/common/schemas/payment-receipt.ts new file mode 100644 index 00000000..8ef067fe --- /dev/null +++ b/code/samples/typescript/src/common/schemas/payment-receipt.ts @@ -0,0 +1,74 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from "zod"; + +export const paymentSuccessSchema = z.object({ + kind: z.literal("success"), + merchantConfirmationId: z + .string() + .describe("A unique identifier for the transaction confirmation at the merchant."), + pspConfirmationId: z + .string() + .optional() + .describe("A unique identifier for the transaction confirmation at the PSP."), + networkConfirmationId: z + .string() + .optional() + .describe("A unique identifier for the transaction confirmation at the network."), +}); + +export const paymentErrorSchema = z.object({ + kind: z.literal("error"), + errorMessage: z + .string() + .describe("A human-readable message explaining the error and how to proceed."), +}); + +export const paymentFailureSchema = z.object({ + kind: z.literal("failure"), + failureMessage: z + .string() + .describe("A human-readable message explaining the failure and how to proceed."), +}); + +export const paymentStatusSchema = z.discriminatedUnion("kind", [ + paymentSuccessSchema, + paymentErrorSchema, + paymentFailureSchema, +]); + +export const paymentReceiptSchema = z.object({ + paymentMandateId: z + .string() + .describe("A unique identifier for the processed payment mandate."), + timestamp: z + .string() + .describe("The date and time the payment receipt was created, in ISO 8601 format."), + paymentId: z + .string() + .describe("A unique identifier for the payment."), + amount: z.object({ + currency: z.string().describe("The three-letter ISO 4217 currency code."), + value: z.number().describe("The monetary value."), + }).describe("The monetary amount of the payment."), + paymentStatus: paymentStatusSchema + .describe("The status of the payment."), + paymentMethodDetails: z + .record(z.string(), z.unknown()) + .optional() + .describe("The payment method used for the transaction."), +}); diff --git a/code/samples/typescript/src/common/schemas/shipping-address.ts b/code/samples/typescript/src/common/schemas/shipping-address.ts new file mode 100644 index 00000000..65ba23ed --- /dev/null +++ b/code/samples/typescript/src/common/schemas/shipping-address.ts @@ -0,0 +1,30 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { z } from "zod"; + +export const shippingAddressSchema = z.object({ + city: z.string().optional(), + country: z.string().optional(), + dependent_locality: z.string().optional(), + organization: z.string().optional(), + phone_number: z.string().optional(), + postal_code: z.string().optional(), + recipient: z.string().optional(), + region: z.string().optional(), + sorting_code: z.string().optional(), + address_line: z.array(z.string()).optional(), +}); diff --git a/code/samples/typescript/src/common/sdjwt/crypto.ts b/code/samples/typescript/src/common/sdjwt/crypto.ts new file mode 100644 index 00000000..1e6e16fc --- /dev/null +++ b/code/samples/typescript/src/common/sdjwt/crypto.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * ES256 crypto primitives for SD-JWT, backed by @sd-jwt/crypto-nodejs + * (WebCrypto under the hood). AP2 v0.2 mandates ES256 (ECDSA P-256) for + * mandate SD-JWTs, so this is the single algorithm used across issue, + * present (key-binding), and verify. + */ + +import { ES256, digest, generateSalt } from '@sd-jwt/crypto-nodejs'; +import type { Hasher, SaltGenerator, Signer, Verifier } from '@sd-jwt/types'; + +/** A P-256 JSON Web Key (public or private). */ +export type Es256Jwk = JsonWebKey; + +export interface Es256KeyPair { + publicKey: Es256Jwk; + privateKey: Es256Jwk; +} + +export const ALG = ES256.alg; // "ES256" + +/** Hasher (sha-256) compatible with @sd-jwt SDJwtInstance config. */ +export const hasher: Hasher = (data, alg) => digest(data, alg); + +/** Salt generator for selective-disclosure commitments. */ +export const saltGenerator: SaltGenerator = (length: number) => generateSalt(length); + +export async function generateKeyPair(): Promise { + return ES256.generateKeyPair(); +} + +export async function makeSigner(privateJwk: Es256Jwk): Promise { + return ES256.getSigner(privateJwk); +} + +export async function makeVerifier(publicJwk: Es256Jwk): Promise { + return ES256.getVerifier(publicJwk); +} diff --git a/code/samples/typescript/src/common/sdjwt/index.ts b/code/samples/typescript/src/common/sdjwt/index.ts new file mode 100644 index 00000000..a7441ba3 --- /dev/null +++ b/code/samples/typescript/src/common/sdjwt/index.ts @@ -0,0 +1,18 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Barrel for shared ES256 primitives: keypair generation, a file-backed JWK + * key store, and plain compact JWS (used for the merchant checkout JWT and the + * PSP / merchant receipts). The Verifiable Intent SD-JWT delegation chain lives + * in `src/common/vi` (backed by @verifiable-intent/core). + */ + +export * from './crypto.js'; +export * from './jwt.js'; +export * from './key-store.js'; diff --git a/code/samples/typescript/src/common/sdjwt/jwt.ts b/code/samples/typescript/src/common/sdjwt/jwt.ts new file mode 100644 index 00000000..24547345 --- /dev/null +++ b/code/samples/typescript/src/common/sdjwt/jwt.ts @@ -0,0 +1,59 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Plain ES256 compact JWS (JWT) helpers — distinct from the SD-JWT mandate + * format. Used for artifacts that are signed but not selectively disclosed: + * the merchant-signed checkout JWT and the PSP-signed payment receipt. + * + * Built directly on the ES256 signer/verifier from crypto.ts (ECDSA P-256), + * producing a standard `..` + * compact JWS. + */ + +import { ALG, makeSigner, makeVerifier, type Es256Jwk } from './crypto.js'; + +function b64urlJson(value: unknown): string { + return Buffer.from(JSON.stringify(value)).toString('base64url'); +} + +/** Sign a payload as a compact ES256 JWS. */ +export async function signJwtEs256( + payload: Record, + privateJwk: Es256Jwk, +): Promise { + const signer = await makeSigner(privateJwk); + const header = { alg: ALG, typ: 'JWT' }; + const signingInput = `${b64urlJson(header)}.${b64urlJson(payload)}`; + const signature = await signer(signingInput); + return `${signingInput}.${signature}`; +} + +/** + * Verify a compact ES256 JWS and return its payload. + * @throws if the token is malformed or the signature does not verify. + */ +export async function verifyJwtEs256( + compact: string, + publicJwk: Es256Jwk, +): Promise> { + const parts = compact.split('.'); + if (parts.length !== 3) { + throw new Error('malformed JWT: expected three dot-separated segments'); + } + const [headerB64, payloadB64, signature] = parts; + const verifier = await makeVerifier(publicJwk); + const ok = await verifier(`${headerB64}.${payloadB64}`, signature); + if (!ok) { + throw new Error('invalid JWT signature'); + } + return JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf-8')) as Record< + string, + unknown + >; +} diff --git a/code/samples/typescript/src/common/sdjwt/key-store.ts b/code/samples/typescript/src/common/sdjwt/key-store.ts new file mode 100644 index 00000000..233f95ab --- /dev/null +++ b/code/samples/typescript/src/common/sdjwt/key-store.ts @@ -0,0 +1,43 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * File-backed ES256 keypair store. Each role (user, agent, merchant, psp) + * persists its keypair as `_key.jwk.json` under a shared TEMP_DB so that + * separate processes (the agent and each MCP subprocess) can resolve the same + * public keys and verify each other's signatures. + */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { generateKeyPair, type Es256Jwk, type Es256KeyPair } from './crypto.js'; + +function keyPath(tempDb: string, name: string): string { + return path.join(tempDb, `${name}_key.jwk.json`); +} + +/** Load the named keypair, generating + persisting it on first use. */ +export async function loadOrCreateKeyPair(tempDb: string, name: string): Promise { + try { + return JSON.parse(fs.readFileSync(keyPath(tempDb, name), 'utf-8')) as Es256KeyPair; + } catch { + const pair = await generateKeyPair(); + fs.mkdirSync(tempDb, { recursive: true }); + fs.writeFileSync(keyPath(tempDb, name), JSON.stringify(pair)); + return pair; + } +} + +/** Read just the public JWK of a previously persisted keypair (null if absent). */ +export function loadPublicJwk(tempDb: string, name: string): Es256Jwk | null { + try { + return (JSON.parse(fs.readFileSync(keyPath(tempDb, name), 'utf-8')) as Es256KeyPair).publicKey; + } catch { + return null; + } +} diff --git a/code/samples/typescript/src/common/server/a2a-context.ts b/code/samples/typescript/src/common/server/a2a-context.ts new file mode 100644 index 00000000..dd0a9bdf --- /dev/null +++ b/code/samples/typescript/src/common/server/a2a-context.ts @@ -0,0 +1,93 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Task } from '@a2a-js/sdk'; +import type { ExecutionEventBus } from '@a2a-js/sdk/server'; + +/** + * Per-request A2A context that must bypass ADK's session cloneDeep. + * + * ADK's InMemorySessionService deep-clones session state on every + * getSession/createSession call, which breaks live object references + * (eventBus methods, task object identity). This module-level Map + * provides a side-channel for tools to access these live objects. + */ +export interface A2AContext { + dataParts: Record[]; + eventBus: ExecutionEventBus; + currentTask: Task; +} + +const contextStore = new Map(); + +/** Store A2A context for a session. Called by executor before runner.runAsync. */ +export function setA2AContext(sessionId: string, ctx: A2AContext): void { + contextStore.set(sessionId, ctx); +} + +/** Retrieve A2A context inside a tool. Uses the session ID from tool context. */ +export function getA2AContext(sessionId: string): A2AContext | undefined { + return contextStore.get(sessionId); +} + +/** No-op event bus for ADK dev mode (npm run dev) where no A2A server is running. */ +const noopEventBus: ExecutionEventBus = { + publish: () => {}, + finished: () => {}, +} as unknown as ExecutionEventBus; + +/** + * Retrieve A2A context from a tool's execution context. + * This is the primary API for tools to access dataParts, eventBus, and currentTask. + * + * When running in ADK dev mode (npm run dev), no BaseAgentExecutor is active, + * so no A2A context exists. In that case, returns a fallback context with + * empty dataParts and a no-op eventBus so tools degrade gracefully. + * + * @param toolContext - The tool's execution context (second arg of FunctionTool.execute) + * @returns The A2A context with dataParts, eventBus, and currentTask + */ +export function getA2AContextFromTool(toolContext: { + invocationContext: { session: { id: string } }; +}): A2AContext { + const sessionId = toolContext.invocationContext.session.id; + const ctx = contextStore.get(sessionId); + if (!ctx) { + // ADK dev mode fallback: no A2A server running, return safe defaults + console.warn( + `[A2A] No context for session ${sessionId} — running in ADK dev mode. ` + + 'Using fallback (empty dataParts, no-op eventBus).' + ); + return { + dataParts: [], + eventBus: noopEventBus, + currentTask: { + kind: 'task', + id: sessionId, + contextId: sessionId, + status: { state: 'working', timestamp: new Date().toISOString() }, + history: [], + artifacts: [], + } as Task, + }; + } + return ctx; +} + +/** Clean up after request completes. Called by executor after runner finishes. */ +export function clearA2AContext(sessionId: string): void { + contextStore.delete(sessionId); +} diff --git a/code/samples/typescript/src/common/server/base-executor.ts b/code/samples/typescript/src/common/server/base-executor.ts new file mode 100644 index 00000000..7b480feb --- /dev/null +++ b/code/samples/typescript/src/common/server/base-executor.ts @@ -0,0 +1,464 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { v4 as uuidv4 } from 'uuid'; +import type { Runner } from '@google/adk'; +import type { + DataPart, + Message, + Task, + TaskStatusUpdateEvent, + TextPart, +} from '@a2a-js/sdk'; +import type { + AgentExecutor, + RequestContext, + ExecutionEventBus, +} from '@a2a-js/sdk/server'; +import { sessionService } from '../config/session.js'; +import { setA2AContext, clearA2AContext } from './a2a-context.js'; + +interface ADKEvent { + author: string; + content?: { + parts?: Array<{ + text?: string; + thought?: boolean; + functionCall?: { name: string; args: unknown; id: string }; + functionResponse?: { name: string; response: unknown; id: string }; + }>; + role?: string; + }; + finishReason?: string; + usageMetadata?: unknown; +} + +interface BaseExecutorOptions { + agentName: string; + appName: string; + runner: Runner; + workingMessage: string; + /** Maximum number of LLM calls per request. Defaults to 10. */ + maxLlmCalls?: number; + /** Called before ADK agent runs. Return modified message text or undefined to use original. */ + preprocessMessage?: (params: { + userText: string; + dataParts: Record[]; + existingTask: Task | undefined; + session: { state: Record }; + }) => string | undefined; + /** Called after ADK event loop. Return to override default completion behavior. */ + postprocessResult?: (params: { + responseText: string; + toolWasCalled: boolean; + lastToolResult: Record | undefined; + session: { state: Record }; + eventBus: ExecutionEventBus; + taskId: string; + contextId: string; + }) => TaskStatusUpdateEvent | null | undefined; + /** Called before session creation to inject extra state. */ + initSessionState?: (params: { + dataParts: Record[]; + session: { state: Record }; + }) => void; + /** + * Called after session init but before ADK runner executes. + * Return a TaskStatusUpdateEvent to short-circuit execution (e.g., when a + * previous result is cached). Return undefined to proceed normally. + */ + shouldShortCircuit?: (params: { + session: { state: Record }; + dataParts: Record[]; + eventBus: ExecutionEventBus; + taskId: string; + contextId: string; + }) => TaskStatusUpdateEvent | undefined; +} + +/** + * Base executor that implements the common A2A agent execution pattern. + * Reduces ~200 lines of boilerplate per server to ~20 lines of config. + */ +export class BaseAgentExecutor implements AgentExecutor { + private cancelledTasks = new Map(); + private static readonly CANCELLED_TASK_TTL_MS = 5 * 60 * 1000; // 5 minutes + private options: BaseExecutorOptions; + + constructor(options: BaseExecutorOptions) { + this.options = options; + // Periodic cleanup of expired cancellation entries + setInterval(() => { + const now = Date.now(); + for (const [taskId, timestamp] of this.cancelledTasks) { + if (now - timestamp > BaseAgentExecutor.CANCELLED_TASK_TTL_MS) { + this.cancelledTasks.delete(taskId); + } + } + }, 60_000).unref(); + } + + public cancelTask = async (taskId: string, eventBus: ExecutionEventBus) => { + this.cancelledTasks.set(taskId, Date.now()); + eventBus.publish({ + kind: 'status-update', + taskId, + contextId: '', + status: { + state: 'canceled', + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + eventBus.finished(); + }; + + private isTaskCancelled(taskId: string): boolean { + return this.cancelledTasks.has(taskId); + } + + async execute(requestContext: RequestContext, eventBus: ExecutionEventBus) { + const { agentName, appName, runner, workingMessage } = this.options; + const userMessage = requestContext.userMessage; + const existingTask = requestContext.task; + + const taskId = existingTask?.id || uuidv4(); + const contextId = + userMessage.contextId || existingTask?.contextId || uuidv4(); + + // Publish initial task if new + if (!existingTask) { + const initialTask: Task = { + kind: 'task', + id: taskId, + contextId, + status: { + state: 'submitted', + timestamp: new Date().toISOString(), + }, + history: [userMessage], + metadata: userMessage.metadata, + artifacts: [], + }; + eventBus.publish(initialTask); + } + + // Publish working status + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'working', + message: { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: workingMessage }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: false, + } satisfies TaskStatusUpdateEvent); + + // Extract text from message + const userText = userMessage.parts + .filter((p): p is TextPart => p.kind === 'text' && !!(p as TextPart).text) + .map((p) => p.text) + .join('\n'); + + if (!userText) { + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'failed', + message: { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: 'No input message found to process.' }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + eventBus.finished(); + return; + } + + // Extract dataParts from A2A message + const dataParts = userMessage.parts + .filter((p): p is DataPart => p.kind === 'data') + .map((p) => p.data); + + const currentTask: Task = existingTask || { + kind: 'task', + id: taskId, + contextId, + status: { + state: 'working', + timestamp: new Date().toISOString(), + }, + history: [userMessage], + artifacts: [], + }; + + try { + // Get or create ADK session + let session = await sessionService.getSession({ + appName, + userId: 'user', + sessionId: contextId, + }); + + if (!session) { + session = await sessionService.createSession({ + appName, + userId: 'user', + sessionId: contextId, + }); + } + + // Allow subclass to inject extra session state + if (this.options.initSessionState) { + this.options.initSessionState({ dataParts, session }); + } + + // Allow subclass to short-circuit before running the ADK agent + if (this.options.shouldShortCircuit) { + const shortCircuit = this.options.shouldShortCircuit({ + session, + dataParts, + eventBus, + taskId, + contextId, + }); + if (shortCircuit) { + eventBus.publish(shortCircuit); + eventBus.finished(); + return; + } + } + + // Store A2A context in a side-channel that bypasses ADK's cloneDeep. + // ADK's InMemorySessionService deep-clones session state on every + // getSession() call, which breaks live object references (eventBus, + // currentTask). The side-channel Map lets tools look up these objects + // by session ID without going through cloneDeep. + setA2AContext(session.id, { dataParts, eventBus, currentTask }); + + try { + // Allow subclass to preprocess the message + let messageText = this.options.preprocessMessage?.({ + userText, + dataParts, + existingTask, + session, + }) ?? userText; + + // Append a structured summary of A2A data parts so the LLM knows + // what data is available and can decide which tool to call. Tools + // access the full objects via the side-channel, but the LLM needs + // visibility into available keys and values to make correct decisions. + if (dataParts.length > 0) { + const dataPartSummaries = dataParts.map((dp) => { + const entries = Object.entries(dp).map(([key, value]) => { + // For large objects, show type + top-level keys; for scalars show the value + if (value && typeof value === 'object') { + const topKeys = Object.keys(value as Record).slice(0, 5); + return ` ${key}: {${topKeys.join(', ')}${topKeys.length < Object.keys(value as Record).length ? ', ...' : ''}}`; + } + return ` ${key}: ${JSON.stringify(value)}`; + }); + return entries.join('\n'); + }); + messageText += `\n\n[Available data parts — call the appropriate tool to process them, do NOT ask the user for this data]:\n${dataPartSummaries.join('\n')}`; + } + + // Run ADK agent with a bounded number of LLM calls to prevent infinite loops + const events = runner.runAsync({ + userId: 'user', + sessionId: session.id, + newMessage: { + role: 'user', + parts: [{ text: messageText }], + }, + runConfig: { + maxLlmCalls: this.options.maxLlmCalls ?? 10, + }, + }); + + // Collect response and stream intermediate status updates + let responseText = ''; + let toolWasCalled = false; + let lastToolResult: Record | undefined; + let agentEventCount = 0; + + for await (const event of events) { + // Check for cancellation during execution + if (this.isTaskCancelled(taskId)) { + eventBus.finished(); + return; + } + + const adkEvent = event as unknown as ADKEvent; + // Count and extract content from any agent-authored event (root or + // sub_agent). Sub_agents handle most user-facing replies in + // multi-agent flows, so restricting to the root agent loses content. + if (adkEvent.author && adkEvent.author !== 'user') { + agentEventCount++; + const parts = adkEvent.content?.parts; + if (parts && Array.isArray(parts)) { + // Extract text responses (skip internal thought parts) + const textContent = parts.find((c) => c.text && !c.thought); + if (textContent?.text) { + responseText = textContent.text; + } + // Detect function calls + if (parts.some((c) => c.functionCall)) { + toolWasCalled = true; + } + // Extract function response results + const funcResponse = parts.find((c) => c.functionResponse); + if (funcResponse?.functionResponse?.response) { + lastToolResult = funcResponse.functionResponse.response as Record; + } + } + } + } + + // Detect silent LLM failures: no agent events means the model + // likely returned an error that the ADK swallowed + if (agentEventCount === 0) { + console.error(`[${agentName}] No events received from ADK — possible LLM API error`); + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'failed', + message: { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: 'Agent failed: no response from LLM. Check API key and model configuration.' }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + eventBus.finished(); + return; + } + + // Re-fetch session to pick up state changes made by tools during + // the runner execution. ADK's InMemorySessionService deep-clones on + // getSession(), so the `session` variable from before the run is stale. + const updatedSession = await sessionService.getSession({ + appName, + userId: 'user', + sessionId: contextId, + }); + + // Allow subclass to handle special post-processing + if (this.options.postprocessResult) { + const override = this.options.postprocessResult({ + responseText, + toolWasCalled, + lastToolResult, + session: updatedSession || session, + eventBus, + taskId, + contextId, + }); + if (override) { + eventBus.publish(override); + eventBus.finished(); + return; + } + // If postprocessResult returns null, it handled publishing itself + if (override === null) { + eventBus.finished(); + return; + } + } + + // Default: publish completion + const finalText = responseText || + (toolWasCalled ? 'Request processed successfully.' : 'Completed.'); + + const agentMessage: Message = { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: finalText }], + taskId, + contextId, + }; + + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'completed', + message: agentMessage, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + eventBus.finished(); + + } finally { + clearA2AContext(session.id); + } + + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error occurred'; + + console.error(`[${agentName}] Error:`, errorMessage); + + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'failed', + message: { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: `Agent error: ${errorMessage}` }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + eventBus.finished(); + } + } +} diff --git a/code/samples/typescript/src/common/server/bootstrap.ts b/code/samples/typescript/src/common/server/bootstrap.ts new file mode 100644 index 00000000..89ab5de6 --- /dev/null +++ b/code/samples/typescript/src/common/server/bootstrap.ts @@ -0,0 +1,96 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; +import type { Server } from 'http'; +import type { AgentCard } from '@a2a-js/sdk'; +import { + InMemoryTaskStore, + type AgentExecutor, + DefaultRequestHandler, +} from '@a2a-js/sdk/server'; +import { A2AExpressApp } from '@a2a-js/sdk/server/express'; +import { createRateLimiter, validateA2ARequest } from './middleware.js'; + +interface BootstrapOptions { + agentCard: AgentCard; + agentExecutor: AgentExecutor; + port: number; + label: string; +} + +/** + * Bootstraps an A2A Express server with rate limiting and validation. + * Returns the HTTP server handle for graceful shutdown and testing. + */ +export function bootstrapServer(options: BootstrapOptions): Server { + const { agentCard, agentExecutor, port, label } = options; + + const taskStore = new InMemoryTaskStore(); + const requestHandler = new DefaultRequestHandler( + agentCard, + taskStore, + agentExecutor + ); + + const appBuilder = new A2AExpressApp(requestHandler); + const app = express(); + + // Parse JSON bodies before validation middleware can inspect them. + // A JSON error handler is required here because the SDK adds its own + // express.json() + jsonErrorHandler on the router, but this app-level + // parser runs first. Without a handler, a SyntaxError from malformed + // JSON (e.g. bad escape sequences) propagates to Express's default + // error handler which crashes the agent process. + app.use(express.json()); + app.use((err: Error, _req: express.Request, res: express.Response, next: express.NextFunction) => { + if (err instanceof SyntaxError && 'body' in err) { + res.status(400).json({ + jsonrpc: '2.0', + id: null, + error: { + code: -32700, + message: 'Parse error: invalid JSON in request body.', + }, + }); + return; + } + next(err); + }); + + // Apply middleware before A2A routes + app.use(createRateLimiter({ windowMs: 60_000, maxRequests: 60 })); + app.use(validateA2ARequest); + + // Health check endpoint + app.get('/health', (_req: express.Request, res: express.Response) => { + res.json({ status: 'ok', agent: agentCard.name, timestamp: new Date().toISOString() }); + }); + + const expressApp = appBuilder.setupRoutes(app); + + const PORT = process.env.PORT || port; + const server = expressApp.listen(PORT, () => { + console.log(`[${label}] Running on http://localhost:${PORT}`); + }); + + // Workaround: keep the event loop alive on Node v23+ with tsx where + // ADK agent imports can cause the server's TCP handle to be unref'd + const keepAlive = setInterval(() => {}, 1 << 30); + server.on('close', () => clearInterval(keepAlive)); + + return server; +} diff --git a/code/samples/typescript/src/common/server/middleware.ts b/code/samples/typescript/src/common/server/middleware.ts new file mode 100644 index 00000000..a4846db7 --- /dev/null +++ b/code/samples/typescript/src/common/server/middleware.ts @@ -0,0 +1,121 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Request, Response, NextFunction } from 'express'; + +/** + * Simple in-memory rate limiter for A2A endpoints. + * Tracks request counts per IP within a fixed window. + */ +export function createRateLimiter(options: { + windowMs: number; + maxRequests: number; +}) { + const { windowMs, maxRequests } = options; + const requestCounts = new Map(); + + // Periodic cleanup of expired entries + const cleanupTimer = setInterval(() => { + const now = Date.now(); + for (const [key, entry] of requestCounts) { + if (now > entry.resetTime) { + requestCounts.delete(key); + } + } + }, windowMs); + cleanupTimer.unref(); + + return (req: Request, res: Response, next: NextFunction): void => { + const clientIp = req.ip || req.socket.remoteAddress || 'unknown'; + const now = Date.now(); + + const entry = requestCounts.get(clientIp); + + if (!entry || now > entry.resetTime) { + requestCounts.set(clientIp, { count: 1, resetTime: now + windowMs }); + next(); + return; + } + + if (entry.count >= maxRequests) { + const requestId = req.body?.id ?? null; + res.status(429).json({ + jsonrpc: '2.0', + id: requestId, + error: { + code: -32000, + message: 'Too many requests. Please try again later.', + }, + }); + return; + } + + entry.count++; + next(); + }; +} + +/** + * Validates that incoming JSON-RPC requests have the required A2A structure. + */ +export function validateA2ARequest(req: Request, res: Response, next: NextFunction): void { + // Only validate POST requests to the A2A endpoint + if (req.method !== 'POST' || !req.path.endsWith('/')) { + next(); + return; + } + + const body = req.body; + const requestId = body?.id ?? null; + + if (!body || typeof body !== 'object') { + res.status(400).json({ + jsonrpc: '2.0', + id: null, + error: { + code: -32600, + message: 'Invalid request: body must be a JSON object.', + }, + }); + return; + } + + if (body.jsonrpc !== '2.0') { + res.status(400).json({ + jsonrpc: '2.0', + id: requestId, + error: { + code: -32600, + message: 'Invalid request: jsonrpc must be "2.0".', + }, + }); + return; + } + + if (!body.method || typeof body.method !== 'string') { + res.status(400).json({ + jsonrpc: '2.0', + id: requestId, + error: { + code: -32600, + message: 'Invalid request: method is required.', + }, + }); + return; + } + + next(); +} diff --git a/code/samples/typescript/src/common/types/cart-mandate.ts b/code/samples/typescript/src/common/types/cart-mandate.ts new file mode 100644 index 00000000..e4f84662 --- /dev/null +++ b/code/samples/typescript/src/common/types/cart-mandate.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { cartMandateSchema } from "../schemas/cart-mandate.js"; +import type { z } from "zod"; + +export type CartMandate = z.infer; diff --git a/code/samples/typescript/src/common/types/intent-mandate.ts b/code/samples/typescript/src/common/types/intent-mandate.ts new file mode 100644 index 00000000..a30f3695 --- /dev/null +++ b/code/samples/typescript/src/common/types/intent-mandate.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { intentMandateSchema } from "../schemas/intent-mandate.js"; +import type { z } from "zod"; + +export type IntentMandate = z.infer; diff --git a/code/samples/typescript/src/common/types/payment-item.ts b/code/samples/typescript/src/common/types/payment-item.ts new file mode 100644 index 00000000..f51d90e2 --- /dev/null +++ b/code/samples/typescript/src/common/types/payment-item.ts @@ -0,0 +1,27 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type PaymentCurrencyAmount = { + currency: string; + value: number; +}; + +export type PaymentItem = { + label: string; + amount: PaymentCurrencyAmount; + pending?: boolean; + refundPeriod: number; +}; diff --git a/code/samples/typescript/src/common/types/payment-mandate.ts b/code/samples/typescript/src/common/types/payment-mandate.ts new file mode 100644 index 00000000..35d21114 --- /dev/null +++ b/code/samples/typescript/src/common/types/payment-mandate.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { paymentMandateSchema } from "../schemas/payment-mandate.js"; +import type { z } from "zod"; + +export type PaymentMandate = z.infer; diff --git a/code/samples/typescript/src/common/types/payment-receipt.ts b/code/samples/typescript/src/common/types/payment-receipt.ts new file mode 100644 index 00000000..570685da --- /dev/null +++ b/code/samples/typescript/src/common/types/payment-receipt.ts @@ -0,0 +1,20 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { paymentReceiptSchema } from "../schemas/payment-receipt.js"; +import type { z } from "zod"; + +export type PaymentReceipt = z.infer; diff --git a/code/samples/typescript/src/common/utils/artifact.ts b/code/samples/typescript/src/common/utils/artifact.ts new file mode 100644 index 00000000..8ed1becb --- /dev/null +++ b/code/samples/typescript/src/common/utils/artifact.ts @@ -0,0 +1,70 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Artifact, DataPart } from "@a2a-js/sdk"; + +/** + * Extracts and validates canonical objects from A2A artifacts by data key. + * + * Searches through artifact parts for DataParts that contain the specified + * key, then validates each match with the provided schema. + * + * @param artifacts - The A2A artifacts to search + * @param dataKey - The data key to look for (e.g., "ap2.mandates.CartMandate") + * @param schema - A Zod-style schema with a `parse` method for validation + * @returns An array of validated objects + */ +export function findCanonicalObjects( + artifacts: Artifact[], + dataKey: string, + schema: { parse: (data: unknown) => T } +): T[] { + const canonicalObjects: T[] = []; + + for (const artifact of artifacts) { + for (const part of artifact.parts) { + if (part.kind === "data") { + const data = (part as DataPart).data as Record; + if (data[dataKey]) { + try { + const validatedObject = schema.parse(data[dataKey]); + canonicalObjects.push(validatedObject); + } catch (error) { + console.warn(`Failed to validate object for key ${dataKey}:`, error); + } + } + } + } + } + + return canonicalObjects; +} + +/** + * Returns the data from the first DataPart found across all artifacts. + */ +export const getFirstDataPart = ( + artifacts: Artifact[] +): Record => { + for (const artifact of artifacts) { + for (const part of artifact.parts) { + if (part.kind === "data") { + return (part as DataPart).data as Record; + } + } + } + return {}; +}; diff --git a/code/samples/typescript/src/common/utils/message.ts b/code/samples/typescript/src/common/utils/message.ts new file mode 100644 index 00000000..21ada712 --- /dev/null +++ b/code/samples/typescript/src/common/utils/message.ts @@ -0,0 +1,83 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Finds and returns the value for the first occurrence of the key in the data parts. + * + * @param dataKey - The key to search for. + * @param dataParts - The data parts to be searched (array of objects with data). + * @returns The value for the first occurrence of the key, or null if not found. + */ +export const findDataPart = ( + dataKey: string, + dataParts: Record[] +): unknown => { + for (const dataPart of dataParts) { + if (dataKey in dataPart) { + return dataPart[dataKey]; + } + } + return null; +}; + +/** + * Finds and returns all values for the given key in the data parts. + * + * @param dataKey - The key to search for. + * @param dataParts - The data parts to be searched (array of objects with data). + * @returns An array of all values for the given key. + */ +export const findDataParts = ( + dataKey: string, + dataParts: Record[] +): unknown[] => { + const dataPartsWithKey: unknown[] = []; + for (const dataPart of dataParts) { + if (dataKey in dataPart) { + dataPartsWithKey.push(dataPart[dataKey]); + } + } + return dataPartsWithKey; +}; + +/** + * Converts the data part value for the given key to a canonical object using a Zod schema. + * This is the TypeScript equivalent of Python's parse_canonical_object. + * + * @param dataKey - The key to search for. + * @param dataParts - The data parts to be searched (array of objects with data). + * @param schema - The Zod schema to validate and parse the data. + * @returns The canonical object created from the data part value. + * @throws Error if the data key is not found or validation fails. + * + * @example + * const paymentMandate = parseCanonicalObject( + * "ap2.mandates.PaymentMandate", + * dataParts, + * paymentMandateSchema + * ); + */ +export const parseCanonicalObject = ( + dataKey: string, + dataParts: Record[], + schema: { parse: (data: unknown) => T } +): T => { + const canonicalObjectData = findDataPart(dataKey, dataParts); + if (!canonicalObjectData) { + throw new Error(`${dataKey} not found in data parts.`); + } + return schema.parse(canonicalObjectData); +}; diff --git a/code/samples/typescript/src/common/vi/README.md b/code/samples/typescript/src/common/vi/README.md new file mode 100644 index 00000000..929d5152 --- /dev/null +++ b/code/samples/typescript/src/common/vi/README.md @@ -0,0 +1,85 @@ + + +# `common/vi` — Verifiable Intent integration + +TypeScript replication of the official Python reference flow +(`verifiable_intent/python/examples`), wired into the AP2 sample. It is a thin, +per-role facade over the [`@verifiable-intent/core`](https://www.npmjs.com/package/@verifiable-intent/core) +library that produces a cryptographic, layered SD-JWT delegation chain so a +merchant and a payment network can independently prove an autonomous agent +purchased **exactly what the human authorized**. + +## The layer model + +A chain of signed credentials, each one binding the **next** signer's key +(`cnf.jwk`, RFC 7800) and the **previous** document's hash (`sd_hash`): + +| Layer | Signed by | Says | VI call | +|---|---|---|---| +| **L1** issuer credential | Credentials Provider | "this card belongs to the user" + binds the **user** key | `issueIssuerCredential` → `createLayer1` | +| **L2** user mandate | User | "I authorize **this agent** within these limits" + constraints | `createUserMandate{Autonomous,Immediate}` | +| **L3a** payment (→ network) | Agent | "pay $X to merchant M for txn T" | `createLayer3Payment` | +| **L3b** checkout (→ merchant) | Agent | "here is the final checkout JWT" | `createLayer3Checkout` | + +Two modes: **autonomous** (Human-Not-Present — L1→L2→split-L3, the agent acts +later within the mandate) and **immediate** (Human-Present — L1→L2 with final +values, no L3). Amounts are always **minor units (cents)**. + +## AP2 role → layer mapping + +``` + Credentials Provider User / shopping-agent-v2 Shopping Agent + = Issuer (L1) = User mandate (L2) = Agent (L3 split) + │ │ │ + │ L1 (binds user key) │ L2 (binds agent key, │ L3a → network + └────────────────────────► │ constraints) ────────► │ L3b → merchant + │ + merchant-agent-mcp ── verifyCheckoutChain (L1→L2→L3b, aud-pinned) ◄── L3b + credentials-provider-mcp ── verifyPaymentChainAndConstraints (L1→L2→L3a) ◄── L3a +``` + +## Cross-role file contract (TEMP_DB) + +The agent persists serialized SD-JWTs; the MCP servers read them back by id: + +| File | Written by | Read by | +|---|---|---| +| `l1.sdjwt`, `l2.sdjwt` | `assembleAndSignMandates` | merchant, CP | +| `.sdjwt`, `.l2.sdjwt` | `createMandateFulfillment` (merchant view) | merchant `complete_checkout` | +| `.sdjwt`, `.l2.sdjwt` | `createMandateFulfillment` (network view) | CP `issue_payment_credential` | +| `_key.jwk.json` | `loadOrCreateViKey` | every role | + +## Public API (`flow.ts`) + +- `issueIssuerCredential(params) → l1Serialized` +- `createUserMandateAutonomous(params) → l2Serialized` +- `createUserMandateImmediate(params) → l2Serialized` +- `createAgentFulfillment(params) → { l3PaymentSerialized, l3CheckoutSerialized, l2PaymentSerialized, l2CheckoutSerialized }` +- `verifyCheckoutChain(params) → ChainVerificationResult` *(merchant; pin `expectedL3CheckoutAud`)* +- `verifyPaymentChainAndConstraints(params) → { valid, errors, result, constraints }` *(network; pin `expectedL3PaymentAud`)* + +Plus `fixtures.ts` (scenario data + `MERCHANT_AUD`/`NETWORK_AUD`), `keys.ts` +(file-backed JWK key store), `checkout-jwt.ts` (merchant checkout JWS). + +## Security properties (enforced + tested) + +Verified in `test/unit/vi-*.test.ts` (28 of 30 unit tests cover this module; +`src/common/vi` ≈96% stmts / 91% funcs): + +- **Issuer trust** — chain fails closed without the issuer key; wrong key rejected. +- **Delegation binding** — only the `cnf`-bound agent key can sign a valid L3 + (an impostor key, even with a matching `kid`, is rejected). +- **Layer binding** — `sd_hash` ties L2→L1 and L3→L2; a tampered mandate fails. +- **Audience binding** — verifiers pin `aud`, rejecting a presentation addressed + to a different party. +- **Spend cap** — amount at-cap allowed, one minor unit over / wrong currency rejected. +- **Freshness** — expired L3 (exp ≤ iat+3600) rejected. + +## Known gaps (need a live e2e session to fix + verify) + +See `../../../BACKLOG.md`: payment-token↔checkout binding, replay/nonce dedup, +and full e2e validation of the item-id consent fix. These involve the running +MCP/A2A servers and a Gemini key, so they can't be exercised by the unit suite. diff --git a/code/samples/typescript/src/common/vi/checkout-jwt.ts b/code/samples/typescript/src/common/vi/checkout-jwt.ts new file mode 100644 index 00000000..8149e6f0 --- /dev/null +++ b/code/samples/typescript/src/common/vi/checkout-jwt.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Merchant-signed checkout JWT — a plain ES256 compact JWS committing the cart. + * Port of python/examples/helpers.py `create_checkout_jwt` / `checkout_hash_from_jwt`. + * The checkout hash binds the Payment Mandate to the checkout (transaction_id) + * and the Layer 3 fulfillment to the merchant cart. + */ + +import { hashBytes, jwtEncode, makeSigner, utf8 } from '@verifiable-intent/core'; +import { findProduct } from './fixtures.js'; +import type { ViKeyPair } from './keys.js'; + +export interface CartLineItem { + sku: string; + quantity?: number; +} + +/** Build and sign a merchant checkout JWT from line items (ES256, merchant key). */ +export async function createCheckoutJwt(items: CartLineItem[], merchant: ViKeyPair): Promise { + const now = Math.floor(Date.now() / 1000); + const cartItems: Record[] = []; + let totalCents = 0; + + for (const item of items) { + const product = findProduct(item.sku); + if (!product) { + throw new Error(`Product ${item.sku} not found`); + } + const qty = item.quantity ?? 1; + totalCents += product.price * qty; + cartItems.push({ + sku: product.sku, + name: product.name, + size: product.size, + size_label: product.sizeLabel, + color: product.color, + quantity: qty, + unitPrice: product.price / 100, // display price in dollars + }); + } + + const payload = { + iss: 'https://tennis-warehouse.com', + sub: 'cart_checkout', + iat: now, + exp: now + 3600, + cart: { + items: cartItems, + subTotal: { amount: totalCents / 100, currencyCode: 'USD' }, + }, + }; + const header = { alg: 'ES256', typ: 'JWT', kid: merchant.kid }; + const signer = await makeSigner(merchant.privateKey); + return jwtEncode(header, payload, signer); +} + +/** SHA-256(base64url) of a checkout JWT string — the checkout hash / transaction id. */ +export function checkoutHashFromJwt(checkoutJwt: string): string { + return hashBytes(utf8(checkoutJwt)); +} diff --git a/code/samples/typescript/src/common/vi/fixtures.ts b/code/samples/typescript/src/common/vi/fixtures.ts new file mode 100644 index 00000000..845ee698 --- /dev/null +++ b/code/samples/typescript/src/common/vi/fixtures.ts @@ -0,0 +1,93 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Scenario fixtures for the Verifiable Intent flow — a direct port of the + * `verifiable_intent` Python reference examples (python/examples/helpers.py): + * a tennis-racket purchase across two acceptable merchants. These define the + * canonical catalog, merchant allowlist, acceptable items and payment + * instrument used by the autonomous (3-layer) and immediate (2-layer) flows. + */ + +import type { Dict } from '@verifiable-intent/core'; + +/** Merchant allowlist — carried into the open mandate constraints + disclosures. */ +export const MERCHANTS: Dict[] = [ + { id: 'merchant-uuid-1', name: 'Tennis Warehouse', website: 'https://tennis-warehouse.com' }, + { id: 'merchant-uuid-2', name: 'Babolat', website: 'https://babolat.com' }, +]; + +/** Acceptable items — the user's line-item constraint references these by id. */ +export const ACCEPTABLE_ITEMS: Dict[] = [ + { id: 'BAB86345', title: 'Babolat Pure Aero Tennis Racket' }, + { id: 'HEA23102', title: 'Head Graphene 360 Speed' }, +]; + +export interface Product { + sku: string; + name: string; + /** Price in minor units (cents). */ + price: number; + currency: string; + brand: string; + model: string; + color: string; + size: number; + sizeLabel: string; + category: string; +} + +export const PRODUCTS: Product[] = [ + { + sku: 'BAB86345', + name: 'Babolat Pure Aero Tennis Racket', + price: 27999, + currency: 'USD', + brand: 'Babolat', + model: 'Pure Aero', + color: 'white', + size: 3, + sizeLabel: '4 3/8', + category: 'racket', + }, + { + sku: 'HEA23102', + name: 'Head Graphene 360 Speed Tennis Racket', + price: 24999, + currency: 'USD', + brand: 'HEAD', + model: 'Speed Pro', + color: 'black', + size: 3, + sizeLabel: '4 3/8', + category: 'racket', + }, +]; + +/** Mastercard digital card payment instrument (matches the Python reference). */ +export const PAYMENT_INSTRUMENT: Dict = { + type: 'mastercard.srcDigitalCard', + id: 'f199c3dd-7106-478b-9b5f-7af9ca725170', + description: 'Mastercard **** 1234', +}; + +/** + * Stable audiences for the Layer 3 presentations. The agent stamps these as the + * `aud` when minting L3a/L3b, and each verifier pins the matching value so a + * presentation addressed to a different party is rejected (RFC 7519 `aud`). + */ +export const MERCHANT_AUD = 'https://tennis-warehouse.com'; +export const NETWORK_AUD = 'https://www.mastercard.com'; + +export function getCatalog(): Product[] { + return PRODUCTS; +} + +export function findProduct(sku: string): Product | undefined { + return PRODUCTS.find((p) => p.sku === sku); +} diff --git a/code/samples/typescript/src/common/vi/flow.ts b/code/samples/typescript/src/common/vi/flow.ts new file mode 100644 index 00000000..6ad07445 --- /dev/null +++ b/code/samples/typescript/src/common/vi/flow.ts @@ -0,0 +1,511 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Verifiable Intent flow — per-role facade over `@verifiable-intent/core`. + * + * This is the TypeScript replication of the official Python integration + * (verifiable_intent: python/examples/autonomous_flow.py + immediate_flow.py), + * sliced along the AP2 role boundaries so each agent/MCP server calls exactly + * the one layer it owns: + * + * Issuer (credentials-provider) → issueIssuerCredential (L1) + * User (shopping-agent-v2) → createUserMandate{Autonomous,Immediate} (L2) + * Agent (shopping-agent-v2) → createAgentFulfillment (L3a + L3b + presentations) + * Merchant(merchant-agent-mcp) → verifyCheckoutChain (verify L3b) + * Network (merchant-pp-mcp) → verifyPaymentChainAndConstraints (verify L3a + constraints) + * + * All values that cross a process boundary are serialized SD-JWT strings. + */ + +import { randomUUID } from 'node:crypto'; +import { + AllowedMerchantConstraint, + AllowedPayeeConstraint, + ChainVerificationResult, + CheckoutL3Mandate, + CheckoutLineItemsConstraint, + CheckoutMandate, + type Constraint, + ConstraintCheckResult, + createLayer1, + createLayer2Autonomous, + createLayer2Immediate, + createLayer3Checkout, + createLayer3Payment, + type Dict, + decodeSdJwt, + type Es256Jwk, + FinalCheckoutMandate, + FinalPaymentMandate, + hashAscii, + hashDisclosure, + IssuerCredential, + MandateMode, + PaymentAmountConstraint, + PaymentL3Mandate, + PaymentMandate, + PaymentRecurrenceConstraint, + resolveDisclosures, + type SdJwt, + StrictnessMode, + buildSelectivePresentation, + checkConstraints, + UserMandate, + verifyChain, +} from '@verifiable-intent/core'; + +import { checkoutHashFromJwt } from './checkout-jwt.js'; +import { MERCHANT_AUD, NETWORK_AUD } from './fixtures.js'; +import type { ViKeyPair } from './keys.js'; + +const nowSeconds = (): number => Math.floor(Date.now() / 1000); +const asJwk = (jwk: Es256Jwk): Dict => ({ ...(jwk as unknown as Dict) }); + +// --------------------------------------------------------------------------- +// L1 — Issuer credential (Credentials Provider) +// --------------------------------------------------------------------------- + +export interface IssueCredentialParams { + /** User device public key bound into the credential via cnf.jwk. */ + userPublicJwk: Es256Jwk; + /** Issuer (Credentials Provider) signing keypair. */ + issuer: ViKeyPair; + /** Subject (cardholder) identifier. */ + sub: string; + iss?: string; + aud?: string | null; + iat?: number; + ttlSeconds?: number; + email?: string | null; + panLastFour?: string; + scheme?: string; +} + +/** Issue the Layer 1 issuer credential (binds the user's key). Returns serialized SD-JWT. */ +export async function issueIssuerCredential(params: IssueCredentialParams): Promise { + const iat = params.iat ?? nowSeconds(); + const credential = new IssuerCredential({ + iss: params.iss ?? 'https://www.mastercard.com', + sub: params.sub, + iat, + exp: iat + (params.ttlSeconds ?? 86400), + aud: params.aud ?? 'https://wallet.example.com', + cnfJwk: asJwk(params.userPublicJwk), + email: params.email ?? null, + panLastFour: params.panLastFour ?? '', + scheme: params.scheme ?? 'Mastercard', + }); + const l1 = await createLayer1(credential, params.issuer.privateKey, { kid: params.issuer.kid }); + return l1.serialize(); +} + +// --------------------------------------------------------------------------- +// L2 — User mandate, autonomous (human-not-present) +// --------------------------------------------------------------------------- + +export interface AutonomousMandateParams { + l1Serialized: string; + user: ViKeyPair; + /** Agent public key the user delegates to (bound via cnf.jwk). */ + agentPublicJwk: Es256Jwk; + /** Agent kid — MUST equal the agent's L3 header kid. */ + agentKid: string; + promptSummary: string; + nonce?: string; + aud?: string; + iss?: string; + iat?: number; + ttlSeconds?: number; + merchants: Dict[]; + acceptableItems: Dict[]; + paymentInstrument: Dict; + riskData?: Dict | null; + /** Amount range in minor units (cents). */ + amountMin: number; + amountMax: number; + currency?: string; + /** Override the line-items constraint; defaults to one line of acceptableItems. */ + lineItems?: Dict[]; + recurrence?: { frequency: string; startDate: string; endDate?: string | null; number?: number | null }; +} + +/** Create the Layer 2 autonomous user mandate (open mandates + agent delegation). */ +export async function createUserMandateAutonomous(params: AutonomousMandateParams): Promise { + const iat = params.iat ?? nowSeconds(); + const currency = params.currency ?? 'USD'; + + const checkoutConstraints = [ + new AllowedMerchantConstraint({ allowed: params.merchants }), + new CheckoutLineItemsConstraint({ + items: params.lineItems ?? [{ id: 'line-item-1', acceptable_items: params.acceptableItems, quantity: 1 }], + }), + ]; + + const paymentConstraints: Constraint[] = [ + new PaymentAmountConstraint({ currency, min: params.amountMin, max: params.amountMax }), + new AllowedPayeeConstraint({ allowed: params.merchants }), + ]; + if (params.recurrence) { + paymentConstraints.push( + new PaymentRecurrenceConstraint({ + frequency: params.recurrence.frequency, + startDate: params.recurrence.startDate, + endDate: params.recurrence.endDate ?? null, + number: params.recurrence.number ?? null, + }), + ); + } + + const mandate = new UserMandate({ + nonce: params.nonce ?? randomUUID(), + aud: params.aud ?? 'https://agent.verifiable-intent.example', + iat, + iss: params.iss ?? 'https://wallet.example.com', + exp: iat + (params.ttlSeconds ?? 86400), + mode: MandateMode.AUTONOMOUS, + sdHash: hashAscii(params.l1Serialized), + promptSummary: params.promptSummary, + checkoutMandate: new CheckoutMandate({ + vct: 'mandate.checkout.open.1', + cnfJwk: asJwk(params.agentPublicJwk), + cnfKid: params.agentKid, + constraints: checkoutConstraints, + }), + paymentMandate: new PaymentMandate({ + vct: 'mandate.payment.open.1', + cnfJwk: asJwk(params.agentPublicJwk), + cnfKid: params.agentKid, + paymentInstrument: params.paymentInstrument, + riskData: params.riskData ?? null, + constraints: paymentConstraints, + }), + merchants: params.merchants, + acceptableItems: params.acceptableItems, + }); + + const l2 = await createLayer2Autonomous(mandate, params.user.privateKey, { kid: params.user.kid }); + return l2.serialize(); +} + +// --------------------------------------------------------------------------- +// L2 — User mandate, immediate (human-present) +// --------------------------------------------------------------------------- + +export interface ImmediateMandateParams { + l1Serialized: string; + user: ViKeyPair; + checkoutJwt: string; + paymentInstrument: Dict; + payee: Dict; + /** Amount in minor units (cents). */ + amount: number; + currency?: string; + nonce?: string; + aud?: string; + iss?: string; + iat?: number; + ttlSeconds?: number; + promptSummary?: string | null; +} + +/** Create the Layer 2 immediate user mandate (final values, no delegation, no L3). */ +export async function createUserMandateImmediate(params: ImmediateMandateParams): Promise { + const iat = params.iat ?? nowSeconds(); + const checkoutHash = checkoutHashFromJwt(params.checkoutJwt); + + const mandate = new UserMandate({ + nonce: params.nonce ?? randomUUID(), + aud: params.aud ?? 'https://agent.verifiable-intent.example', + iat, + iss: params.iss ?? 'https://wallet.example.com', + exp: iat + (params.ttlSeconds ?? 900), + mode: MandateMode.IMMEDIATE, + sdHash: hashAscii(params.l1Serialized), + promptSummary: params.promptSummary ?? null, + checkoutMandate: new CheckoutMandate({ + vct: 'mandate.checkout.1', + checkoutJwt: params.checkoutJwt, + checkoutHash, + }), + paymentMandate: new PaymentMandate({ + vct: 'mandate.payment.1', + paymentInstrument: params.paymentInstrument, + payee: params.payee, + currency: params.currency ?? 'USD', + amount: params.amount, + transactionId: checkoutHash, + }), + }); + + const result = await createLayer2Immediate(mandate, params.user.privateKey, { kid: params.user.kid }); + return result.serialize(); +} + +// --------------------------------------------------------------------------- +// L3 — Agent fulfillment (split L3a payment + L3b checkout) + selective routing +// --------------------------------------------------------------------------- + +/** Find the disclosure string in an L2 whose resolved object value matches `predicate`. */ +function findDisclosure(l2: SdJwt, predicate: (value: Dict) => boolean): string | null { + for (let i = 0; i < l2.disclosures.length; i++) { + const dv = l2.disclosureValues[i]; + const value = dv.length ? dv[dv.length - 1] : null; + if (value && typeof value === 'object' && !Array.isArray(value) && predicate(value as Dict)) { + return l2.disclosures[i]; + } + } + return null; +} + +export interface AgentFulfillmentParams { + l2Serialized: string; + agent: ViKeyPair; + checkoutJwt: string; + checkoutHash: string; + /** The chosen merchant (must be one of the mandate's merchants). */ + payee: Dict; + /** The chosen item id / sku (must be an acceptable item). */ + itemId: string; + /** Amount in minor units (cents). */ + amount: number; + currency?: string; + paymentInstrument: Dict; + networkAud?: string; + merchantAud?: string; + nonce?: string; + iat?: number; + ttlSeconds?: number; +} + +export interface AgentFulfillment { + /** L3a — payment fulfillment for the network. */ + l3PaymentSerialized: string; + /** L3b — checkout fulfillment for the merchant. */ + l3CheckoutSerialized: string; + /** L2 presentation the network sees (payment + merchant disclosures). */ + l2PaymentSerialized: string; + /** L2 presentation the merchant sees (checkout + item disclosures). */ + l2CheckoutSerialized: string; +} + +/** Agent builds the split L3 credentials and the per-recipient L2 presentations. */ +export async function createAgentFulfillment(params: AgentFulfillmentParams): Promise { + const iat = params.iat ?? nowSeconds(); + const exp = iat + (params.ttlSeconds ?? 300); + const nonce = params.nonce ?? randomUUID(); + + const l2 = decodeSdJwt(params.l2Serialized); + const l2BaseJwt = params.l2Serialized.split('~')[0]; + + const paymentDisc = findDisclosure(l2, (v) => v.vct === 'mandate.payment.open.1'); + const checkoutDisc = findDisclosure(l2, (v) => v.vct === 'mandate.checkout.open.1'); + const merchantDisc = findDisclosure(l2, (v) => + Boolean(v.website) && (params.payee.id ? v.id === params.payee.id : v.name === params.payee.name), + ); + const itemDisc = findDisclosure(l2, (v) => v.id === params.itemId || v.sku === params.itemId); + + if (!paymentDisc || !checkoutDisc || !merchantDisc || !itemDisc) { + throw new Error( + `Missing L2 disclosures (payment=${Boolean(paymentDisc)} checkout=${Boolean(checkoutDisc)} ` + + `merchant=${Boolean(merchantDisc)} item=${Boolean(itemDisc)})`, + ); + } + + // L3a — payment, for the network. + const l3aMandate = new PaymentL3Mandate({ + nonce, + aud: params.networkAud ?? NETWORK_AUD, + iat, + iss: 'https://agent.example.com', + exp, + finalPayment: new FinalPaymentMandate({ + transactionId: params.checkoutHash, + payee: params.payee, + paymentAmount: { currency: params.currency ?? 'USD', amount: params.amount }, + paymentInstrument: params.paymentInstrument, + }), + finalMerchant: params.payee, + }); + const l3a = await createLayer3Payment(l3aMandate, params.agent.privateKey, l2BaseJwt, paymentDisc, merchantDisc, { + kid: params.agent.kid, + }); + + // L3b — checkout, for the merchant. + const l3bMandate = new CheckoutL3Mandate({ + nonce, + aud: params.merchantAud ?? MERCHANT_AUD, + iat, + iss: 'https://agent.example.com', + exp, + finalCheckout: new FinalCheckoutMandate({ checkoutJwt: params.checkoutJwt, checkoutHash: params.checkoutHash }), + }); + const l3b = await createLayer3Checkout(l3bMandate, params.agent.privateKey, l2BaseJwt, checkoutDisc, itemDisc, { + kid: params.agent.kid, + }); + + const l2PaymentSerialized = buildSelectivePresentation(l2BaseJwt, [paymentDisc, merchantDisc]); + const l2CheckoutSerialized = buildSelectivePresentation(l2BaseJwt, [checkoutDisc, itemDisc]); + + return { + l3PaymentSerialized: l3a.serialize(), + l3CheckoutSerialized: l3b.serialize(), + l2PaymentSerialized, + l2CheckoutSerialized, + }; +} + +// --------------------------------------------------------------------------- +// Verification — Merchant (checkout side) +// --------------------------------------------------------------------------- + +export interface VerifyCheckoutParams { + l1Serialized: string; + /** L2 presentation the merchant received (checkout + item disclosures). */ + l2CheckoutSerialized: string; + l3CheckoutSerialized: string; + issuerPublicJwk: Es256Jwk; + /** Full L2 serialization (for pairing); defaults to the checkout presentation. */ + l2Serialized?: string; + currentTime?: number; + expectedL3CheckoutAud?: string; + expectedL3CheckoutNonce?: string; +} + +/** Merchant verifies the checkout-side chain (L1 → L2 → L3b). */ +export async function verifyCheckoutChain(params: VerifyCheckoutParams): Promise { + const l1 = decodeSdJwt(params.l1Serialized); + const l2 = decodeSdJwt(params.l2CheckoutSerialized); + const l3Checkout = decodeSdJwt(params.l3CheckoutSerialized); + return verifyChain(l1, l2, { + l3Checkout, + issuerPublicJwk: params.issuerPublicJwk, + l1Serialized: params.l1Serialized, + l2Serialized: params.l2Serialized ?? params.l2CheckoutSerialized, + l2CheckoutSerialized: params.l2CheckoutSerialized, + currentTime: params.currentTime, + expectedL3CheckoutAud: params.expectedL3CheckoutAud, + expectedL3CheckoutNonce: params.expectedL3CheckoutNonce, + }); +} + +// --------------------------------------------------------------------------- +// Verification — Network / PSP (payment side) + constraint enforcement +// --------------------------------------------------------------------------- + +export interface VerifyPaymentParams { + l1Serialized: string; + /** L2 presentation the network received (payment + merchant disclosures). */ + l2PaymentSerialized: string; + l3PaymentSerialized: string; + issuerPublicJwk: Es256Jwk; + /** Full L2 serialization (for pairing); defaults to the payment presentation. */ + l2Serialized?: string; + currentTime?: number; + expectedL3PaymentAud?: string; + expectedL3PaymentNonce?: string; +} + +export interface PaymentVerificationOutcome { + valid: boolean; + errors: string[]; + result: ChainVerificationResult; + constraints: ConstraintCheckResult | null; +} + +/** Network verifies the payment-side chain (L1 → L2 → L3a) and enforces constraints (STRICT). */ +export async function verifyPaymentChainAndConstraints( + params: VerifyPaymentParams, +): Promise { + const l1 = decodeSdJwt(params.l1Serialized); + const l2 = decodeSdJwt(params.l2Serialized ?? params.l2PaymentSerialized); + const l3Payment = decodeSdJwt(params.l3PaymentSerialized); + + const result = await verifyChain(l1, l2, { + l3Payment, + issuerPublicJwk: params.issuerPublicJwk, + l1Serialized: params.l1Serialized, + l2Serialized: params.l2Serialized ?? params.l2PaymentSerialized, + l2PaymentSerialized: params.l2PaymentSerialized, + currentTime: params.currentTime, + expectedL3PaymentAud: params.expectedL3PaymentAud, + expectedL3PaymentNonce: params.expectedL3PaymentNonce, + }); + + if (!result.valid) { + return { valid: false, errors: result.errors, result, constraints: null }; + } + + const constraints = enforcePaymentConstraints(l2, result); + if (constraints === null) { + // No payment constraints present (e.g. immediate mode) — chain validity stands. + return { valid: true, errors: [], result, constraints: null }; + } + return { + valid: constraints.satisfied, + errors: constraints.satisfied ? [] : constraints.violations, + result, + constraints, + }; +} + +/** + * Resolve L2 payment constraints + L3 fulfillment and run the constraint checker + * in STRICT mode (payment networks MUST treat unknown constraints as violations). + * Port of python/examples/helpers.py `validate_intent` / autonomous_flow step 8. + * Returns null when the L2 carries no payment constraints. + */ +function enforcePaymentConstraints(l2: SdJwt, result: ChainVerificationResult): ConstraintCheckResult | null { + const l2Claims = resolveDisclosures(l2); + const delegates = (l2Claims.delegate_payload as Dict[] | undefined) ?? []; + + let paymentConstraints: Dict[] = []; + for (const delegate of delegates) { + if ( + delegate && + typeof delegate === 'object' && + (delegate.vct === 'mandate.payment.open.1' || delegate.vct === 'mandate.payment.1') + ) { + paymentConstraints = (delegate.constraints as Dict[] | undefined) ?? []; + break; + } + } + if (paymentConstraints.length === 0) { + return null; + } + + let fulfillment: Dict = {}; + for (const delegate of (result.l3PaymentClaims.delegate_payload as Dict[] | undefined) ?? []) { + if (delegate && typeof delegate === 'object' && delegate.vct === 'mandate.payment.1') { + fulfillment = { ...delegate }; + break; + } + } + + // Resolve allowed_payees SD-refs into concrete merchant objects for the checker. + const discByHash = new Map(); + for (let i = 0; i < l2.disclosures.length; i++) { + discByHash.set(hashDisclosure(l2.disclosures[i]), l2.disclosureValues[i]); + } + for (const constraint of paymentConstraints) { + if (constraint.type === 'mandate.payment.allowed_payees') { + const resolved: unknown[] = []; + for (const ref of (constraint.allowed as unknown[] | undefined) ?? []) { + const refHash = ref && typeof ref === 'object' ? ((ref as Dict)['...'] as string) : ''; + if (refHash && discByHash.has(refHash)) { + const dv = discByHash.get(refHash)!; + resolved.push(dv[dv.length - 1]); + } + } + fulfillment.allowed_merchants = resolved; + break; + } + } + + return checkConstraints(paymentConstraints, fulfillment, { mode: StrictnessMode.STRICT }); +} diff --git a/code/samples/typescript/src/common/vi/index.ts b/code/samples/typescript/src/common/vi/index.ts new file mode 100644 index 00000000..c5fc9956 --- /dev/null +++ b/code/samples/typescript/src/common/vi/index.ts @@ -0,0 +1,19 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Verifiable Intent integration barrel. Re-exports the `@verifiable-intent/core` + * primitives plus the AP2-sample glue (fixtures, key store, checkout JWT, and + * the per-role flow facade) that replicate the Python reference integration. + */ + +export * from '@verifiable-intent/core'; +export * from './fixtures.js'; +export * from './keys.js'; +export * from './checkout-jwt.js'; +export * from './flow.js'; diff --git a/code/samples/typescript/src/common/vi/keys.ts b/code/samples/typescript/src/common/vi/keys.ts new file mode 100644 index 00000000..a48273d3 --- /dev/null +++ b/code/samples/typescript/src/common/vi/keys.ts @@ -0,0 +1,69 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * File-backed ES256 (P-256) JWK key store for the Verifiable Intent roles. + * Each role (issuer, user, agent, merchant, psp) persists its keypair as + * `_key.jwk.json` under a shared TEMP_DB so the agent and each MCP + * subprocess resolve the same public keys and can verify each other's + * signatures. Keys carry a stable `kid` matching the Python reference, used + * for the SD-JWT header `kid` and the `cnf.jwk` key-binding (RFC 7800). + */ + +import fs from 'node:fs'; +import path from 'node:path'; +import { generateEs256Key, type Es256Jwk } from '@verifiable-intent/core'; + +export interface ViKeyPair { + publicKey: Es256Jwk; + privateKey: Es256Jwk; + kid: string; +} + +/** Stable per-role key ids, mirroring python/examples/helpers.py. */ +export const ROLE_KIDS: Record = { + issuer: 'mastercard-issuer-key-1', + user: 'user-device-key-1', + agent: 'agent-key-1', + merchant: 'merchant-key-1', + psp: 'psp-key-1', +}; + +function keyPath(tempDb: string, name: string): string { + return path.join(tempDb, `${name}_key.jwk.json`); +} + +function kidFor(name: string): string { + return ROLE_KIDS[name] ?? `${name}-key-1`; +} + +/** Load the named keypair, generating + persisting it (with a stable kid) on first use. */ +export async function loadOrCreateViKey(tempDb: string, name: string): Promise { + try { + const raw = JSON.parse(fs.readFileSync(keyPath(tempDb, name), 'utf-8')) as Partial; + if (raw.publicKey && raw.privateKey) { + return { publicKey: raw.publicKey, privateKey: raw.privateKey, kid: raw.kid ?? kidFor(name) }; + } + } catch { + /* fall through to generate */ + } + const { publicKey, privateKey } = await generateEs256Key(); + const pair: ViKeyPair = { publicKey, privateKey, kid: kidFor(name) }; + fs.mkdirSync(tempDb, { recursive: true }); + fs.writeFileSync(keyPath(tempDb, name), JSON.stringify(pair)); + return pair; +} + +/** Read just the public JWK of a previously persisted keypair (null if absent). */ +export function loadViPublicJwk(tempDb: string, name: string): Es256Jwk | null { + try { + return (JSON.parse(fs.readFileSync(keyPath(tempDb, name), 'utf-8')) as ViKeyPair).publicKey; + } catch { + return null; + } +} diff --git a/code/samples/typescript/src/roles/credentials-provider-agent/account-manager.ts b/code/samples/typescript/src/roles/credentials-provider-agent/account-manager.ts new file mode 100644 index 00000000..6a24cc95 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-agent/account-manager.ts @@ -0,0 +1,429 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * An in-memory manager of a user's 'account details'. + * + * Each 'account' contains a user's payment methods and shipping address. + * For demonstration purposes, several accounts are pre-populated with sample data. + * + * Token creation issues SD-JWT payment credentials signed with the + * credentials-provider's ES256 key (AP2 v0.2). Sensitive payment method + * fields are made selectively disclosable. Built directly on the Verifiable + * Intent SD-JWT primitives (@verifiable-intent/core): the issuer signs a + * selective-disclosure SD-JWT with a `cnf.jwk` holder-binding key (RFC 7800), + * and verification checks the issuer signature and resolves the disclosures. + */ +import { + createDisclosure, + createSdArray, + createSdJwt, + decodeSdJwt, + type Es256Jwk, + generateEs256Key, + resolveDisclosures, + verifySdJwtSignature, +} from '../../common/vi/index.js'; + +type IssuerKeyPair = { publicKey: Es256Jwk; privateKey: Es256Jwk }; + +export type PaymentMethod = { + type: string; + alias: string; + network?: { name?: string; formats?: string[] }[]; + cryptogram?: string; + token?: string; + card_holder_name?: string; + card_expiration?: string; + card_billing_address?: { country?: string; postal_code?: string }; + account_number?: string; + brand?: string; + account_identifier?: string; +}; + +type Account = { + shipping_address?: { + recipient: string; + organization?: string; + address_line: string[]; + city: string; + region: string; + postal_code: string; + country: string; + phone_number: string; + }; + payment_methods: { + [key: string]: PaymentMethod; + }; +}; + +const accountDb: { [email: string]: Account } = { + // Default demo account used when no user email has been collected. + "user@example.com": { + shipping_address: { + recipient: "Demo User", + address_line: ["123 Main St"], + city: "San Francisco", + region: "CA", + postal_code: "94105", + country: "US", + phone_number: "+14155551234", + }, + payment_methods: { + card1: { + type: "CARD", + alias: "Visa ending in 4242", + network: [{ name: "visa", formats: ["DPAN"] }], + cryptogram: "fake_cryptogram_demo", + token: "4242000000004242", + card_holder_name: "Demo User", + card_expiration: "12/2030", + card_billing_address: { + country: "US", + postal_code: "94105", + }, + }, + }, + }, + "bugsbunny@gmail.com": { + shipping_address: { + recipient: "Bugs Bunny", + organization: "Sample Organization", + address_line: ["123 Main St"], + city: "Sample City", + region: "ST", + postal_code: "00000", + country: "US", + phone_number: "+1-000-000-0000", + }, + payment_methods: { + card1: { + type: "CARD", + alias: "American Express ending in 4444", + network: [{ name: "amex", formats: ["DPAN"] }], + cryptogram: "fake_cryptogram_abc123", + token: "1111000000000000", + card_holder_name: "John Doe", + card_expiration: "12/2028", + card_billing_address: { + country: "US", + postal_code: "00000", + }, + }, + card2: { + type: "CARD", + alias: "American Express ending in 8888", + network: [{ name: "amex", formats: ["DPAN"] }], + cryptogram: "fake_cryptogram_ghi789", + token: "2222000000000000", + card_holder_name: "Bugs Bunny", + card_expiration: "10/2027", + card_billing_address: { + country: "US", + postal_code: "00000", + }, + }, + bank_account1: { + type: "BANK_ACCOUNT", + account_number: "111", + alias: "Primary bank account", + }, + digital_wallet1: { + type: "DIGITAL_WALLET", + brand: "PayPal", + account_identifier: "foo@bar.com", + alias: "Bugs's PayPal account", + }, + }, + }, + "daffyduck@gmail.com": { + payment_methods: { + bank_account1: { + type: "BANK_ACCOUNT", + brand: "Bank of Money", + account_number: "789", + alias: "Main checking account", + }, + }, + }, + "elmerfudd@gmail.com": { + payment_methods: { + digital_wallet1: { + type: "DIGITAL_WALLET", + brand: "PayPal", + account_identifier: "elmerfudd@gmail.com", + alias: "Fudd's PayPal", + }, + }, + }, +}; + +/** + * Token store: maps a serialized SD-JWT (the "token" string) to its metadata. + * The SD-JWT itself is the token — it cryptographically binds the payment + * method to the issuer. The store tracks the mandate association. + */ +const tokens: { + [token: string]: { + emailAddress: string; + paymentMethodAlias: string; + paymentMandateId: string | null; + }; +} = {}; + +/** + * The credentials-provider's ES256 issuer keypair. Used to sign payment + * credential SD-JWTs and to verify them on the way back. The same keypair's + * public key is also bound into `cnf.jwk` as the holder key for these demo + * tokens (no separate holder key is involved at issuance time). + */ +let issuerKey: IssuerKeyPair | null = null; + +/** + * Initializes the issuer ES256 keypair. Idempotent — repeated calls after the + * first are no-ops, so it is safe to invoke during server boot. + */ +export async function initIssuerKey(): Promise { + if (issuerKey) { + return; + } + issuerKey = await generateEs256Key(); +} + +/** + * Returns the initialized issuer keypair. + * + * @throws Error if {@link initIssuerKey} has not been called yet. + */ +function getIssuerKey(): IssuerKeyPair { + if (!issuerKey) { + throw new Error('Issuer key not initialized. Call initIssuerKey() first.'); + } + return issuerKey; +} + +/** + * Payment method fields that carry sensitive data and should be made + * selectively disclosable in the issued SD-JWT. + */ +const DISCLOSABLE_FIELDS = [ + 'cryptogram', + 'token', + 'card_holder_name', + 'card_expiration', + 'card_billing_address', + 'account_number', + 'account_identifier', +]; + +/** + * Creates a token for an account by issuing an SD-JWT payment credential. + * + * The SD-JWT embeds the payment method data as claims and is signed with the + * credentials-provider's ES256 issuer key. Sensitive payment method fields are + * made selectively disclosable. The serialized SD-JWT string serves as the + * token. + * + * @param emailAddress - The email address of the account. + * @param paymentMethodAlias - The alias of the payment method. + * @returns The serialized SD-JWT token for the payment method. + */ +export const createToken = async ( + emailAddress: string, + paymentMethodAlias: string +): Promise => { + const paymentMethod = getPaymentMethodByAlias(emailAddress, paymentMethodAlias); + if (!paymentMethod) { + throw new Error( + `Payment method "${paymentMethodAlias}" not found for ${emailAddress}` + ); + } + + const key = getIssuerKey(); + + // Build the claim set from the payment method fields plus credential + // metadata. The credential `type` claim ("PaymentCredential") shadows the + // payment method's own `type` field (e.g. "CARD"), so the latter is + // preserved under `payment_method_type` and restored on verification. + const claims: Record = { + ...(paymentMethod as unknown as Record), + payment_method_type: paymentMethod.type, + sub: `mailto:${emailAddress}`, + payment_method_alias: paymentMethodAlias, + type: 'PaymentCredential', + iat: Math.floor(Date.now() / 1000), + }; + + // Only the sensitive fields actually present on this payment method are + // declared as selectively disclosable. + const disclosable = DISCLOSABLE_FIELDS.filter((field) => field in claims); + + // Build the selective disclosures for the sensitive fields, and the always- + // visible payload for everything else (plus the cnf holder-binding key). + const disclosures = disclosable.map((field) => createDisclosure(field, claims[field])); + const payload: Record = {}; + for (const [k, v] of Object.entries(claims)) { + if (!disclosable.includes(k)) { + payload[k] = v; + } + } + // cnf is never selectively disclosed (RFC 7800). For these demo credentials + // the issuer's own public key is bound as the holder key. + payload.cnf = { jwk: key.publicKey }; + payload._sd = createSdArray(disclosures); + payload._sd_alg = 'sha-256'; + + // Issue + serialize the SD-JWT payment credential signed by the issuer key. + const header = { alg: 'ES256', typ: 'sd+jwt' }; + const sdJwt = await createSdJwt(header, payload, disclosures, key.privateKey); + const token = sdJwt.serialize(); + + tokens[token] = { + emailAddress, + paymentMethodAlias, + paymentMandateId: null, + }; + + return token; +}; + +/** + * Updates the token with the payment mandate id. + * + * @param token - The token (serialized VC) to update. + * @param paymentMandateId - The payment mandate id to associate with the token. + */ +export const updateToken = (token: string, paymentMandateId: string): void => { + if (!(token in tokens)) { + throw new Error(`Token ${token} not found`); + } + if (tokens[token].paymentMandateId) { + // Do not overwrite the payment mandate id if it is already set. + return; + } + tokens[token].paymentMandateId = paymentMandateId; +}; + +/** + * Verify a token (serialized SD-JWT) and return the payment method. + * + * Performs cryptographic verification of the SD-JWT issuer signature, checks + * the in-memory mandate binding, and reconstructs the payment method from the + * verified claims. + * + * @param token - The serialized SD-JWT token. + * @param paymentMandateId - The payment mandate id associated with the token. + * @returns The payment method extracted from the verified SD-JWT. + * @throws Error if the token is invalid or the mandate doesn't match. + */ +export const verifyToken = async ( + token: string, + paymentMandateId: string +): Promise => { + // Check the token store for mandate binding + const accountLookup = tokens[token]; + if (!accountLookup) { + throw new Error("Invalid token"); + } + if (accountLookup.paymentMandateId !== paymentMandateId) { + throw new Error("Invalid token"); + } + + const key = getIssuerKey(); + + // Cryptographically verify the SD-JWT issuer signature, then resolve the + // selective disclosures into the full claim set. + const sdJwt = decodeSdJwt(token); + const signatureValid = await verifySdJwtSignature(sdJwt, key.publicKey); + if (!signatureValid) { + throw new Error('Invalid token: SD-JWT signature verification failed'); + } + const payload = resolveDisclosures(sdJwt); + + // Reconstruct the PaymentMethod from the verified claims. Strip the + // credential metadata (sub, payment_method_alias, type, iat), the SD-JWT + // machinery (_sd, _sd_alg), and the holder-binding `cnf` claim. The + // credential `type` ("PaymentCredential") is dropped; the payment method's + // own `type` (e.g. "CARD") was stashed in `payment_method_type` at issuance + // and is restored here. + const { + sub: _sub, + payment_method_alias: _alias, + type: _credentialType, + iat: _iat, + cnf: _cnf, + _sd: _sdHashes, + _sd_alg: _sdAlg, + payment_method_type: paymentMethodType, + ...rest + } = payload; + const paymentMethodData: Record = { ...rest }; + if (paymentMethodType !== undefined) { + paymentMethodData.type = paymentMethodType; + } + return paymentMethodData as unknown as PaymentMethod; +}; + +/** + * Returns a list of the payment methods for the given account email address. + * + * @param emailAddress - The account's email address. + * @returns A list of the user's payment_methods. + */ +export const getAccountPaymentMethods = ( + emailAddress: string +): PaymentMethod[] => { + const account = accountDb[emailAddress]; + if (!account || !account.payment_methods) { + return []; + } + return Object.values(account.payment_methods); +}; + +/** + * Gets the shipping address associated for the given account email address. + * + * @param emailAddress - The account's email address. + * @returns The account's shipping address. + */ +export const getAccountShippingAddress = ( + emailAddress: string +): Account["shipping_address"] | null => { + const account = accountDb[emailAddress]; + return account?.shipping_address || null; +}; + +/** + * Returns the payment method for a given account and alias. + * + * @param emailAddress - The account's email address. + * @param alias - The alias of the payment method to retrieve. + * @returns The payment method for the given account and alias, or null if not found. + */ +export const getPaymentMethodByAlias = ( + emailAddress: string, + alias: string +): PaymentMethod | null => { + const paymentMethods = getAccountPaymentMethods(emailAddress).filter( + (paymentMethod) => paymentMethod.alias.toLowerCase() === alias.toLowerCase() + ); + + if (paymentMethods.length === 0) { + return null; + } + + return paymentMethods[0]; +}; diff --git a/code/samples/typescript/src/roles/credentials-provider-agent/agent.ts b/code/samples/typescript/src/roles/credentials-provider-agent/agent.ts new file mode 100644 index 00000000..d28b4e31 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-agent/agent.ts @@ -0,0 +1,57 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from '@google/adk'; +import { DEBUG_MODE_INSTRUCTIONS } from '../../common/constants/index.js'; +import { + handleCreatePaymentCredentialToken, + handleGetPaymentMethodRawCredentials, + handleGetShippingAddress, + handleSearchPaymentMethods, + handleSignedPaymentMandate, + handlePaymentReceipt, +} from './tools.js'; + +/** + * Credentials Provider Agent (ADK) + * + * This agent acts as a secure digital wallet managing user payment credentials. + */ +export const credentialsProviderAgent = new LlmAgent({ + name: 'credentials_provider_agent', + model: 'gemini-2.5-flash', + description: 'An agent that holds a user\'s payment credentials.', + instruction: `You are a credentials provider agent acting as a secure digital wallet. +Your job is to manage a user's payment methods and shipping addresses. + +IMPORTANT RULES: +1. Read the user request carefully and call EXACTLY ONE tool. +2. After the tool returns its result, respond with a single short + sentence confirming what was done. Example: "Shipping address retrieved." +3. NEVER call a tool more than once per request. +4. NEVER ask follow-up questions or continue the conversation. +5. Your entire response after the tool result must be one sentence. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [ + handleCreatePaymentCredentialToken, + handleGetPaymentMethodRawCredentials, + handleGetShippingAddress, + handleSearchPaymentMethods, + handleSignedPaymentMandate, + handlePaymentReceipt, + ], +}); diff --git a/code/samples/typescript/src/roles/credentials-provider-agent/server.ts b/code/samples/typescript/src/roles/credentials-provider-agent/server.ts new file mode 100644 index 00000000..b2ed8866 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-agent/server.ts @@ -0,0 +1,144 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Runner } from '@google/adk'; +import type { AgentCard } from '@a2a-js/sdk'; + +import { credentialsProviderAgent } from './agent.js'; +import { sessionService } from '../../common/config/session.js'; +import { BaseAgentExecutor } from '../../common/server/base-executor.js'; +import { bootstrapServer } from '../../common/server/bootstrap.js'; +import { DATA_KEYS, A2A_DATA_KEYS } from '../../common/constants/index.js'; +import * as accountManager from './account-manager.js'; + +const runner = new Runner({ + appName: 'ap2-credentials-provider', + agent: credentialsProviderAgent, + sessionService, +}); + +const agentExecutor = new BaseAgentExecutor({ + agentName: 'credentials_provider_agent', + appName: 'ap2-credentials-provider', + runner, + maxLlmCalls: 3, + workingMessage: 'Processing request...', + preprocessMessage({ userText, dataParts }) { + // Build a hint about available data so the LLM knows which tool to call + const dataKeys = dataParts.flatMap((dp) => Object.keys(dp)); + const hasUserEmail = dataKeys.includes(A2A_DATA_KEYS.USER_EMAIL); + const hasPaymentMandate = dataKeys.includes(DATA_KEYS.PAYMENT_MANDATE); + const hasPaymentMethodData = dataKeys.includes(A2A_DATA_KEYS.PAYMENT_METHOD_DATA); + const hasPaymentMethodAlias = dataKeys.includes(A2A_DATA_KEYS.PAYMENT_METHOD_ALIAS); + + if (hasPaymentMandate && hasUserEmail) { + return `${userText}\n\nThe request data contains a PaymentMandate. Call the appropriate tool to handle it.`; + } + if (hasPaymentMethodData && hasUserEmail) { + return `${userText}\n\nThe request data contains user_email and payment method criteria. Call handleSearchPaymentMethods.`; + } + if (hasPaymentMethodAlias && hasUserEmail) { + return `${userText}\n\nThe request data contains user_email and payment_method_alias. Call handleCreatePaymentCredentialToken.`; + } + if (hasUserEmail) { + return `${userText}\n\nThe request data contains user_email. Call handleGetShippingAddress now.`; + } + return userText; + }, +}); + +const agentCard: AgentCard = { + name: 'CredentialsProvider', + description: "An agent that holds a user's payment credentials.", + url: 'http://localhost:8002', + provider: { organization: 'AP2 Demo', url: 'https://github.com/google-agentic-commerce/ap2' }, + skills: [ + { + id: 'initiate_payment', + name: 'Initiate Payment', + description: 'Initiates a payment with the correct payment processor.', + tags: ['payments'], + }, + { + id: 'get_eligible_payment_methods', + name: 'Get Eligible Payment Methods', + description: + 'Provides a list of eligible payment methods for a particular purchase.', + parameters: { + type: 'object', + properties: { + email_address: { + type: 'string', + description: + "The email address associated with the user's account.", + }, + }, + required: ['email_address'], + }, + tags: ['eligible', 'payment', 'methods'], + } as AgentCard['skills'][number], + { + id: 'get_account_shipping_address', + name: 'Get Shipping Address', + description: "Fetches the shipping address from a user's wallet.", + parameters: { + type: 'object', + properties: { + email_address: { + type: 'string', + description: + "The email address associated with the user's account.", + }, + }, + required: ['email_address'], + }, + tags: ['account', 'shipping'], + } as AgentCard['skills'][number], + ], + capabilities: { + streaming: true, + pushNotifications: false, + stateTransitionHistory: true, + extensions: [ + { + uri: 'https://github.com/google-agentic-commerce/ap2/v1', + description: 'Supports the Agent Payments Protocol.', + required: true, + }, + { + uri: 'https://sample-card-network.github.io/paymentmethod/common/types/v1', + description: + 'Supports the Sample Card Network payment method extension', + required: true, + }, + ], + }, + defaultInputModes: ['text/plain'], + defaultOutputModes: ['application/json'], + protocolVersion: '0.3.0', + version: '1.0.0', +}; + +// Initialize the issuer ES256 key before starting the server so the +// credentials-provider can issue and verify SD-JWT payment credentials. +accountManager.initIssuerKey().then(() => { + bootstrapServer({ + agentCard, + agentExecutor, + port: 8002, + label: 'CredentialsProvider', + }); +}); diff --git a/code/samples/typescript/src/roles/credentials-provider-agent/tools.ts b/code/samples/typescript/src/roles/credentials-provider-agent/tools.ts new file mode 100644 index 00000000..1da48666 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-agent/tools.ts @@ -0,0 +1,360 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from '@google/adk'; +import { z } from 'zod'; +import { v4 as uuidv4 } from 'uuid'; +import { + findDataPart, + findDataParts, + parseCanonicalObject, +} from '../../common/utils/message.js'; +import * as accountManager from './account-manager.js'; +import { paymentMandateSchema } from '../../common/schemas/payment-mandate.js'; +import { getA2AContextFromTool } from '../../common/server/a2a-context.js'; +import { DATA_KEYS, A2A_DATA_KEYS } from '../../common/constants/index.js'; + +const PAYMENT_MANDATE_DATA_KEY = DATA_KEYS.PAYMENT_MANDATE; +const PAYMENT_METHOD_DATA_DATA_KEY = A2A_DATA_KEYS.PAYMENT_METHOD_DATA; + +interface PaymentMethodData { + supportedMethods: string; + data: { + network?: string[]; + } & Record; +} + +// Helper functions +function getPaymentMethodAliases( + paymentMethods: accountManager.PaymentMethod[] +): (string | undefined)[] { + return paymentMethods.map((paymentMethod) => paymentMethod.alias); +} + +function paymentMethodIsEligible( + paymentMethod: accountManager.PaymentMethod, + merchantCriteria: PaymentMethodData +): boolean { + if (paymentMethod.type !== merchantCriteria.supportedMethods) { + return false; + } + + const merchantSupportedNetworks = (merchantCriteria.data?.network || []).map( + (network) => network.toLowerCase() + ); + + if (merchantSupportedNetworks.length === 0) { + return false; + } + + const paymentCardNetworks = paymentMethod.network || []; + for (const networkInfo of paymentCardNetworks) { + for (const supportedNetwork of merchantSupportedNetworks) { + if (networkInfo.name?.toLowerCase() === supportedNetwork) { + return true; + } + } + } + + return false; +} + +function getEligiblePaymentMethodAliases( + userEmail: string, + merchantAcceptedPaymentMethods: PaymentMethodData[] +): { payment_method_aliases: (string | undefined)[] } { + const paymentMethods = accountManager.getAccountPaymentMethods(userEmail); + const eligiblePaymentMethods: accountManager.PaymentMethod[] = []; + + for (const paymentMethod of paymentMethods) { + for (const criteria of merchantAcceptedPaymentMethods) { + if (paymentMethodIsEligible(paymentMethod, criteria)) { + eligiblePaymentMethods.push(paymentMethod); + break; + } + } + } + + return { + payment_method_aliases: getPaymentMethodAliases(eligiblePaymentMethods), + }; +} + +/** + * ADK Tools for Credentials Provider Agent + * + * Note: These tools are designed to work within the A2A protocol. + * The dataParts, eventBus, and currentTask are stored in session state + * by the AgentExecutor before calling the agent. + */ + +export const handleCreatePaymentCredentialToken = new FunctionTool({ + name: 'handleCreatePaymentCredentialToken', + description: 'Handles a request to get a payment credential token. Updates a task with the payment credential token.', + parameters: z.object({ + // Dummy parameter since ADK FunctionTool requires at least one parameter + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const userEmail = findDataPart("user_email", dataParts) as string | null; + const paymentMethodAlias = findDataPart( + "payment_method_alias", + dataParts + ) as string | null; + + if (!userEmail || !paymentMethodAlias) { + return { error: "user_email and payment_method_alias are required but were not found in the request data. Report this error to the caller." }; + } + + const tokenizedPaymentMethod = await accountManager.createToken( + userEmail, + paymentMethodAlias + ); + + // Publish artifact via A2A eventBus + if (eventBus) { + eventBus.publish({ + kind: "artifact-update", + taskId: currentTask?.id, + contextId: currentTask?.contextId, + artifact: { + artifactId: uuidv4(), + parts: [{ kind: "data", data: { token: tokenizedPaymentMethod } }], + }, + }); + } + + return { tokenizedPaymentMethod }; + }, +}); + +export const handleGetPaymentMethodRawCredentials = new FunctionTool({ + name: 'handleGetPaymentMethodRawCredentials', + description: 'Handles a request to get the raw credentials for a payment method. Updates a task with the payment method\'s raw credentials.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + let paymentMandate; + try { + paymentMandate = parseCanonicalObject( + PAYMENT_MANDATE_DATA_KEY, + dataParts, + paymentMandateSchema + ); + } catch { + return { error: "PaymentMandate not found in request data. Report this error to the caller." }; + } + const paymentMandateContents = paymentMandate.paymentMandateContents; + + // Extract token value from nested {value, url} structure + const tokenObj = paymentMandateContents.paymentResponse.details?.token as + | { value?: string; url?: string } + | string + | undefined; + const token = typeof tokenObj === 'object' ? (tokenObj?.value ?? '') : (tokenObj ?? ''); + const paymentMandateId = paymentMandateContents.paymentMandateId; + + const paymentMethod = await accountManager.verifyToken(token, paymentMandateId); + + if (!paymentMethod) { + return { error: "Payment method not found for the given token. Report this error to the caller." }; + } + + if (eventBus) { + eventBus.publish({ + kind: "artifact-update", + taskId: currentTask?.id, + contextId: currentTask?.contextId, + artifact: { + artifactId: uuidv4(), + parts: [{ kind: "data", data: paymentMethod }], + }, + }); + } + + return { paymentMethod }; + }, +}); + +export const handleGetShippingAddress = new FunctionTool({ + name: 'handleGetShippingAddress', + description: 'Handles a request to get the user\'s shipping address. Updates a task with the user\'s shipping address.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const userEmail = findDataPart("user_email", dataParts) as string | null; + if (!userEmail) { + return { error: "user_email is required but was not found in the request data. Report this error to the caller." }; + } + + const shippingAddress = accountManager.getAccountShippingAddress(userEmail); + if (!shippingAddress) { + return { error: `Shipping address not found for user ${userEmail}. Report this error to the caller.` }; + } + + if (eventBus) { + eventBus.publish({ + kind: "artifact-update", + taskId: currentTask?.id, + contextId: currentTask?.contextId, + artifact: { + artifactId: uuidv4(), + parts: [{ kind: "data", data: { [DATA_KEYS.CONTACT_ADDRESS]: shippingAddress } }], + }, + }); + } + + return { shippingAddress }; + }, +}); + +export const handleSearchPaymentMethods = new FunctionTool({ + name: 'handleSearchPaymentMethods', + description: `Returns the user's payment methods that match what the merchant accepts. + +The merchant's accepted payment methods are provided in the data_parts as a +list of PaymentMethodData objects. The user's account is identified by the +user_email provided in the data_parts. + +This tool finds and returns all the payment methods associated with the user's +account that match the merchant's accepted payment methods.`, + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const userEmail = findDataPart("user_email", dataParts) as string | null; + const methodData = findDataParts(PAYMENT_METHOD_DATA_DATA_KEY, dataParts); + + if (!userEmail) { + return { error: "user_email is required for search_payment_methods but was not found in the request data. Report this error to the caller." }; + } + if (!methodData || methodData.length === 0) { + return { error: "method_data is required for search_payment_methods but was not found in the request data. Report this error to the caller." }; + } + + const merchantMethodDataList = methodData.map( + (data) => data as PaymentMethodData + ); + + const eligibleAliases = getEligiblePaymentMethodAliases( + userEmail, + merchantMethodDataList + ); + + if (eventBus) { + eventBus.publish({ + kind: "artifact-update", + taskId: currentTask?.id, + contextId: currentTask?.contextId, + artifact: { + artifactId: uuidv4(), + parts: [{ kind: "data", data: eligibleAliases }], + }, + }); + } + + return { eligibleAliases }; + }, +}); + +export const handleSignedPaymentMandate = new FunctionTool({ + name: 'handleSignedPaymentMandate', + description: 'Handles a signed payment mandate. Adds the payment mandate id to the token in storage and then completes the task.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + let paymentMandate; + try { + paymentMandate = parseCanonicalObject( + PAYMENT_MANDATE_DATA_KEY, + dataParts, + paymentMandateSchema + ); + } catch { + return { error: "PaymentMandate not found in request data. Report this error to the caller." }; + } + + // x402 short-circuit: no token processing needed + const methodName = paymentMandate.paymentMandateContents.paymentResponse.methodName; + if (methodName === 'https://www.x402.org/') { + return { success: true, message: 'x402 payment mandate received, no token update needed.' }; + } + + // Extract token value from nested {value, url} structure + const tokenObj = paymentMandate.paymentMandateContents.paymentResponse.details?.token as + | { value?: string; url?: string } + | string + | undefined; + const token = typeof tokenObj === 'object' ? (tokenObj?.value ?? '') : (tokenObj ?? ''); + const paymentMandateId = paymentMandate.paymentMandateContents.paymentMandateId; + + accountManager.updateToken(token, paymentMandateId); + + if (eventBus) { + eventBus.publish({ + kind: "artifact-update", + taskId: currentTask?.id, + contextId: currentTask?.contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { + kind: "data", + data: { + status: "signed_payment_mandate_received", + paymentMandateId: paymentMandateId, + }, + }, + ], + }, + }); + } + + return { + success: true, + message: "Signed payment mandate validated and stored successfully.", + }; + }, +}); + +export const handlePaymentReceipt = new FunctionTool({ + name: 'handlePaymentReceipt', + description: 'Handles a payment receipt. This is a placeholder that completes the task without any action.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async () => { + return { success: true, message: 'Payment receipt acknowledged.' }; + }, +}); diff --git a/code/samples/typescript/src/roles/credentials-provider-mcp/server.ts b/code/samples/typescript/src/roles/credentials-provider-mcp/server.ts new file mode 100644 index 00000000..709210e1 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-mcp/server.ts @@ -0,0 +1,161 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Credential Provider MCP Server. + * + * Exposes three MCP tools consumed by the shopping agent v2 over stdio: + * issue_payment_credential, revoke_payment_credential, verify_payment_receipt + * + * issue_payment_credential performs REAL SD-JWT verification of the presented + * closed payment-mandate (KB-SD-JWT): it loads the mandate the agent persisted + * under TEMP_DB, verifies the issuer (user) signature and the agent Key-Binding + * JWT against `cnf.jwk` with the expected nonce, and only then mints a token — + * mirroring the Python credentials_provider_mcp.issue_payment_credential. + * Tool names/args/response shapes mirror the v0.2 Python server. + */ + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { randomUUID } from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { z } from 'zod'; +import { verifyJwtEs256, loadPublicJwk } from '../../common/sdjwt/index.js'; +import { NETWORK_AUD, loadViPublicJwk, verifyPaymentChainAndConstraints } from '../../common/vi/index.js'; + +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; + +const TOKEN_STORE = new Map(); + +function readTempFile(filename: string): string | null { + try { + return fs.readFileSync(path.join(TEMP_DB, filename), 'utf-8'); + } catch { + return null; + } +} + +const server = new McpServer({ + name: 'credentials-provider-mcp', + version: '0.2.0', +}); + +server.registerTool( + 'issue_payment_credential', + { + description: + 'Verify the payment-side Verifiable Intent chain (L1 issuer -> L2 user mandate -> L3a agent ' + + 'payment fulfillment) and enforce the mandate constraints (STRICT). Only on a valid chain ' + + 'whose amount/payee satisfy the user mandate is a scoped single-use payment token issued.', + inputSchema: { + payment_mandate_chain_id: z.string(), + }, + }, + async ({ payment_mandate_chain_id }) => { + if (!payment_mandate_chain_id) { + const error = { error: 'missing_fields', message: 'payment_mandate_chain_id is required' }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + // Load the agent-produced payment chain artifacts (L3a + L2 payment presentation) + L1. + const l3Payment = readTempFile(`${payment_mandate_chain_id}.sdjwt`); + const l2Payment = readTempFile(`${payment_mandate_chain_id}.l2.sdjwt`); + const l1 = readTempFile('l1.sdjwt'); + if (!l3Payment || !l2Payment || !l1) { + const error = { error: 'payment_chain_artifacts_missing', message: payment_mandate_chain_id }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + const issuerPublicJwk = loadViPublicJwk(TEMP_DB, 'issuer'); + if (!issuerPublicJwk) { + const error = { error: 'issuer_key_unavailable', message: 'issuer key not found in TEMP_DB' }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + + // Verify the payment chain (issuer sig, L2->L1 binding, agent L3 key + sd_hash + // binding) AND enforce the user mandate constraints in STRICT mode. A forged + // chain fails signature/binding; an out-of-policy amount/payee fails constraints. + try { + const outcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: l2Payment, + l3PaymentSerialized: l3Payment, + issuerPublicJwk, + expectedL3PaymentAud: NETWORK_AUD, + }); + if (!outcome.valid) { + const error = { error: 'payment_chain_invalid', message: outcome.errors.join('; ') }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + } catch (e) { + const error = { error: 'payment_chain_verification_failed', message: String(e) }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + + // Verified — mint a scoped single-use token bound to the mandate chain. + const token = `pay_token_${randomUUID()}`; + const issuedAt = Math.floor(Date.now() / 1000); + const expiresAt = issuedAt + 600; + TOKEN_STORE.set(token, { issued_at: issuedAt, expires_at: expiresAt }); + const result = { payment_token: token, expires_at: expiresAt }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +server.registerTool( + 'revoke_payment_credential', + { + description: + 'Revoke a previously issued payment token, removing it from the token store. ' + + 'Returns whether the token existed.', + inputSchema: { payment_token: z.string() }, + }, + async ({ payment_token }) => { + const existed = TOKEN_STORE.delete(payment_token); + const result = { revoked: existed, payment_token }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +server.registerTool( + 'verify_payment_receipt', + { + description: + 'Verify a payment receipt (stubbed: checks signature against the PSP key ' + + 'and that it matches a prior issued payment token).', + inputSchema: { payment_receipt: z.string() }, + }, + async ({ payment_receipt }) => { + // Verify the receipt's ES256 signature against the PSP public key. + const pspPub = loadPublicJwk(TEMP_DB, 'psp'); + if (!pspPub) { + const error = { error: 'psp_key_unavailable', message: 'psp key not found in TEMP_DB' }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + try { + const payload = await verifyJwtEs256(payment_receipt, pspPub); + const result = { verified: true, issuer: payload.iss, receipt_id: payload.receipt_id }; + return { content: [{ type: 'text', text: JSON.stringify(result) }], structuredContent: result }; + } catch (e) { + const error = { error: 'receipt_verification_failed', message: String(e) }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + }, +); + +const transport = new StdioServerTransport(); +await server.connect(transport); diff --git a/code/samples/typescript/src/roles/credentials-provider-mcp/trigger-server.ts b/code/samples/typescript/src/roles/credentials-provider-mcp/trigger-server.ts new file mode 100644 index 00000000..ee516d99 --- /dev/null +++ b/code/samples/typescript/src/roles/credentials-provider-mcp/trigger-server.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * HTTP server for receiving payment receipts. Runs on port 8082. + * Mirrors the Python `credentials_provider_mcp/trigger_server.py`. + */ + +import express, { type Request, type Response } from 'express'; + +const PORT = Number(process.env.CREDENTIALS_PROVIDER_TRIGGER_PORT ?? 8082); + +const app = express(); +app.use(express.json({ limit: '1mb' })); + +app.post('/payment-receipt', (req: Request, res: Response) => { + const paymentReceipt = req.body?.payment_receipt; + if (!paymentReceipt) { + return res.status(400).json({ error: 'payment_receipt required' }); + } + // STUB: real impl calls into the MCP server's verify_payment_receipt. + // Here we just log the receipt prefix. + const prefix = + typeof paymentReceipt === 'string' ? paymentReceipt.slice(0, 20) : 'opaque'; + console.log(`[trigger] Received payment receipt: ${prefix}...`); + res.json({ status: 'ok' }); +}); + +app.listen(PORT, '127.0.0.1', () => { + console.log( + `Credentials provider trigger server: http://localhost:${PORT}/payment-receipt`, + ); +}); diff --git a/code/samples/typescript/src/roles/index.ts b/code/samples/typescript/src/roles/index.ts new file mode 100644 index 00000000..c7222e46 --- /dev/null +++ b/code/samples/typescript/src/roles/index.ts @@ -0,0 +1,22 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Agent card URLs for server agents in the AP2 system. */ +export const AGENT_URLS = { + CREDENTIALS_PROVIDER: 'http://localhost:8002/.well-known/agent-card.json', + PAYMENT_PROCESSOR: 'http://localhost:8003/.well-known/agent-card.json', + MERCHANT: 'http://localhost:8004/.well-known/agent-card.json', +} as const; diff --git a/code/samples/typescript/src/roles/merchant-agent-mcp/server.ts b/code/samples/typescript/src/roles/merchant-agent-mcp/server.ts new file mode 100644 index 00000000..607d7dba --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent-mcp/server.ts @@ -0,0 +1,436 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Merchant MCP Server — inventory, cart, checkout tools. + * + * Exposes five MCP tools consumed by the shopping agent v2 over stdio: + * search_inventory, check_product, assemble_cart, create_checkout, complete_checkout + * + * NOTE: This is the minimum viable port of the v0.2 Python `merchant_agent_mcp/server.py`. + * Mandate verification (SD-JWT, ES256 chain checks) is STUBBED. Real implementations + * would call into a ported AP2 SDK. The tool contracts (names, args, response shapes) + * faithfully mirror the Python so the shopping-agent-v2 client code can be a 1:1 port. + */ + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import fs from 'node:fs'; +import path from 'node:path'; +import { randomUUID, createHash } from 'node:crypto'; +import { z } from 'zod'; +import { + signJwtEs256, + verifyJwtEs256, + loadOrCreateKeyPair, + loadPublicJwk, +} from '../../common/sdjwt/index.js'; +import { MERCHANT_AUD, loadViPublicJwk, verifyCheckoutChain } from '../../common/vi/index.js'; + +/** Base64url SHA-256 — the checkout JWT hash binds the payment mandate. */ +function sha256Base64Url(input: string): string { + return createHash('sha256').update(input).digest('base64url'); +} + +/** PSP trigger endpoint used to settle and obtain a PSP-signed receipt. */ +const PSP_TRIGGER_PORT = process.env.MERCHANT_PAYMENT_PROCESSOR_TRIGGER_PORT ?? '8083'; +const PSP_INITIATE_URL = `http://localhost:${PSP_TRIGGER_PORT}/initiate-payment`; + +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; +const TRIGGER_STATE_PATH = + process.env.MERCHANT_TRIGGER_STATE_PATH ?? + path.join(TEMP_DB, 'merchant_trigger_state.json'); +const INVENTORY_PATH = + process.env.MERCHANT_INVENTORY_PATH ?? + path.join(TEMP_DB, 'merchant_inventory.json'); +const CARTS_PATH = + process.env.MERCHANT_CARTS_PATH ?? path.join(TEMP_DB, 'merchant_carts.json'); + +type InventoryEntry = { name: string; price: number; stock: number }; +type TriggerEntry = { price?: number; stock?: number; _touch: number }; + +function loadJson(p: string, fallback: T): T { + try { + return JSON.parse(fs.readFileSync(p, 'utf-8')) as T; + } catch { + return fallback; + } +} + +function saveJson(p: string, data: unknown): void { + fs.mkdirSync(path.dirname(p), { recursive: true }); + fs.writeFileSync(p, JSON.stringify(data, null, 2)); +} + +function loadInventory(): Record { + return loadJson(INVENTORY_PATH, {}); +} + +function saveInventory(inv: Record): void { + saveJson(INVENTORY_PATH, inv); +} + +function triggerOverrides(itemId: string): { price?: number; stock?: number } { + const state = loadJson>(TRIGGER_STATE_PATH, {}); + const entry = state[itemId]; + return { price: entry?.price, stock: entry?.stock }; +} + +function effectivePrice(itemId: string, basePrice: number): number { + const { price } = triggerOverrides(itemId); + return price ?? basePrice; +} + +function generateInventoryEntry( + productDescription: string, + priceCap: number | null, +): { item_id: string; name: string; price: number; stock: number } { + const slug = productDescription + .toLowerCase() + .replace(/[^a-z0-9]+/g, '_') + .replace(/^_|_$/g, '') + .slice(0, 40); + const itemId = `${slug}_0`; + const inv = loadInventory(); + if (inv[itemId]) { + return { item_id: itemId, ...inv[itemId] }; + } + const price = priceCap !== null ? Math.min(priceCap, 199.99) : 199.99; + const entry: InventoryEntry = { + name: productDescription.replace(/\b\w/g, (c) => c.toUpperCase()), + price, + stock: 0, + }; + inv[itemId] = entry; + saveInventory(inv); + return { item_id: itemId, ...entry }; +} + +function resolveItem(itemId: string, priceCap: number | null = null): InventoryEntry | null { + const inv = loadInventory(); + if (inv[itemId]) return inv[itemId]; + // Auto-create matching the Python pattern _0 + if (/^[a-z0-9_]+_0$/.test(itemId)) { + const description = itemId.slice(0, -2).replace(/_/g, ' '); + const entry = generateInventoryEntry(description, priceCap); + return { name: entry.name, price: entry.price, stock: entry.stock }; + } + return null; +} + +// Carts are persisted to TEMP_DB (not in-memory): the shopping agent v2 gives +// each sub-agent its own merchant MCP subprocess, so a cart assembled by one +// agent must be visible to another. File-backing keeps them consistent. +function loadCarts(): Record { + return loadJson(CARTS_PATH, {}); +} +function saveCart(cartId: string, cart: unknown): void { + const carts = loadCarts(); + carts[cartId] = cart; + saveJson(CARTS_PATH, carts); +} +function getCart(cartId: string): unknown { + return loadCarts()[cartId]; +} + +/** Read a raw text file from TEMP_DB (chain artifacts), null if absent. */ +function readTempText(filename: string): string | null { + try { + return fs.readFileSync(path.join(TEMP_DB, filename), 'utf-8'); + } catch { + return null; + } +} + +const server = new McpServer({ + name: 'merchant-mcp', + version: '0.2.0', +}); + +server.registerTool( + 'search_inventory', + { + description: + 'Search merchant inventory for a product matching a free-text description, ' + + 'optionally constrained by a price cap. Returns matching catalog entries.', + inputSchema: { + product_description: z.string(), + constraint_price_cap: z.number().nullable().optional(), + }, + }, + async ({ product_description, constraint_price_cap }) => { + if (!product_description.trim()) { + const error = { + error: 'invalid_description', + message: 'product_description must be non-empty', + }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + const entry = generateInventoryEntry( + product_description, + constraint_price_cap ?? null, + ); + const result = { + matches: [entry], + message: + `Found 1 matching product: ${entry.item_id}. ` + + 'Stock is 0 until a drop is simulated via the trigger server.', + }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +server.registerTool( + 'check_product', + { + description: + 'Check the current price and availability of a specific catalog item by id, ' + + 'applying any active price/stock trigger overrides.', + inputSchema: { + item_id: z.string(), + constraint_price_cap: z.number().nullable().optional(), + }, + }, + async ({ item_id, constraint_price_cap }) => { + const item = resolveItem(item_id, constraint_price_cap ?? null); + if (!item) { + const error = { error: 'item_not_found' }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + const price = effectivePrice(item_id, item.price); + const { stock } = triggerOverrides(item_id); + const available = stock !== undefined && stock > 0; + const result = { + item_id, + price, + available, + timestamp: Math.floor(Date.now() / 1000), + payment_method: process.env.FLOW ?? 'card', + payment_method_description: 'Card (stub)', + }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +server.registerTool( + 'assemble_cart', + { + description: + 'Assemble a cart for a given in-stock item and quantity, computing line ' + + 'items and totals in minor units, and persisting it for checkout.', + inputSchema: { item_id: z.string(), qty: z.number().int().positive() }, + }, + async ({ item_id, qty }) => { + const item = resolveItem(item_id); + if (!item) { + const error = { error: 'item_not_found' }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + const { stock } = triggerOverrides(item_id); + if (!(stock !== undefined && stock > 0)) { + const error = { + error: 'out_of_stock', + message: 'Item is not available to purchase yet (e.g. drop not live).', + }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + const price = effectivePrice(item_id, item.price); + const cartId = randomUUID(); + const priceMinor = Math.round(price * 100); + const totalMinor = priceMinor * qty; + const cart = { + cart_id: cartId, + total: totalMinor, + line_items: [ + { item_id, qty, unit_price: priceMinor, item_name: item.name }, + ], + currency: 'USD', + }; + saveCart(cartId, cart); + return { + content: [{ type: 'text', text: JSON.stringify(cart) }], + structuredContent: cart, + }; + }, +); + +server.registerTool( + 'create_checkout', + { + description: + 'Create a checkout for a previously assembled cart, returning a real ES256-signed ' + + 'merchant checkout JWT and its hash. The agent commits checkout_jwt_hash into the ' + + 'Layer 3 fulfillment (it becomes the payment transaction_id and the checkout binding).', + inputSchema: { + cart_id: z.string(), + // Accepted for backwards-compat with older prompts; the VI chain binds via + // checkout_jwt_hash, so the open-mandate id is no longer required here. + open_checkout_mandate_id: z.string().optional(), + }, + }, + async ({ cart_id }) => { + const cart = getCart(cart_id); + if (!cart) { + const error = { error: 'cart_not_found' }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + // Sign a real ES256 checkout JWT with the merchant key. A random `jti` gives + // the JWT entropy (the AP2 spec warns deterministic signatures over + // low-entropy checkout content are rainbow-table-able for the hash binding). + const merchant = await loadOrCreateKeyPair(TEMP_DB, 'merchant'); + const checkoutJwt = await signJwtEs256( + { + iss: 'merchant-agent', + iat: Math.floor(Date.now() / 1000), + jti: randomUUID(), + cart, + }, + merchant.privateKey, + ); + const checkoutJwtHash = sha256Base64Url(checkoutJwt); + const result = { + checkout_jwt: checkoutJwt, + checkout_jwt_hash: checkoutJwtHash, + cart, + }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +server.registerTool( + 'complete_checkout', + { + description: + 'Verify the checkout-side Verifiable Intent chain (L1 issuer -> L2 user mandate -> L3b agent ' + + 'checkout fulfillment) for the given chain id, then settle with the PSP and return a ' + + 'merchant-signed checkout receipt plus the PSP-signed payment receipt.', + inputSchema: { + checkout_jwt: z.string(), + payment_credential: z.unknown().optional(), + checkout_mandate_chain_id: z.string(), + }, + }, + async ({ checkout_jwt, payment_credential, checkout_mandate_chain_id }) => { + // 1. Verify the merchant's own checkout JWT signature before finalizing. + const merchantPub = loadPublicJwk(TEMP_DB, 'merchant'); + if (!merchantPub) { + const error = { error: 'merchant_key_unavailable', message: 'merchant key not found in TEMP_DB' }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + let checkoutJwtHash: string; + try { + await verifyJwtEs256(checkout_jwt, merchantPub); + checkoutJwtHash = sha256Base64Url(checkout_jwt); + } catch (e) { + const error = { error: 'invalid_checkout_jwt', message: String(e) }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + + // 2. Verify the checkout-side VI chain the agent produced (L1 -> L2 -> L3b). + const l1 = readTempText('l1.sdjwt'); + const l3Checkout = readTempText(`${checkout_mandate_chain_id}.sdjwt`); + const l2Checkout = readTempText(`${checkout_mandate_chain_id}.l2.sdjwt`); + const issuerPub = loadViPublicJwk(TEMP_DB, 'issuer'); + if (!l1 || !l3Checkout || !l2Checkout || !issuerPub) { + const error = { + error: 'checkout_chain_artifacts_missing', + message: `missing L1/L2/L3b for ${checkout_mandate_chain_id}`, + }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + try { + const chain = await verifyCheckoutChain({ + l1Serialized: l1, + l2CheckoutSerialized: l2Checkout, + l3CheckoutSerialized: l3Checkout, + issuerPublicJwk: issuerPub, + expectedL3CheckoutAud: MERCHANT_AUD, + }); + if (!chain.valid) { + const error = { error: 'checkout_chain_invalid', message: chain.errors.join('; ') }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + } catch (e) { + const error = { error: 'checkout_chain_verification_failed', message: String(e) }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + + // Settle with the PSP (server-to-server) and obtain a PSP-signed payment + // receipt — mirrors Python merchant_agent_mcp._initiate_payment_with_payment_processor. + let paymentReceipt: string | null = null; + try { + const res = await fetch(PSP_INITIATE_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + payment_token: (payment_credential as { payment_token?: string })?.payment_token ?? 'tok_unknown', + checkout_jwt_hash: checkoutJwtHash, + open_checkout_hash: checkoutJwtHash, + }), + }); + const body = (await res.json()) as { payment_receipt?: string }; + paymentReceipt = body.payment_receipt ?? null; + } catch (e) { + const error = { error: 'psp_settlement_failed', message: String(e) }; + return { content: [{ type: 'text', text: JSON.stringify(error) }], structuredContent: error, isError: true }; + } + + // Sign the merchant's checkout receipt (ES256) over the verified checkout. + const merchant = await loadOrCreateKeyPair(TEMP_DB, 'merchant'); + const checkoutReceipt = await signJwtEs256( + { + iss: 'merchant-agent', + receipt_id: randomUUID(), + iat: Math.floor(Date.now() / 1000), + checkout_jwt_hash: checkoutJwtHash, + }, + merchant.privateKey, + ); + const result = { + status: 'completed', + checkout_receipt: checkoutReceipt, // merchant-signed ES256 JWT + payment_receipt: paymentReceipt, // PSP-signed ES256 JWT + }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +const transport = new StdioServerTransport(); +await server.connect(transport); diff --git a/code/samples/typescript/src/roles/merchant-agent-mcp/trigger-server.ts b/code/samples/typescript/src/roles/merchant-agent-mcp/trigger-server.ts new file mode 100644 index 00000000..e27bc1fd --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent-mcp/trigger-server.ts @@ -0,0 +1,103 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * HTTP server for simulating merchant-side events. Mirrors the Python + * `merchant_agent_mcp/trigger_server.py` semantics. + * + * Example: + * curl -X POST "http://localhost:8081/trigger-price-drop?item_id=apple_0&price=5&stock=10" + */ + +import express, { type Request, type Response } from 'express'; +import fs from 'node:fs'; +import path from 'node:path'; + +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; +const TRIGGER_STATE_PATH = + process.env.MERCHANT_TRIGGER_STATE_PATH ?? + path.join(TEMP_DB, 'merchant_trigger_state.json'); +const PORT = Number(process.env.MERCHANT_TRIGGER_PORT ?? 8081); + +type TriggerEntry = { price?: number; stock?: number; _touch: number }; +type TriggerState = Record; + +function loadState(): TriggerState { + try { + return JSON.parse(fs.readFileSync(TRIGGER_STATE_PATH, 'utf-8')) as TriggerState; + } catch { + return {}; + } +} + +function mergeState(itemId: string, value: TriggerEntry): TriggerState { + const state = loadState(); + state[itemId] = value; + fs.mkdirSync(path.dirname(TRIGGER_STATE_PATH), { recursive: true }); + fs.writeFileSync(TRIGGER_STATE_PATH, JSON.stringify(state, null, 2)); + return state; +} + +const app = express(); + +app.use((_req, res, next) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + next(); +}); + +app.options(/.*/, (_req, res) => { + res.status(204).end(); +}); + +app.post('/trigger-price-drop', (req: Request, res: Response) => { + const itemId = String(req.query.item_id ?? ''); + if (!itemId) { + return res.status(400).json({ error: 'item_id required' }); + } + const price = Number(req.query.price ?? 5); + const stockRaw = req.query.stock; + const payload: TriggerEntry = { price, _touch: Date.now() / 1000 }; + if (stockRaw !== undefined) { + payload.stock = Math.max(0, Number(stockRaw)); + } + mergeState(itemId, payload); + const stockMsg = payload.stock !== undefined ? `, stock ${payload.stock}` : ''; + res.json({ + ok: true, + item_id: itemId, + price, + ...(payload.stock !== undefined ? { stock: payload.stock } : {}), + message: + `Price for ${itemId} set to $${price}${stockMsg}. ` + + 'Shopping agent sees it on next check_product (web UI may nudge immediately via /state poll).', + }); +}); + +app.get('/state', (req: Request, res: Response) => { + const itemId = String(req.query.item_id ?? ''); + if (!itemId) return res.status(400).json({ error: 'item_id required' }); + const entry = loadState()[itemId] ?? null; + res.json({ item_id: itemId, entry }); +}); + +app.get(['/', '/health'], (_req: Request, res: Response) => { + res.json({ + status: 'ok', + endpoints: [ + `POST http://localhost:${PORT}/trigger-price-drop?item_id=&price=[&stock=]`, + `GET http://localhost:${PORT}/state?item_id=`, + ], + }); +}); + +app.listen(PORT, '127.0.0.1', () => { + console.log(`Merchant trigger server: http://localhost:${PORT}/`); + console.log(`State file: ${TRIGGER_STATE_PATH}`); +}); diff --git a/code/samples/typescript/src/roles/merchant-agent/agent.ts b/code/samples/typescript/src/roles/merchant-agent/agent.ts new file mode 100644 index 00000000..9671f5c9 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent/agent.ts @@ -0,0 +1,50 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from '@google/adk'; +import { DEBUG_MODE_INSTRUCTIONS } from '../../common/constants/index.js'; +import { findItemsWorkflow, updateCart, initiatePayment, dpcFinish } from './tools.js'; + +/** + * Merchant Agent (ADK) + * + * A sales assistant agent for merchants. Handles catalog search, cart updates, + * and payment processing. + */ +export const merchantAgent = new LlmAgent({ + name: 'merchant_agent', + model: 'gemini-2.5-flash', + description: 'A sales assistant agent for a merchant.', + instruction: `You are a merchant sales assistant agent. Your role is to help customers find products, manage their shopping cart, and complete purchases. + +Based on the customer's request, select the appropriate tool to call: + +1. **findItemsWorkflow**: Use when the customer wants to search for products or when you receive an IntentMandate. This generates product recommendations. + +2. **updateCart**: Use when the customer provides a shipping address and you need to update the cart with shipping costs and taxes. + +3. **initiatePayment**: Use when the customer wants to complete their purchase and you have a PaymentMandate. + +4. **dpcFinish**: Use when you receive a DPC response to finalize the payment. + +Important: +- If you detect a PaymentMandate in the request, immediately call initiatePayment +- Only call one tool per request based on the current context +- After the tool returns a result, respond with a brief summary of the outcome. Do not call the same tool again after it has already returned. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [findItemsWorkflow, updateCart, initiatePayment, dpcFinish], +}); diff --git a/code/samples/typescript/src/roles/merchant-agent/server.ts b/code/samples/typescript/src/roles/merchant-agent/server.ts new file mode 100644 index 00000000..edb02708 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent/server.ts @@ -0,0 +1,190 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { v4 as uuidv4 } from 'uuid'; +import { Runner } from '@google/adk'; +import type { + AgentCard, + Message, + TaskStatusUpdateEvent, +} from '@a2a-js/sdk'; + +import { merchantAgent } from './agent.js'; +import { sessionService } from '../../common/config/session.js'; +import { BaseAgentExecutor } from '../../common/server/base-executor.js'; +import { bootstrapServer } from '../../common/server/bootstrap.js'; +import { DATA_KEYS } from '../../common/constants/index.js'; + +const runner = new Runner({ + appName: 'ap2-merchant', + agent: merchantAgent, + sessionService, +}); + +const agentExecutor = new BaseAgentExecutor({ + agentName: 'merchant_agent', + appName: 'ap2-merchant', + runner, + maxLlmCalls: 5, + workingMessage: 'The merchant is processing your request...', + preprocessMessage({ userText, dataParts }) { + // If PaymentMandate is present, instruct agent to call initiatePayment immediately + const hasPaymentMandate = dataParts.some( + (dp) => DATA_KEYS.PAYMENT_MANDATE in dp + ); + if (hasPaymentMandate) { + return 'A PaymentMandate is present in the data. Call the initiatePayment tool immediately.'; + } + // If IntentMandate is present, instruct agent to call findItemsWorkflow immediately + const hasIntentMandate = dataParts.some( + (dp) => DATA_KEYS.INTENT_MANDATE in dp + ); + if (hasIntentMandate) { + return 'An IntentMandate is present in the data. Call the findItemsWorkflow tool immediately to find matching products.'; + } + return userText; + }, + postprocessResult({ + responseText, + toolWasCalled, + lastToolResult, + eventBus, + taskId, + contextId, + }) { + // Handle payment input-required status (OTP challenge) + if (lastToolResult?.status === 'input-required') { + const inputRequiredMessage: Message = { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [ + { + kind: 'text', + text: 'A payment challenge has been raised. Please provide the OTP to complete the transaction. (Hint: the code is 123)', + }, + ], + taskId, + contextId, + }; + + eventBus.publish({ + kind: 'status-update', + taskId, + contextId, + status: { + state: 'input-required', + message: inputRequiredMessage, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent); + + return null; // Signal: already handled + } + + // If the initiatePayment tool already published a terminal status-update + // (completed/failed) directly via eventBus, suppress the default to avoid + // double-publishing. + const terminalToolStates = ['completed', 'failed', 'canceled', 'rejected']; + if (lastToolResult?.status && terminalToolStates.includes(lastToolResult.status as string)) { + return null; // Signal: already handled by the tool + } + + // Determine final response text + let finalText = responseText || 'Completed.'; + if (toolWasCalled && !responseText) { + finalText = 'Request processed successfully.'; + } + + const agentMessage: Message = { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: finalText }], + taskId, + contextId, + }; + + return { + kind: 'status-update', + taskId, + contextId, + status: { + state: 'completed', + message: agentMessage, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent; + }, +}); + +const agentCard: AgentCard = { + name: 'MerchantAgent', + description: 'A sales assistant agent for a merchant.', + url: 'http://localhost:8004', + provider: { organization: 'AP2 Demo', url: 'https://github.com/google-agentic-commerce/ap2' }, + skills: [ + { + id: 'search_catalog', + name: 'Search Catalog', + description: + "Searches the merchant's catalog based on a shopping intent & returns a cart containing the top results.", + parameters: { + type: 'object', + properties: { + shopping_intent: { + type: 'string', + description: + "A JSON string representing the user's shopping intent.", + }, + }, + required: ['shopping_intent'], + }, + tags: ['merchant', 'search', 'catalog'], + } as AgentCard['skills'][number], + ], + capabilities: { + streaming: true, + pushNotifications: false, + stateTransitionHistory: true, + extensions: [ + { + uri: 'https://github.com/google-agentic-commerce/ap2/v1', + description: 'Supports the Agent Payments Protocol.', + required: true, + }, + { + uri: 'https://sample-card-network.github.io/paymentmethod/common/types/v1', + description: + 'Supports the Sample Card Network payment method extension', + required: true, + }, + ], + }, + defaultInputModes: ['application/json'], + defaultOutputModes: ['application/json'], + protocolVersion: '0.3.0', + version: '1.0.0', +}; + +bootstrapServer({ + agentCard, + agentExecutor, + port: 8004, + label: 'Merchant', +}); diff --git a/code/samples/typescript/src/roles/merchant-agent/storage.ts b/code/samples/typescript/src/roles/merchant-agent/storage.ts new file mode 100644 index 00000000..714d7db0 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent/storage.ts @@ -0,0 +1,57 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * In-memory storage for CartMandates and risk data. + * + * A CartMandate may be updated multiple times during the course of a shopping + * journey. This storage system is used to persist CartMandates between + * interactions between the shopper and merchant agents. + */ + +import type { CartMandate } from "../../common/types/cart-mandate.js"; + +// Separate stores for type safety — avoids union-type ambiguity +const cartMandateStore = new Map(); +const riskDataStore = new Map(); + +/** + * Get a cart mandate by cart ID. + */ +export function getCartMandate(cartId: string): CartMandate | undefined { + return cartMandateStore.get(cartId); +} + +/** + * Set a cart mandate by cart ID. + */ +export function setCartMandate(cartId: string, cartMandate: CartMandate): void { + cartMandateStore.set(cartId, cartMandate); +} + +/** + * Set risk data by context ID. + */ +export function setRiskData(contextId: string, riskData: string): void { + riskDataStore.set(contextId, riskData); +} + +/** + * Get risk data by context ID. + */ +export function getRiskData(contextId: string): string | undefined { + return riskDataStore.get(contextId); +} diff --git a/code/samples/typescript/src/roles/merchant-agent/tools.ts b/code/samples/typescript/src/roles/merchant-agent/tools.ts new file mode 100644 index 00000000..fd1b6e66 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-agent/tools.ts @@ -0,0 +1,542 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from '@google/adk'; +import { z } from 'zod'; +import { v4 as uuidv4 } from 'uuid'; +import { A2AClient } from '@a2a-js/sdk/client'; +import type { + MessageSendParams, + SendMessageSuccessResponse, + Task, + TaskArtifactUpdateEvent, + TaskStatusUpdateEvent, +} from '@a2a-js/sdk'; +import { findDataPart, parseCanonicalObject } from '../../common/utils/message.js'; +import { getA2AContextFromTool } from '../../common/server/a2a-context.js'; +import type { PaymentItem } from '../../common/types/payment-item.js'; +import type { CartMandate } from '../../common/types/cart-mandate.js'; +import type { IntentMandate } from '../../common/types/intent-mandate.js'; +import type { PaymentMandate } from '../../common/types/payment-mandate.js'; +import { intentMandateSchema } from '../../common/schemas/intent-mandate.js'; +import { paymentMandateSchema } from '../../common/schemas/payment-mandate.js'; +import { getCartMandate, getRiskData, setCartMandate, setRiskData } from './storage.js'; +import { GoogleGenAI } from '@google/genai'; +import { AGENT_URLS } from '../index.js'; +import { DATA_KEYS } from '../../common/constants/index.js'; + +/** Known shopping agent IDs allowed to interact with this merchant. */ +const KNOWN_SHOPPING_AGENTS = new Set(['trusted_shopping_agent']); + +const FAKE_JWT = 'eyJhbGciOiJSUzI1NiIsImtpZIwMjQwOTA...'; +const INTENT_MANDATE_DATA_KEY = DATA_KEYS.INTENT_MANDATE; +const CART_MANDATE_DATA_KEY = DATA_KEYS.CART_MANDATE; +const PAYMENT_MANDATE_DATA_KEY = DATA_KEYS.PAYMENT_MANDATE; + +const PAYMENT_PROCESSORS_BY_PAYMENT_METHOD_TYPE: Record = { + CARD: AGENT_URLS.PAYMENT_PROCESSOR, + 'https://www.x402.org/': AGENT_URLS.PAYMENT_PROCESSOR, +}; + +// Lazy initialization of Gemini for product generation +function getGenAI() { + const apiKey = process.env.GOOGLE_GENAI_API_KEY || process.env.GEMINI_API_KEY; + if (!apiKey) { + throw new Error('GOOGLE_GENAI_API_KEY or GEMINI_API_KEY environment variable is required for product generation'); + } + return new GoogleGenAI({ apiKey }); +} + +// Helper functions +function getPaymentProcessorTaskId(task: Task | undefined): string | null { + if (!task || !task.history) { + return null; + } + + for (const message of task.history) { + if (message.taskId && message.taskId !== task.id) { + return message.taskId; + } + } + + return null; +} + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +/** + * Tool 1: Find Items Workflow + * + * Generates products matching the user's IntentMandate using Gemini. + */ +export const findItemsWorkflow = new FunctionTool({ + name: 'findItemsWorkflow', + description: "Finds products that match the user's IntentMandate by generating realistic product recommendations. Pass the user's shopping intent description.", + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + intentDescription: z.string().optional().describe("The user's shopping intent description (used in ADK dev mode when no A2A data parts are available)."), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const taskId = currentTask?.id || uuidv4(); + const contextId = currentTask?.contextId || uuidv4(); + + // Validate shopping agent ID + const shoppingAgentId = findDataPart('shopping_agent_id', dataParts) as string | null; + if (shoppingAgentId && !KNOWN_SHOPPING_AGENTS.has(shoppingAgentId)) { + return { error: `Unknown shopping agent: ${shoppingAgentId}. Report this error to the caller.` }; + } + + // Parse IntentMandate from A2A data parts, or fall back to direct parameter + let intent: string; + try { + const intentMandate = parseCanonicalObject( + INTENT_MANDATE_DATA_KEY, + dataParts, + intentMandateSchema + ); + intent = intentMandate.naturalLanguageDescription; + } catch { + // ADK dev mode fallback: use the intent description parameter directly + if (input.intentDescription) { + intent = input.intentDescription; + } else { + return { error: 'IntentMandate not found in request data and no intentDescription provided. Report this error to the caller.' }; + } + } + + // Generate products using Gemini + const genAI = getGenAI(); + + const prompt = `Based on the user's request for '${intent}', generate 3 complete, unique and realistic PaymentItem JSON objects. + +You MUST exclude all branding from the PaymentItem label field. + +Generate realistic, diverse product data with reasonable prices and details. + +Return a JSON array where each object has: label (string), amount (object with currency string and value number), and refundPeriod (number in days).`; + + // Retry mechanism + const maxRetries = 3; + const retryDelay = 1000; + let items: PaymentItem[] = []; + + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + const result = await genAI.models.generateContent({ + model: 'gemini-2.5-flash', + contents: prompt, + config: { + responseMimeType: 'application/json', + }, + }); + const text = result.text ?? ''; + items = JSON.parse(text) as PaymentItem[]; + break; + } catch (error) { + if (attempt === maxRetries - 1) { + return { error: `Unable to generate products after ${maxRetries} attempts: ${error instanceof Error ? error.message : String(error)}. Report this error to the caller.` }; + } + await sleep(retryDelay * (attempt + 1)); + } + } + + if (!items || items.length === 0) { + return { error: 'No products were generated. Report this error to the caller.' }; + } + + // Create cart mandates for each item + const currentTime = new Date(); + let itemCount = 0; + + for (const item of items) { + itemCount++; + const cartExpiryTime = new Date(currentTime.getTime() + 30 * 60 * 1000); + + const cartMandate: CartMandate = { + contents: { + id: `cart_${itemCount}`, + userCartConfirmationRequired: true, + paymentRequest: { + methodData: [ + { + supportedMethods: 'CARD', + data: { + network: ['mastercard', 'paypal', 'amex'], + }, + }, + ], + details: { + id: `order_${itemCount}`, + displayItems: [item], + shippingOptions: [], + modifiers: [], + total: { + label: 'Total', + amount: item.amount, + pending: false, + refundPeriod: item.refundPeriod, + }, + }, + options: { + requestShipping: true, + }, + }, + cartExpiry: cartExpiryTime.toISOString(), + merchantName: 'Generic Merchant', + }, + }; + + setCartMandate(cartMandate.contents.id, cartMandate); + + const artifactUpdate: TaskArtifactUpdateEvent = { + kind: 'artifact-update', + taskId, + contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { + kind: 'data', + data: { + [CART_MANDATE_DATA_KEY]: cartMandate, + }, + }, + ], + }, + }; + + eventBus.publish(artifactUpdate); + } + + // Add risk data + const riskData = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...fake_risk_data'; + setRiskData(contextId, riskData); + + const riskDataArtifact: TaskArtifactUpdateEvent = { + kind: 'artifact-update', + taskId, + contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { + kind: 'data', + data: { risk_data: riskData }, + }, + ], + }, + }; + eventBus.publish(riskDataArtifact); + + return { status: 'success', itemCount }; + }, +}); + +/** + * Tool 2: Update Cart + * + * Updates cart with shipping address and adds tax/shipping costs. + */ +export const updateCart = new FunctionTool({ + name: 'updateCart', + description: 'Updates an existing cart after a shipping address is provided.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const cartId = findDataPart('cart_id', dataParts) as string | null; + if (!cartId) { + return { error: 'Missing cart_id in request data. Report this error to the caller.' }; + } + + const shippingAddress = findDataPart( + 'shipping_address', + dataParts + ) as Record | null; + if (!shippingAddress) { + return { error: 'Missing shipping address in request data. Report this error to the caller.' }; + } + + const cartMandate = getCartMandate(cartId); + if (!cartMandate) { + return { error: `CartMandate not found for cart_id: ${cartId}. Report this error to the caller.` }; + } + + const riskData = getRiskData(currentTask.contextId); + if (!riskData) { + return { error: `Missing risk_data for context_id: ${currentTask.contextId}. Report this error to the caller.` }; + } + + // Cast shipping address from A2A data parts to the expected schema type + cartMandate.contents.paymentRequest.shippingAddress = shippingAddress as typeof cartMandate.contents.paymentRequest.shippingAddress; + + const taxAndShippingCosts: PaymentItem[] = [ + { + label: 'Shipping', + amount: { + currency: 'USD', + value: 2.0, + }, + refundPeriod: 30, + }, + { + label: 'Tax', + amount: { + currency: 'USD', + value: 1.5, + }, + refundPeriod: 30, + }, + ]; + + const paymentRequest = cartMandate.contents.paymentRequest; + + if (!paymentRequest.details.displayItems) { + paymentRequest.details.displayItems = taxAndShippingCosts; + } else { + paymentRequest.details.displayItems.push(...taxAndShippingCosts); + } + + paymentRequest.details.total.amount.value = + paymentRequest.details.displayItems.reduce( + (acc, curr) => acc + curr.amount.value, + 0 + ); + + cartMandate.merchantAuthorization = FAKE_JWT; + + const artifactUpdate: TaskArtifactUpdateEvent = { + kind: 'artifact-update', + taskId: currentTask.id, + contextId: currentTask.contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { + kind: 'data', + data: { + [CART_MANDATE_DATA_KEY]: cartMandate, + }, + }, + { + kind: 'data', + data: { + risk_data: riskData, + }, + }, + ], + }, + }; + + eventBus.publish(artifactUpdate); + + return { status: 'success', cartMandate }; + }, +}); + +/** + * Tool 3: Initiate Payment + * + * Delegates payment processing to the payment processor agent. + */ +export const initiatePayment = new FunctionTool({ + name: 'initiatePayment', + description: 'Initiates a payment for a given payment mandate by delegating to the payment processor.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + let paymentMandate: PaymentMandate; + try { + paymentMandate = parseCanonicalObject( + PAYMENT_MANDATE_DATA_KEY, + dataParts, + paymentMandateSchema + ); + } catch { + return { error: 'PaymentMandate not found in request data. Report this error to the caller.' }; + } + + const riskData = findDataPart('risk_data', dataParts) as string | null; + if (!riskData) { + return { error: 'Missing risk_data in request data. Report this error to the caller.' }; + } + + const paymentMethodType = + paymentMandate.paymentMandateContents.paymentResponse.methodName; + + const processorUrl = + PAYMENT_PROCESSORS_BY_PAYMENT_METHOD_TYPE[paymentMethodType]; + + if (!processorUrl) { + return { error: `No payment processor found for method: ${paymentMethodType}. Report this error to the caller.` }; + } + + const client = await A2AClient.fromCardUrl(processorUrl); + + const message: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + contextId: currentTask.contextId, + parts: [ + { + kind: 'text', + text: 'Call the initiatePayment tool to process this payment. The payment mandate and risk data are provided in the data parts of this message.', + }, + { + kind: 'data', + data: { + [PAYMENT_MANDATE_DATA_KEY]: paymentMandate, + }, + }, + { + kind: 'data', + data: { + risk_data: riskData, + }, + }, + ], + kind: 'message', + }, + }; + + const challengeResponse = findDataPart('challenge_response', dataParts) as + | string + | null; + if (challengeResponse) { + message.message.parts.push({ + kind: 'data', + data: { challenge_response: challengeResponse }, + }); + } + + const paymentProcessorTaskId = getPaymentProcessorTaskId(currentTask); + if (paymentProcessorTaskId) { + message.message.taskId = paymentProcessorTaskId; + } + + const response = await client.sendMessage(message); + + if ('error' in response) { + return { error: `Payment processor error: ${response.error.message}. Report this error to the caller.` }; + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === 'task') { + const task = result as Task; + + // Forward PaymentReceipt artifacts from payment processor to shopping agent + for (const artifact of task.artifacts ?? []) { + for (const part of artifact.parts) { + if (part.kind === 'data') { + const data = (part as { kind: 'data'; data: Record }).data; + if (data[DATA_KEYS.PAYMENT_RECEIPT]) { + const receiptArtifact: TaskArtifactUpdateEvent = { + kind: 'artifact-update', + taskId: currentTask.id, + contextId: currentTask.contextId, + artifact: { + artifactId: uuidv4(), + parts: [{ kind: 'data', data: { [DATA_KEYS.PAYMENT_RECEIPT]: data[DATA_KEYS.PAYMENT_RECEIPT] } }], + }, + }; + eventBus.publish(receiptArtifact); + } + } + } + } + + const statusUpdate: TaskStatusUpdateEvent = { + kind: 'status-update', + taskId: currentTask.id, + contextId: currentTask.contextId, + status: { + state: task.status.state, + message: task.status.message, + timestamp: new Date().toISOString(), + }, + final: false, + }; + + const terminalStates = ['completed', 'failed', 'canceled', 'rejected']; + if (terminalStates.includes(task.status.state)) { + statusUpdate.final = true; + } + + eventBus.publish(statusUpdate); + + return { + status: task.status.state, + taskId: task.id, + }; + } + + return { error: 'Unexpected response type from payment processor. Report this error to the caller.' }; + }, +}); + +/** + * Tool 4: DPC Finish + * + * Receives and validates DPC response to finalize payment. + */ +export const dpcFinish = new FunctionTool({ + name: 'dpcFinish', + description: 'Receives and validates a DPC response to finalize payment. This receives the Digital Payment Credential (DPC) response and simulates payment finalization.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + + const dpcResponse = findDataPart('dpc_response', dataParts) as Record< + string, + unknown + > | null; + if (!dpcResponse) { + return { error: 'Missing dpc_response in request data. Report this error to the caller.' }; + } + + const artifactUpdate: TaskArtifactUpdateEvent = { + kind: 'artifact-update', + taskId: currentTask.id, + contextId: currentTask.contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { + kind: 'data', + data: { paymentStatus: 'SUCCESS', transactionId: 'txn_1234567890' }, + }, + ], + }, + }; + eventBus.publish(artifactUpdate); + + return { status: 'success' }; + }, +}); diff --git a/code/samples/typescript/src/roles/merchant-payment-processor-agent/agent.ts b/code/samples/typescript/src/roles/merchant-payment-processor-agent/agent.ts new file mode 100644 index 00000000..7f75377f --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-payment-processor-agent/agent.ts @@ -0,0 +1,41 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from "@google/adk"; +import { DEBUG_MODE_INSTRUCTIONS } from "../../common/constants/index.js"; +import { initiatePayment } from "./tools.js"; + +/** + * Payment Processor Agent (ADK) + * + * Processes card payments on behalf of merchants with OTP challenge support. + */ +export const paymentProcessorAgent = new LlmAgent({ + name: "payment_processor_agent", + model: "gemini-2.5-flash", + description: "An agent that processes card payments on behalf of a merchant.", + instruction: `You are a payment processor agent that handles card payments. + +When you receive a payment mandate, call the initiatePayment tool to process it. +The tool will handle the OTP challenge flow automatically. + +Call the initiatePayment tool exactly once per request. After the tool returns +a result, respond with a brief summary of the outcome. Do not call the tool +again after it has already returned. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [initiatePayment], +}); diff --git a/code/samples/typescript/src/roles/merchant-payment-processor-agent/server.ts b/code/samples/typescript/src/roles/merchant-payment-processor-agent/server.ts new file mode 100644 index 00000000..653d61ed --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-payment-processor-agent/server.ts @@ -0,0 +1,91 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Runner } from '@google/adk'; +import type { AgentCard } from '@a2a-js/sdk'; + +import { paymentProcessorAgent } from './agent.js'; +import { sessionService } from '../../common/config/session.js'; +import { BaseAgentExecutor } from '../../common/server/base-executor.js'; +import { bootstrapServer } from '../../common/server/bootstrap.js'; + +const runner = new Runner({ + appName: 'ap2-payment-processor', + agent: paymentProcessorAgent, + sessionService, +}); + +const agentExecutor = new BaseAgentExecutor({ + agentName: 'payment_processor_agent', + appName: 'ap2-payment-processor', + runner, + maxLlmCalls: 3, + workingMessage: 'Processing payment...', + postprocessResult({ lastToolResult, responseText: _responseText, toolWasCalled: _toolWasCalled }) { + // If tool returned input-required or completed, it already published + // the status update directly via eventBus -- suppress default handling + if (lastToolResult?.status === 'input-required' || lastToolResult?.status === 'completed') { + return null; // Signal: already handled + } + + // Otherwise, let the base class handle default completion + return undefined; + }, +}); + +const agentCard: AgentCard = { + name: 'MerchantPaymentProcessorAgent', + description: 'An agent that processes card payments on behalf of a merchant.', + url: 'http://localhost:8003', + provider: { organization: 'AP2 Demo', url: 'https://github.com/google-agentic-commerce/ap2' }, + skills: [ + { + id: 'card-processor', + name: 'Card Processor', + description: 'Processes card payments.', + tags: ['payment', 'card'], + }, + ], + capabilities: { + streaming: true, + pushNotifications: false, + stateTransitionHistory: true, + extensions: [ + { + uri: 'https://github.com/google-agentic-commerce/ap2/v1', + description: 'Supports the Agent Payments Protocol.', + required: true, + }, + { + uri: 'https://sample-card-network.github.io/paymentmethod/common/types/v1', + description: + 'Supports the Sample Card Network payment method extension', + required: true, + }, + ], + }, + defaultInputModes: ['text/plain'], + defaultOutputModes: ['application/json'], + protocolVersion: '0.3.0', + version: '1.0.0', +}; + +bootstrapServer({ + agentCard, + agentExecutor, + port: 8003, + label: 'PaymentProcessor', +}); diff --git a/code/samples/typescript/src/roles/merchant-payment-processor-agent/tools.ts b/code/samples/typescript/src/roles/merchant-payment-processor-agent/tools.ts new file mode 100644 index 00000000..5ec07750 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-payment-processor-agent/tools.ts @@ -0,0 +1,396 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from "@google/adk"; +import { z } from "zod"; +import { v4 as uuidv4 } from "uuid"; +import { A2AClient } from "@a2a-js/sdk/client"; +import type { + MessageSendParams, + SendMessageSuccessResponse, + Task, + TaskArtifactUpdateEvent, + TaskStatusUpdateEvent, +} from "@a2a-js/sdk"; +import type { ExecutionEventBus } from "@a2a-js/sdk/server"; +import { findDataPart, parseCanonicalObject } from "../../common/utils/message.js"; +import { getA2AContextFromTool } from "../../common/server/a2a-context.js"; +import type { PaymentMandate } from "../../common/types/payment-mandate.js"; +import type { PaymentReceipt } from "../../common/types/payment-receipt.js"; +import { paymentMandateSchema } from "../../common/schemas/payment-mandate.js"; +import { DATA_KEYS } from "../../common/constants/index.js"; + +const PAYMENT_MANDATE_DATA_KEY = DATA_KEYS.PAYMENT_MANDATE; +const PAYMENT_RECEIPT_DATA_KEY = DATA_KEYS.PAYMENT_RECEIPT; + +// TODO(production): Replace with real OTP verification against issuer/network API. +function challengeResponseIsValid(challengeResponse: string): boolean { + return challengeResponse === "123"; // Demo-only hardcoded OTP +} + +function getCredentialsProviderUrl( + paymentMandate: PaymentMandate +): string | null { + const details = paymentMandate.paymentMandateContents.paymentResponse.details; + if (!details) return null; + const tokenObj = details.token as + | { value?: string; url?: string } + | string + | undefined; + if (typeof tokenObj === "object" && tokenObj?.url) { + return tokenObj.url; + } + return null; +} + +/** + * Request payment credentials from the credentials provider. + * For x402, the signed payload is already in payment_response.details. + */ +async function requestPaymentCredential( + paymentMandate: PaymentMandate, + contextId: string, + debugMode: boolean = false, + paymentMethod: string = "CARD" +): Promise { + if (paymentMethod === "x402") { + // For x402, the signed payload is already in the payment_response.details + return paymentMandate.paymentMandateContents.paymentResponse.details?.value; + } + + const credentialsProviderUrl = getCredentialsProviderUrl(paymentMandate); + if (!credentialsProviderUrl) { + throw new Error( + "Could not resolve credentials provider URL from payment mandate token." + ); + } + + const client = await A2AClient.fromCardUrl(credentialsProviderUrl); + + const message: MessageSendParams = { + message: { + messageId: uuidv4(), + role: "user", + contextId, + parts: [ + { + kind: "text", + text: "Give me the payment method credentials for the given token.", + }, + { kind: "data", data: { [PAYMENT_MANDATE_DATA_KEY]: paymentMandate } }, + { kind: "data", data: { debug_mode: debugMode } }, + ], + kind: "message", + }, + }; + + const response = await client.sendMessage(message); + + if ("error" in response) { + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === "task") { + const task = result as Task; + if (!task.artifacts || task.artifacts.length === 0) { + throw new Error("Failed to find the payment method data."); + } + + const firstArtifact = task.artifacts[0]; + if (firstArtifact.parts && firstArtifact.parts.length > 0) { + const dataPart = firstArtifact.parts.find((p) => p.kind === "data"); + if (dataPart && dataPart.kind === "data") { + return dataPart.data; + } + } + } + + throw new Error("Failed to retrieve payment credentials."); +} + +/** + * Create a PaymentReceipt from the payment mandate + */ +function createPaymentReceipt(paymentMandate: PaymentMandate): PaymentReceipt { + const paymentId = uuidv4(); + const contents = paymentMandate.paymentMandateContents; + const paymentMethod = process.env.PAYMENT_METHOD || "CARD"; + const methodName = + paymentMethod === "x402" + ? "https://www.x402.org/" + : contents.paymentResponse.methodName; + + return { + paymentMandateId: contents.paymentMandateId, + timestamp: new Date().toISOString(), + paymentId, + amount: contents.paymentDetailsTotal.amount, + paymentStatus: { + kind: "success", + merchantConfirmationId: paymentId, + pspConfirmationId: paymentId, + }, + paymentMethodDetails: { + methodName, + }, + }; +} + +/** + * Send the payment receipt to the credentials provider. + * For x402, skip this step + */ +async function sendPaymentReceiptToCredentialsProvider( + paymentReceipt: PaymentReceipt, + paymentMandate: PaymentMandate, + contextId: string, + debugMode: boolean = false +): Promise { + const paymentMethod = process.env.PAYMENT_METHOD || "CARD"; + if (paymentMethod === "x402") { + console.log( + "Skipping sending payment receipt to credentials provider for x402." + ); + return; + } + + const credentialsProviderUrl = getCredentialsProviderUrl(paymentMandate); + if (!credentialsProviderUrl) { + console.warn( + "Could not resolve credentials provider URL; skipping receipt delivery." + ); + return; + } + + const client = await A2AClient.fromCardUrl(credentialsProviderUrl); + + const message: MessageSendParams = { + message: { + messageId: uuidv4(), + role: "user", + contextId, + parts: [ + { + kind: "text", + text: "Here is the payment receipt. No action is required.", + }, + { kind: "data", data: { [PAYMENT_RECEIPT_DATA_KEY]: paymentReceipt } }, + { kind: "data", data: { debug_mode: debugMode } }, + ], + kind: "message", + }, + }; + + await client.sendMessage(message); +} + +async function raiseChallenge( + eventBus: ExecutionEventBus, + taskId: string, + contextId: string +): Promise { + const challengeData = { + type: "otp", + display_text: + "The payment method issuer sent a verification code to the phone " + + "number on file, please enter it below. It will be shared with the " + + "issuer so they can authorize the transaction." + + "(Demo only hint: the code is 123)", + }; + + const statusUpdate: TaskStatusUpdateEvent = { + kind: "status-update", + taskId, + contextId, + status: { + state: "input-required", + message: { + kind: "message", + role: "agent", + messageId: uuidv4(), + parts: [ + { + kind: "text", + text: "Please provide the challenge response to complete the payment.", + }, + { kind: "data", data: { challenge: challengeData } }, + ], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: true, + }; + + eventBus.publish(statusUpdate); +} + +async function completePayment( + paymentMandate: PaymentMandate, + eventBus: ExecutionEventBus, + taskId: string, + contextId: string, + debugMode: boolean = false +): Promise { + const paymentMethod = process.env.PAYMENT_METHOD || "CARD"; + + // Request payment credentials from credentials provider + await requestPaymentCredential( + paymentMandate, + contextId, + debugMode, + paymentMethod + ); + + // Create payment receipt + const paymentReceipt = createPaymentReceipt(paymentMandate); + + // Send receipt to credentials provider + await sendPaymentReceiptToCredentialsProvider( + paymentReceipt, + paymentMandate, + contextId, + debugMode + ); + + // Publish receipt as artifact with canonical key + const receiptArtifact: TaskArtifactUpdateEvent = { + kind: "artifact-update", + taskId, + contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { kind: "data", data: { [PAYMENT_RECEIPT_DATA_KEY]: paymentReceipt } }, + ], + }, + }; + eventBus.publish(receiptArtifact); + + const successUpdate: TaskStatusUpdateEvent = { + kind: "status-update", + taskId, + contextId, + status: { + state: "completed", + message: { + kind: "message", + role: "agent", + messageId: uuidv4(), + parts: [{ kind: "text", text: "{'status': 'success'}" }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: true, + }; + + eventBus.publish(successUpdate); +} + +/** + * ADK Tool: Initiate Payment + * + * Handles payment processing with OTP challenge flow. + */ +export const initiatePayment = new FunctionTool({ + name: "initiatePayment", + description: + "Initiates a payment for a given payment mandate. Handles OTP challenge flow.", + parameters: z.object({ + _trigger: z.boolean().optional().describe("Tool trigger"), + }), + execute: async (input, context) => { + if (!context) throw new Error("Missing execution context"); + const { dataParts, eventBus, currentTask } = getA2AContextFromTool(context); + const taskId = currentTask?.id || uuidv4(); + const contextId = currentTask?.contextId || uuidv4(); + + let paymentMandate: PaymentMandate; + try { + paymentMandate = parseCanonicalObject( + PAYMENT_MANDATE_DATA_KEY, + dataParts, + paymentMandateSchema + ); + } catch { + return { + error: + "PaymentMandate not found in request data. Report this error to the caller.", + }; + } + + const challengeResponse = findDataPart("challenge_response", dataParts) as + | string + | null; + const debugMode = + (findDataPart("debug_mode", dataParts) as boolean | null) || false; + + // Initial request - raise challenge + if (!currentTask) { + await raiseChallenge(eventBus, taskId, contextId); + return { status: "input-required", message: "Challenge raised" }; + } + + // Handle challenge response + if (currentTask.status.state === "input-required") { + if (!challengeResponse) { + return { + error: + "Challenge response is required but was not provided. Report this error to the caller.", + }; + } + + if (!challengeResponseIsValid(challengeResponse)) { + const statusUpdate: TaskStatusUpdateEvent = { + kind: "status-update", + taskId, + contextId, + status: { + state: "input-required", + message: { + kind: "message", + role: "agent", + messageId: uuidv4(), + parts: [{ kind: "text", text: "Challenge response incorrect." }], + taskId, + contextId, + }, + timestamp: new Date().toISOString(), + }, + final: false, + }; + eventBus.publish(statusUpdate); + return { status: "input-required", message: "Invalid challenge" }; + } + + // Valid challenge response - complete payment + await completePayment( + paymentMandate, + eventBus, + taskId, + contextId, + debugMode + ); + return { status: "completed", message: "Payment completed" }; + } + + return { status: "unknown", message: "Unexpected task state" }; + }, +}); diff --git a/code/samples/typescript/src/roles/merchant-payment-processor-mcp/server.ts b/code/samples/typescript/src/roles/merchant-payment-processor-mcp/server.ts new file mode 100644 index 00000000..11a14da0 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-payment-processor-mcp/server.ts @@ -0,0 +1,89 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Merchant Payment Processor (PSP) MCP Server. + * + * Exposes one MCP tool consumed by the shopping agent v2 over stdio: + * initiate_payment + * + * Settles the payment and signs a real ES256 payment receipt with the PSP key + * (the same receipt the PSP trigger server produces). Token-store lookup is + * still simplified. Tool contract mirrors the v0.2 Python server. + */ + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { randomUUID } from 'node:crypto'; +import { z } from 'zod'; +import { signJwtEs256, loadOrCreateKeyPair } from '../../common/sdjwt/index.js'; + +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; + +const server = new McpServer({ + name: 'merchant-payment-processor-mcp', + version: '0.2.0', +}); + +server.registerTool( + 'initiate_payment', + { + description: + 'Initiate and settle a payment for a previously issued payment token, bound to ' + + 'the checkout-JWT and open-checkout hashes, returning a (stubbed) signed PSP receipt.', + inputSchema: { + payment_token: z.string(), + checkout_jwt_hash: z.string(), + open_checkout_hash: z.string(), + }, + }, + async ({ payment_token, checkout_jwt_hash, open_checkout_hash }) => { + if (!payment_token || !checkout_jwt_hash || !open_checkout_hash) { + const error = { + error: 'missing_fields', + message: + 'payment_token, checkout_jwt_hash, and open_checkout_hash are required', + }; + return { + content: [{ type: 'text', text: JSON.stringify(error) }], + structuredContent: error, + isError: true, + }; + } + // Settle and sign a real ES256 payment receipt with the PSP key. + const psp = await loadOrCreateKeyPair(TEMP_DB, 'psp'); + const receipt = await signJwtEs256( + { + iss: 'merchant-payment-processor', + receipt_id: randomUUID(), + iat: Math.floor(Date.now() / 1000), + checkout_jwt_hash, + open_checkout_hash, + payment_token, + status: 'settled', + }, + psp.privateKey, + ); + const result = { + status: 'settled', + payment_receipt: receipt, + checkout_jwt_hash, + open_checkout_hash, + amount: 1500, + currency: 'USD', + timestamp: Math.floor(Date.now() / 1000), + }; + return { + content: [{ type: 'text', text: JSON.stringify(result) }], + structuredContent: result, + }; + }, +); + +const transport = new StdioServerTransport(); +await server.connect(transport); diff --git a/code/samples/typescript/src/roles/merchant-payment-processor-mcp/trigger-server.ts b/code/samples/typescript/src/roles/merchant-payment-processor-mcp/trigger-server.ts new file mode 100644 index 00000000..5f5887a1 --- /dev/null +++ b/code/samples/typescript/src/roles/merchant-payment-processor-mcp/trigger-server.ts @@ -0,0 +1,55 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * HTTP server for initiating payment processing. Runs on port 8083. + * Mirrors the Python `merchant_payment_processor_mcp/trigger_server.py`. + */ + +import express, { type Request, type Response } from 'express'; +import { randomUUID } from 'node:crypto'; +import { signJwtEs256, loadOrCreateKeyPair } from '../../common/sdjwt/index.js'; + +const PORT = Number(process.env.MERCHANT_PAYMENT_PROCESSOR_TRIGGER_PORT ?? 8083); +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; + +const app = express(); +app.use(express.json({ limit: '1mb' })); + +app.post('/initiate-payment', async (req: Request, res: Response) => { + const { payment_token, checkout_jwt_hash, open_checkout_hash } = req.body ?? {}; + for (const [field, value] of [ + ['payment_token', payment_token], + ['checkout_jwt_hash', checkout_jwt_hash], + ['open_checkout_hash', open_checkout_hash], + ] as const) { + if (!value) return res.status(400).json({ error: `${field} required` }); + } + // Settle and sign a real ES256 payment receipt with the PSP key. The + // credentials-provider verifies this against the PSP public key. + const psp = await loadOrCreateKeyPair(TEMP_DB, 'psp'); + const paymentReceipt = await signJwtEs256( + { + iss: 'merchant-payment-processor', + receipt_id: randomUUID(), + iat: Math.floor(Date.now() / 1000), + checkout_jwt_hash, + open_checkout_hash, + payment_token, + status: 'settled', + }, + psp.privateKey, + ); + res.json({ status: 'settled', payment_receipt: paymentReceipt, timestamp: Math.floor(Date.now() / 1000) }); +}); + +app.listen(PORT, '127.0.0.1', () => { + console.log( + `Merchant payment processor trigger server: http://localhost:${PORT}/initiate-payment`, + ); +}); diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/agent.ts b/code/samples/typescript/src/roles/shopping-agent-v2/agent.ts new file mode 100644 index 00000000..7ecfae24 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/agent.ts @@ -0,0 +1,178 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Shopping Agent v2 — Human-Not-Present. + * + * Mirrors the Python `shopping_agent_v2` sub-agent hierarchy: + * consent_agent (root) -> monitoring_agent -> purchase_agent (leaf). + * + * - consent_agent: drop/budget dialogue + open-mandate signing, then transfers + * to monitoring. + * - monitoring_agent: watches price/availability, transfers to purchase when the + * open-mandate constraints are satisfied and the item is available. + * - purchase_agent: runs the autonomous purchase pipeline (assemble cart -> + * create checkout -> closed-mandate presentations -> issue payment credential + * -> complete checkout -> verify receipts). + * + * Each agent owns its OWN set of MCPToolset instances (separate stdio + * connections) per ADK best practice — sharing a single toolset across agents + * causes stdio connection conflicts (see google/adk-python#712). Each MCP + * toolset launches the corresponding `*-mcp/server.ts` as a stdio subprocess. + */ + +import { LlmAgent, MCPToolset } from '@google/adk'; +import type { BaseTool } from '@google/adk'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { + assembleAndSignMandatesTool, + checkConstraintsAgainstMandateTool, + createMandateFulfillmentTool, + verifyCheckoutReceiptTool, + resetTempDbTool, +} from './mandate-tools.js'; +import { CONSENT_INSTRUCTION } from './prompts/consent.js'; +import { MONITORING_INSTRUCTION } from './prompts/monitoring.js'; +import { PURCHASE_INSTRUCTION } from './prompts/purchase.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROLES_DIR = path.resolve(__dirname, '..'); + +const MERCHANT_SERVER = path.join(ROLES_DIR, 'merchant-agent-mcp/server.ts'); +const CREDENTIAL_SERVER = path.join(ROLES_DIR, 'credentials-provider-mcp/server.ts'); +const PSP_SERVER = path.join(ROLES_DIR, 'merchant-payment-processor-mcp/server.ts'); + +const MCP_ENV = { + ...process.env, + LOGS_DIR: process.env.LOGS_DIR ?? path.resolve(ROLES_DIR, '../../.logs'), + TEMP_DB_DIR: process.env.TEMP_DB_DIR ?? path.resolve(ROLES_DIR, '../../.temp-db'), +} as Record; + +/** + * Build a fresh MCPToolset that launches an `*-mcp/server.ts` over stdio. + * + * A new instance is created per call (and per agent) on purpose: sharing one + * toolset across agents reuses the same stdio session and conflicts. + * + * @param serverEntry Absolute path to the MCP server entrypoint. + * @param toolFilter Optional allowlist of tool names or a predicate. + * @returns A configured MCPToolset. + */ +function makeMcpToolset( + serverEntry: string, + toolFilter?: string[] | ((tool: BaseTool) => boolean), +): MCPToolset { + return new MCPToolset( + { + type: 'StdioConnectionParams', + serverParams: { + command: 'npx', + args: ['tsx', serverEntry], + env: MCP_ENV, + }, + timeout: 60_000, + }, + toolFilter, + ); +} + +const MODEL = process.env.AGENT_MODEL ?? 'gemini-2.5-flash'; + +/** + * Reformat any MCP/mandate tool error into a structured artifact and escalate + * so the LLM reliably stops and emits exactly {type:'error', error, message}. + * + * Returning a replacement object becomes the tool result the model sees, and + * setting `context.actions.escalate` halts further sub-agent processing. + */ +const errorEscalationCallback = ({ + tool, + response, + context, +}: { + tool: BaseTool; + args: Record; + response: Record; + context: { actions: { escalate?: boolean } }; +}): Record | undefined => { + if (response && typeof response === 'object' && 'error' in response) { + const error = (response as { error: unknown }).error; + const message = 'message' in response ? (response as { message: unknown }).message : String(response); + context.actions.escalate = true; + const errorJson = JSON.stringify({ type: 'error', error, message }); + return { + error, + message, + action_required: + `STOP all processing for tool "${tool.name}". Emit EXACTLY this JSON ` + + `as your complete response, nothing else: ${errorJson}`, + }; + } + return undefined; +}; + +export const purchaseAgent = new LlmAgent({ + name: 'purchase_agent', + model: MODEL, + description: + 'Executes the autonomous purchase flow once price and availability satisfy ' + + 'the open mandates: assemble_cart, create_checkout, closed mandates, ' + + 'issue_payment_credential, complete_checkout, and receipt verification.', + instruction: PURCHASE_INSTRUCTION, + outputKey: 'purchase_result', + tools: [ + checkConstraintsAgainstMandateTool, + createMandateFulfillmentTool, + verifyCheckoutReceiptTool, + makeMcpToolset(MERCHANT_SERVER), + makeMcpToolset(CREDENTIAL_SERVER), + // The purchase agent must NOT settle directly via the PSP; filter out + // initiate_payment (mirrors the Python tool_filter lambda). + makeMcpToolset(PSP_SERVER, (tool) => tool.name !== 'initiate_payment'), + ], + afterToolCallback: errorEscalationCallback, +}); + +export const monitoringAgent = new LlmAgent({ + name: 'monitoring_agent', + model: MODEL, + description: + 'Holds the open mandates and monitors item price and availability via ' + + 'check_product. Transfers to purchase_agent when the price is within the ' + + 'mandate and the merchant reports the item as available.', + instruction: MONITORING_INSTRUCTION, + outputKey: 'monitoring_result', + tools: [checkConstraintsAgainstMandateTool, makeMcpToolset(MERCHANT_SERVER)], + subAgents: [purchaseAgent], + afterToolCallback: errorEscalationCallback, +}); + +export const consentAgent = new LlmAgent({ + name: 'consent_agent', + model: MODEL, + description: + 'Handles drop/budget dialogue, item selection, and open-mandate signing. ' + + 'Transfers to monitoring_agent after the mandates are approved or on ' + + '"Check price now".', + instruction: CONSENT_INSTRUCTION, + outputKey: 'consent_result', + tools: [ + resetTempDbTool, + assembleAndSignMandatesTool, + checkConstraintsAgainstMandateTool, + makeMcpToolset(MERCHANT_SERVER), + ], + subAgents: [monitoringAgent], + afterToolCallback: errorEscalationCallback, +}); + +export const shoppingAgentV2 = consentAgent; + +export { shoppingAgentV2 as rootAgent }; diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/mandate-tools.ts b/code/samples/typescript/src/roles/shopping-agent-v2/mandate-tools.ts new file mode 100644 index 00000000..1fce4a34 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/mandate-tools.ts @@ -0,0 +1,347 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Mandate helper tools for shopping-agent-v2, backed by the Verifiable Intent + * library (src/common/vi -> @verifiable-intent/core). This replicates the + * official Python reference flow (verifiable_intent/python/examples) sliced + * along the AP2 roles this agent owns: the User (Layer 2) and the Agent + * (Layer 3 split fulfillment). + * + * - assembleAndSignMandates: issues the Layer 1 issuer credential (binding the + * user key) and the Layer 2 autonomous user mandate (binding the agent key, + * carrying the amount-range / merchant / line-item constraints). + * - checkConstraintsAgainstMandate: reads the L2 constraints and checks an + * observed price/merchant against them. + * - createMandateFulfillment: the agent builds the split Layer 3 credentials + * (L3a payment for the network, L3b checkout for the merchant) plus the + * per-recipient L2 presentations, all bound to the checkout hash. + * - verifyCheckoutReceipt: verifies a merchant-signed checkout receipt (JWS). + * - resetTempDb: clears mandate files for a fresh run, preserving keys. + * + * Chain artifacts (serialized SD-JWTs) are persisted under TEMP_DB and referenced + * by id so the merchant / credentials-provider MCP servers can verify them. + */ + +import { FunctionTool } from '@google/adk'; +import fs from 'node:fs'; +import path from 'node:path'; +import { randomUUID } from 'node:crypto'; +import { z } from 'zod'; + +import { + ACCEPTABLE_ITEMS, + MERCHANTS, + PAYMENT_INSTRUMENT, + type Dict, + type ViKeyPair, + b64urlDecode, + checkConstraints, + createAgentFulfillment, + createUserMandateAutonomous, + decodeSdJwt, + es256Verify, + hashAscii, + hashDisclosure, + issueIssuerCredential, + jwtDecodeParts, + loadOrCreateViKey, + loadViPublicJwk, + resolveDisclosures, + StrictnessMode, +} from '../../common/vi/index.js'; + +const TEMP_DB = process.env.TEMP_DB_DIR ?? '.temp-db'; + +/** Singleton chain artifacts for the active run. */ +const L1_FILE = 'l1.sdjwt'; +const L2_FILE = 'l2.sdjwt'; +/** Mandate file prefixes cleared by resetTempDb (never the *_key.jwk.json keys). */ +const MANDATE_PREFIXES = ['l1', 'l2', 'chk_', 'pay_']; + +function tempPath(filename: string): string { + return path.join(TEMP_DB, filename); +} + +function persist(filename: string, content: string): void { + fs.mkdirSync(TEMP_DB, { recursive: true }); + fs.writeFileSync(tempPath(filename), content); +} + +function readIfExists(filename: string): string | null { + try { + return fs.readFileSync(tempPath(filename), 'utf-8'); + } catch { + return null; + } +} + +/** Verify a plain ES256 compact JWS and return its payload. */ +async function verifyJws(token: string, publicJwk: ViKeyPair['publicKey']): Promise { + const parts = token.split('.'); + if (parts.length !== 3) { + throw new Error('malformed JWT: expected three dot-separated segments'); + } + const ok = await es256Verify(`${parts[0]}.${parts[1]}`, b64urlDecode(parts[2]), publicJwk); + if (!ok) { + throw new Error('invalid JWT signature'); + } + return jwtDecodeParts(token).payload as Dict; +} + +/** Build the merchant allowlist (Dict[]) the L2 mandate carries. */ +function resolveMerchants(allowedNames?: string[]): Dict[] { + if (!allowedNames || allowedNames.length === 0) { + return MERCHANTS; + } + return allowedNames.map((name) => { + const known = MERCHANTS.find((m) => String(m.name).toLowerCase() === name.toLowerCase()); + return known ?? { name, website: `https://${name.toLowerCase().replace(/[^a-z0-9]+/g, '-')}.example` }; + }); +} + +export const assembleAndSignMandatesTool = new FunctionTool({ + name: 'assembleAndSignMandates', + description: + 'Issues the Layer 1 issuer credential (binding the user key) and signs the Layer 2 autonomous ' + + 'user mandate as a real SD-JWT delegation chain (ES256). The mandate delegates to the agent key ' + + '(cnf.jwk) and carries the amount-range, allowed-merchant and acceptable-item constraints. ' + + 'Persists L1 + L2 under TEMP_DB and returns their ids and hashes.', + parameters: z.object({ + natural_language_description: z.string(), + constraint_price_cap: z.number(), + expires_at_iso: z.string(), + allowed_merchants: z.array(z.string()).optional(), + item_id: z.string().optional(), + item_title: z.string().optional(), + }), + execute: async (args) => { + const issuer = await loadOrCreateViKey(TEMP_DB, 'issuer'); + const user = await loadOrCreateViKey(TEMP_DB, 'user'); + const agent = await loadOrCreateViKey(TEMP_DB, 'agent'); + + const now = Math.floor(Date.now() / 1000); + const expiresAt = Math.floor(new Date(args.expires_at_iso).getTime() / 1000); + const ttlSeconds = Number.isFinite(expiresAt) && expiresAt > now ? expiresAt - now : 3600; + const amountMaxCents = Math.round(args.constraint_price_cap * 100); + + const merchants = resolveMerchants(args.allowed_merchants); + const acceptableItems: Dict[] = args.item_id + ? [{ id: args.item_id, title: args.item_title ?? args.natural_language_description }] + : ACCEPTABLE_ITEMS; + + // L1 — the Issuer (credentials provider) binds the user's key. + const l1 = await issueIssuerCredential({ + userPublicJwk: user.publicKey, + issuer, + sub: 'shopping-agent-user', + iat: now, + panLastFour: '1234', + }); + + // L2 — the User delegates to the agent with constraints (autonomous mode). + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: args.natural_language_description, + iat: now, + ttlSeconds, + merchants, + acceptableItems, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 0, + amountMax: amountMaxCents, + }); + + persist(L1_FILE, l1); + persist(L2_FILE, l2); + + return { + credential_id: 'l1', + mandate_id: 'l2', + l1_hash: hashAscii(l1), + l2_hash: hashAscii(l2), + amount_cap_cents: amountMaxCents, + currency: 'USD', + }; + }, +}); + +export const checkConstraintsAgainstMandateTool = new FunctionTool({ + name: 'checkConstraintsAgainstMandate', + description: + "Reads the signed Layer 2 user mandate and checks an observed price (and optional merchant) " + + "against its amount-range and allowed-payee constraints. Returns meets_constraints + violations.", + parameters: z.object({ + current_price: z.number(), + available: z.boolean(), + merchant: z.string().optional(), + currency: z.string().optional(), + }), + execute: async ({ current_price, available, merchant, currency }) => { + if (!available) { + return { meets_constraints: false, satisfies: false, violations: ['item_not_available'] }; + } + const l2Serialized = readIfExists(L2_FILE); + if (!l2Serialized) { + return { error: 'mandate_not_found', message: 'l2 mandate not signed yet' }; + } + + let l2; + try { + l2 = decodeSdJwt(l2Serialized); + } catch (e) { + return { error: 'mandate_decode_failed', message: String(e) }; + } + const claims = resolveDisclosures(l2); + const delegates = (claims.delegate_payload as Dict[] | undefined) ?? []; + let paymentConstraints: Dict[] = []; + for (const d of delegates) { + if (d && typeof d === 'object' && d.vct === 'mandate.payment.open.1') { + paymentConstraints = (d.constraints as Dict[] | undefined) ?? []; + break; + } + } + + // Build a candidate fulfillment from the observed offer and resolve allowed_payees. + const fulfillment: Dict = { + payment_amount: { currency: currency ?? 'USD', amount: Math.round(current_price * 100) }, + }; + const discByHash = new Map(); + for (let i = 0; i < l2.disclosures.length; i++) { + discByHash.set(hashDisclosure(l2.disclosures[i]), l2.disclosureValues[i]); + } + for (const c of paymentConstraints) { + if (c.type === 'mandate.payment.allowed_payees') { + const resolved: unknown[] = []; + for (const ref of (c.allowed as unknown[] | undefined) ?? []) { + const refHash = ref && typeof ref === 'object' ? ((ref as Dict)['...'] as string) : ''; + if (refHash && discByHash.has(refHash)) { + const dv = discByHash.get(refHash)!; + resolved.push(dv[dv.length - 1]); + } + } + fulfillment.allowed_merchants = merchant ? [{ name: merchant }] : resolved; + } + } + + const result = checkConstraints(paymentConstraints, fulfillment, { mode: StrictnessMode.PERMISSIVE }); + return { + meets_constraints: result.satisfied, + satisfies: result.satisfied, // alias for older prompt wording + violations: result.violations, + price: current_price, + available, + }; + }, +}); + +export const createMandateFulfillmentTool = new FunctionTool({ + name: 'createMandateFulfillment', + description: + 'Builds the split Layer 3 agent fulfillment from the signed L2 mandate: L3a (payment, for the ' + + 'network) and L3b (checkout, for the merchant), each bound to the checkout hash, plus the ' + + 'per-recipient L2 presentations (selective disclosure). Persists them and returns their chain ids.', + parameters: z.object({ + checkout_jwt: z.string(), + checkout_jwt_hash: z.string(), + item_id: z.string(), + amount_cents: z.number(), + payee_name: z.string().optional(), + currency: z.string().optional(), + }), + execute: async ({ checkout_jwt, checkout_jwt_hash, item_id, amount_cents, payee_name, currency }) => { + const l2Serialized = readIfExists(L2_FILE); + if (!l2Serialized) { + return { error: 'mandate_not_found', message: 'l2 mandate not signed yet' }; + } + const agent = await loadOrCreateViKey(TEMP_DB, 'agent'); + + const payee = + (payee_name && MERCHANTS.find((m) => String(m.name).toLowerCase() === payee_name.toLowerCase())) || + MERCHANTS[0]; + + let fulfillment; + try { + fulfillment = await createAgentFulfillment({ + l2Serialized, + agent, + checkoutJwt: checkout_jwt, + checkoutHash: checkout_jwt_hash, + payee, + itemId: item_id, + amount: amount_cents, + currency: currency ?? 'USD', + paymentInstrument: PAYMENT_INSTRUMENT, + }); + } catch (e) { + return { error: 'fulfillment_failed', message: String(e) }; + } + + const checkoutId = `chk_${randomUUID()}`; + const paymentId = `pay_${randomUUID()}`; + persist(`${checkoutId}.sdjwt`, fulfillment.l3CheckoutSerialized); + persist(`${checkoutId}.l2.sdjwt`, fulfillment.l2CheckoutSerialized); + persist(`${paymentId}.sdjwt`, fulfillment.l3PaymentSerialized); + persist(`${paymentId}.l2.sdjwt`, fulfillment.l2PaymentSerialized); + + return { + checkout_mandate_chain_id: checkoutId, + payment_mandate_chain_id: paymentId, + }; + }, +}); + +export const verifyCheckoutReceiptTool = new FunctionTool({ + name: 'verifyCheckoutReceipt', + description: + 'Verifies a merchant-signed checkout receipt (compact ES256 JWS) against the merchant public key. ' + + 'Returns verified + the receipt id and issuer.', + parameters: z.object({ + checkout_receipt: z.string(), + }), + execute: async ({ checkout_receipt }) => { + const merchantPub = loadViPublicJwk(TEMP_DB, 'merchant'); + if (!merchantPub) { + return { verified: false, error: 'merchant_key_unavailable', message: 'merchant key not found in TEMP_DB' }; + } + try { + const payload = await verifyJws(checkout_receipt, merchantPub); + return { verified: true, receipt_id: payload.receipt_id, issuer: payload.iss }; + } catch (e) { + return { verified: false, error: 'receipt_verification_failed', message: String(e) }; + } + }, +}); + +export const resetTempDbTool = new FunctionTool({ + name: 'resetTempDb', + description: + 'Clears persisted mandate / chain files (L1, L2, and the L3 fulfillment chains) for a fresh run. ' + + 'Preserves signing keys and merchant inventory.', + parameters: z.object({ + confirm: z.boolean().optional(), + }), + execute: async () => { + let removed = 0; + try { + for (const f of fs.readdirSync(TEMP_DB)) { + if (f.endsWith('_key.jwk.json')) continue; + if (MANDATE_PREFIXES.some((p) => f.startsWith(p)) && (f.endsWith('.sdjwt') || f === L1_FILE || f === L2_FILE)) { + fs.rmSync(tempPath(f), { force: true }); + removed += 1; + } + } + } catch { + return { status: 'ok', removed: 0, message: 'no temp-db to clear' }; + } + return { status: 'ok', removed, message: `removed ${removed} mandate files` }; + }, +}); diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/prompts/consent.ts b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/consent.ts new file mode 100644 index 00000000..0ce1a106 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/consent.ts @@ -0,0 +1,52 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Instruction for the Consent Agent (root of the shopping-agent-v2 hierarchy). + * Mirrors the intent of the Python `prompts/consent_agent.md`. + */ + +export const CONSENT_INSTRUCTION = `You are the Consent Agent, the entry point of a Human-Not-Present shopping agent. You ONLY handle delegated purchase tasks for limited / timed drops: the user authorizes you (via signed open mandates) to buy on their behalf when conditions are met. + +Classify every request first: +- MATCH: the user wants you to proxy-buy an item when a drop goes live or it falls within a budget; OR a short confirmation ("yes" / "ok" / "$200 is fine") right after you asked permission and proposed a price; OR a follow-up like "Check price now". +- NO_MATCH: anything else. Return ONLY this JSON and nothing else: + {"type":"error","error":"unsupported_task","message":"This agent only handles delegated purchase tasks for limited drops."} +A bare "yes"/"ok"/"sure" immediately after you proposed a price is always MATCH — never NO_MATCH. + +Your job: lead the user through preview -> budget confirmation -> mandate signing -> handoff to monitoring. + +Conversation memory: scan all prior messages and build active_product (full natural description: brand, item, size) and active_budget (dollars). If you proposed a price and the user only said "yes", that price is active_budget. Never re-ask for product or budget if already in the thread. + +Workflow: +A) First contact: when the user shows purchase intent for a limited/timed item, write short prose (offer to buy for them, a plausible drop time, typical price, ask their budget / permission). Do NOT call any tool yet. If the user asks to start over / reset, call resetTempDb first. +B) After the user agrees on a budget (or says "yes" to your price): + 1. FIRST call search_inventory(product_description = active_product, constraint_price_cap = active_budget) + to resolve the merchant catalog item_id for this product. Keep matches[0].item_id. + 2. THEN call assembleAndSignMandates with: + - natural_language_description = active_product + - constraint_price_cap = active_budget + - expires_at_iso = an ISO 8601 timestamp ~1 hour from now + - allowed_merchants = optional list if the user named specific merchants + - item_id = the item_id from step 1 (REQUIRED: the signed mandate's acceptable_items must bind + the exact item the monitoring/purchase agents will later check_product / assemble_cart, or the + Layer 3 fulfillment cannot match it) + This issues the Layer 1 issuer credential and signs the Layer 2 autonomous user mandate (a real + SD-JWT delegation chain) with the amount-range, merchant and acceptable-item constraints, and + returns the credential_id / mandate_id and hashes, which persist for the downstream agents. +C) Once the mandates are signed (or the user says "Check price now" and mandates already exist), transfer to the monitoring_agent so it can watch price and availability. Briefly tell the user you are now monitoring the drop. + +Tools: +- resetTempDb: clear prior mandate files when starting a fresh purchase. +- assembleAndSignMandates: sign the open mandates after the user approves the budget. +- checkConstraintsAgainstMandate: optional sanity check of price/availability against the open mandate (returns meets_constraints + violations). +- search_inventory / check_product (merchant MCP): you may use check_product to confirm an item's current price/availability, but never fabricate a price into a mandate. + +Mandate integrity: never invent prices. Transparency: explain what happened and what comes next. + +Error handling: if any tool returns an object with an "error" key, STOP and emit EXACTLY {"type":"error","error":"","message":""} as your entire response.`; diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/prompts/monitoring.ts b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/monitoring.ts new file mode 100644 index 00000000..e3fe1db3 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/monitoring.ts @@ -0,0 +1,26 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Instruction for the Monitoring Agent (sub-agent of the Consent Agent). + * Mirrors the intent of the Python `prompts/monitoring_agent.md`. + */ + +export const MONITORING_INSTRUCTION = `You are the Monitoring Agent. The open mandates have already been signed by the consent agent and persist in state. Your goal is to check the item's current price and availability against the open mandate constraints, and hand off to the purchase flow as soon as the constraints are met. + +On each turn: +1. Call check_product (merchant MCP) with the item_id and the constraint_price_cap from the open mandate to read the current price and availability. The item is usually unavailable (stock 0) until the drop fires. +2. Call checkConstraintsAgainstMandate with the current_price, available, and (if known) the merchant — exactly as returned by check_product. It reads the signed L2 user mandate and returns { meets_constraints: boolean, violations: string[] }. +3. If meets_constraints is true AND available is true, transfer to the purchase_agent immediately so it can execute the autonomous purchase. Do not run the purchase steps yourself. +4. Otherwise (constraints not met or item not yet available), tell the user the current price/availability and that you will keep watching, then stop and wait for the next check. + +Principles: +- Mandate integrity: use only data returned by the tools; the open mandates are the source of truth for the constraints. +- Transparency: clearly report the current price, availability, and status. + +Error handling: if any tool returns an object with an "error" key, STOP and emit EXACTLY {"type":"error","error":"","message":""} as your entire response.`; diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/prompts/purchase.ts b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/purchase.ts new file mode 100644 index 00000000..b7378889 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/prompts/purchase.ts @@ -0,0 +1,34 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Instruction for the Purchase Agent (leaf sub-agent of the Monitoring Agent). + * Mirrors the intent of the Python `prompts/purchase_agent.md`. + */ + +export const PURCHASE_INSTRUCTION = `You are the Purchase Agent. The price/availability constraints are already satisfied. Execute the full purchase pipeline autonomously — never ask the user for confirmation. + +Run these steps strictly in order. Pass each tool exactly the values returned by the previous steps; do not fabricate any value. +1. check_product (merchant MCP) — confirm the item is still available at the expected price. Keep item_id and price. +2. checkConstraintsAgainstMandate(current_price, available) — re-verify against the signed L2 mandate; only continue if meets_constraints is true and available is true. +3. assemble_cart(item_id, qty) — build the cart. Keep the returned cart_id and total (minor units / cents). +4. create_checkout(cart_id) — get the ES256-signed merchant checkout JWT. Keep checkout_jwt and checkout_jwt_hash. +5. createMandateFulfillment(checkout_jwt, checkout_jwt_hash, item_id, amount_cents = the cart total from step 3) — the agent builds the split Layer 3 fulfillment (L3a payment for the network + L3b checkout for the merchant) bound to checkout_jwt_hash. Keep checkout_mandate_chain_id and payment_mandate_chain_id. +6. issue_payment_credential(payment_mandate_chain_id) — the credentials provider verifies the payment-side chain (L1 -> L2 -> L3a) and enforces the mandate constraints before issuing the token. Keep payment_token. +7. complete_checkout(checkout_jwt, payment_credential, checkout_mandate_chain_id) — the merchant verifies the checkout-side chain (L1 -> L2 -> L3b), then finalizes the order. It returns TWO distinct receipts: \`payment_receipt\` (signed by the PSP) and \`checkout_receipt\` (signed by the merchant). Keep both. +8. Verify the two receipts with the matching verifier — do NOT swap them: + a. verify_payment_receipt(payment_receipt) — pass the \`payment_receipt\` field from step 7 (the PSP-signed one). It is verified against the PSP key. + b. verifyCheckoutReceipt(checkout_receipt) — pass the \`checkout_receipt\` field from step 7 (the merchant-signed one). +Then emit a brief purchase_complete summary (order id + both receipts) as JSON. + +Principles: +- Mandate integrity: use only data from tools; the chain ids returned by createMandateFulfillment route the checkout chain to the merchant and the payment chain to the credentials provider. +- Idempotency: never repeat a tool that already succeeded. +- You do NOT have access to the PSP's initiate_payment tool; settlement is driven by issue_payment_credential + complete_checkout. + +Error handling: if ANY tool returns an object with an "error" key, immediately STOP and emit EXACTLY {"type":"error","error":"","message":""} as your entire response. Do not attempt to continue or recover.`; diff --git a/code/samples/typescript/src/roles/shopping-agent-v2/server.ts b/code/samples/typescript/src/roles/shopping-agent-v2/server.ts new file mode 100644 index 00000000..03613d08 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent-v2/server.ts @@ -0,0 +1,83 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Shopping Agent v2 A2A server (Human-Not-Present). + * Mirrors the Python `shopping_agent_v2/run_server.py`. + */ + +import { Runner } from '@google/adk'; +import type { AgentCard } from '@a2a-js/sdk'; + +import { shoppingAgentV2 } from './agent.js'; +import { sessionService } from '../../common/config/session.js'; +import { BaseAgentExecutor } from '../../common/server/base-executor.js'; +import { bootstrapServer } from '../../common/server/bootstrap.js'; + +const PORT = Number(process.env.AGENT_PORT ?? 8080); + +const runner = new Runner({ + appName: 'ap2-shopping-v2', + agent: shoppingAgentV2, + sessionService, +}); + +const agentExecutor = new BaseAgentExecutor({ + agentName: 'shopping_agent', + appName: 'ap2-shopping-v2', + runner, + maxLlmCalls: 20, + workingMessage: 'The shopping agent is monitoring your drop...', +}); + +const agentCard: AgentCard = { + name: 'Shopping Agent v2', + description: + 'Human-Not-Present shopping agent. Holds signed open mandates and ' + + 'autonomously executes purchases when price/availability constraints are met.', + url: `http://localhost:${PORT}/a2a/shopping_agent`, + provider: { organization: 'AP2 TypeScript samples', url: 'https://github.com/google-agentic-commerce/AP2' }, + skills: [ + { + id: 'monitor_and_purchase', + name: 'Monitor and Purchase', + description: + 'Captures user intent, signs open mandates, monitors the merchant for ' + + 'price/availability changes, and executes purchase autonomously.', + parameters: { + type: 'object', + properties: { + user_intent: { + type: 'string', + description: 'Natural-language description of what to buy and the constraints.', + }, + }, + required: ['user_intent'], + }, + tags: ['shopping', 'hnp', 'autonomous'], + } as AgentCard['skills'][number], + ], + capabilities: { + streaming: true, + pushNotifications: false, + stateTransitionHistory: true, + extensions: [ + { + uri: 'https://github.com/google-agentic-commerce/ap2/v1', + description: 'Supports the Agent Payments Protocol.', + required: true, + }, + ], + }, + defaultInputModes: ['application/json'], + defaultOutputModes: ['application/json'], + protocolVersion: '0.3.0', + version: '0.2.0', +}; + +bootstrapServer({ agentCard, agentExecutor, port: PORT, label: 'Shopping Agent v2' }); diff --git a/code/samples/typescript/src/roles/shopping-agent/agent.ts b/code/samples/typescript/src/roles/shopping-agent/agent.ts new file mode 100644 index 00000000..e742fd55 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/agent.ts @@ -0,0 +1,101 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from '@google/adk'; +import { DEBUG_MODE_INSTRUCTIONS } from '../../common/constants/index.js'; + +import { + updateCart, + createPaymentMandate, + signMandatesOnUserDevice, + sendSignedPaymentMandateToCredentialsProvider, + initiatePayment, + initiatePaymentWithOtp, +} from './tools.js'; + +// Import sub_agents +import { shopperAgent } from './subagents/shopper/agent.js'; +import { shippingCollectorAgent } from './subagents/shipping-address-collector/agent.js'; +import { paymentCollectorAgent } from './subagents/payment-method-collector/agent.js'; + +/** + * Shopping Agent (ADK) + * + * Main orchestrator for the entire shopping and payment flow. + * Uses ADK sub_agents for Shopper, ShippingCollector, and PaymentCollector + * (matching Python's architecture where these share the same process and session state). + */ +export const shoppingAgent = new LlmAgent({ + name: 'root_agent', + model: 'gemini-2.5-flash', + description: 'A shopping agent responsible for helping users find and purchase products from merchants.', + instruction: `You are a shopping agent responsible for helping users find and purchase products from merchants. + +You have three subagents that you delegate to: +- shopper_agent: Helps users find and select products from merchants. +- shipping_address_collector_agent: Collects the user's shipping address. +- payment_method_collector_agent: Collects the user's payment method. + +When you delegate to a subagent, ADK handles the delegation automatically. Simply describe what you need done and the appropriate subagent will handle it. + +Follow these instructions, depending upon the scenario: + +Scenario 1: +The user asks to buy or shop for something. +1. Delegate to the shopper_agent to collect the products the user is interested in purchasing. The shopper_agent will return a message indicating if the chosen cart mandate is ready or not. +2. Once a success message is received, delegate to the shipping_address_collector_agent to collect the user's shipping address. +3. The shipping_address_collector_agent will return the user's shipping address. Display the shipping address to the user. +4. Once you have the shipping address, call the updateCart tool to update the cart. You will receive a new, signed CartMandate object. +5. Immediately after the updateCart tool returns successfully, delegate to the payment_method_collector_agent to collect the user's payment method. +6. The payment_method_collector_agent will return the user's payment method alias. +7. Send this message separately to the user: 'This is where you would be redirected to a trusted surface to confirm the purchase.' 'But this is a demo, so you can confirm your purchase here.' +8. Call the createPaymentMandate tool to create a payment mandate. +9. Present to the user the final cart contents including price, shipping, tax, total price, how long the cart is valid for (in a human-readable format) and how long it can be refunded (in a human-readable format). In a second block, show the shipping address. Format it all nicely. In a third block, show the user's payment method alias. Format it nicely. +10. Confirm with the user they want to purchase the selected item using the selected form of payment. +11. When the user confirms purchase call the following tools in order: + a. signMandatesOnUserDevice + b. sendSignedPaymentMandateToCredentialsProvider +12. Initiate the payment by calling the initiatePayment tool. +13. If prompted for an OTP, relay the OTP request to the user. Do not ask the user for anything other than the OTP request. Once you have a challenge response, display the display_text from it and then call the initiatePaymentWithOtp tool to retry the payment. Surface the result to the user. +14. If the response is a success or confirmation, create a block of text titled 'Payment Receipt'. Ensure its contents includes price, shipping, tax and total price. In a second block, show the shipping address. Format it all nicely. In a third block, show the user's payment method alias. Format it nicely and give it to the user. + +Scenario 2: +The user first wants you to describe all the data passed between you, tools, and other subagents before starting with their shopping prompt. +1. Listen to the user's request for describing the process you are following and the data passed between you, tools, and other subagents. Describe the process you are following. Share data and tools used. Anytime you reach out to other subagents, ask them to describe the data they are receiving and sending as well as the tools they are using. Be sure to include which subagent is currently speaking to the user. +2. Follow the instructions for Scenario 1 once the user confirms they want to start with their shopping prompt. + +Scenario 3: +The users ask you do to anything else. +1. Respond to the user with this message: "Hi, I'm your shopping assistant. How can I help you? For example, you can say 'I want to buy a pair of shoes'" + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [ + updateCart, + createPaymentMandate, + signMandatesOnUserDevice, + sendSignedPaymentMandateToCredentialsProvider, + initiatePayment, + initiatePaymentWithOtp, + ], + subAgents: [ + shopperAgent, + shippingCollectorAgent, + paymentCollectorAgent, + ], +}); + +// ADK devtools discovers the root agent via a `rootAgent` named export. +export { shoppingAgent as rootAgent }; diff --git a/code/samples/typescript/src/roles/shopping-agent/server.ts b/code/samples/typescript/src/roles/shopping-agent/server.ts new file mode 100644 index 00000000..259e94ab --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/server.ts @@ -0,0 +1,127 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { v4 as uuidv4 } from 'uuid'; +import { Runner } from '@google/adk'; +import type { + AgentCard, + Message, + TaskArtifactUpdateEvent, + TaskStatusUpdateEvent, +} from '@a2a-js/sdk'; + +import { shoppingAgent } from './agent.js'; +import { sessionService } from '../../common/config/session.js'; +import { BaseAgentExecutor } from '../../common/server/base-executor.js'; +import { bootstrapServer } from '../../common/server/bootstrap.js'; + +const runner = new Runner({ + appName: 'ap2-shopping-agent', + agent: shoppingAgent, + sessionService, +}); + +const agentExecutor = new BaseAgentExecutor({ + agentName: 'root_agent', + appName: 'ap2-shopping-agent', + runner, + workingMessage: 'Processing your shopping request...', + postprocessResult({ + responseText, + toolWasCalled, + session, + eventBus, + taskId, + contextId, + }) { + // Check if payment receipt was generated (indicates completion) + const paymentReceipt = session.state.paymentReceipt; + const isTaskComplete = !!paymentReceipt; + + const fallbackText = (!responseText && !toolWasCalled && !isTaskComplete) + ? 'I encountered an issue processing your request. Could you please try again?' + : undefined; + + const finalResponseText = fallbackText || responseText || 'Processing...'; + + // Publish artifact if payment receipt was generated + if (isTaskComplete && paymentReceipt) { + eventBus.publish({ + kind: 'artifact-update', + taskId, + contextId, + artifact: { + artifactId: uuidv4(), + parts: [ + { kind: 'data', data: { paymentReceipt } }, + ], + }, + } satisfies TaskArtifactUpdateEvent); + } + + const agentMessage: Message = { + kind: 'message', + role: 'agent', + messageId: uuidv4(), + parts: [{ kind: 'text', text: finalResponseText }], + taskId, + contextId, + }; + + return { + kind: 'status-update', + taskId, + contextId, + status: { + state: isTaskComplete ? 'completed' : 'input-required', + message: agentMessage, + timestamp: new Date().toISOString(), + }, + final: true, + } satisfies TaskStatusUpdateEvent; + }, +}); + +const agentCard: AgentCard = { + name: 'ShoppingAgent', + description: 'A shopping agent that helps users find and purchase products from merchants.', + url: 'http://localhost:8001', + provider: { organization: 'AP2 Demo', url: 'https://github.com/google-agentic-commerce/ap2' }, + skills: [ + { + id: 'shop_for_products', + name: 'Shop for Products', + description: 'Help users find and purchase products from merchants.', + tags: ['shopping', 'payments', 'e-commerce'], + }, + ], + capabilities: { + streaming: true, + pushNotifications: false, + stateTransitionHistory: true, + }, + defaultInputModes: ['text/plain'], + defaultOutputModes: ['application/json'], + protocolVersion: '0.3.0', + version: '1.0.0', +}; + +bootstrapServer({ + agentCard, + agentExecutor, + port: 8001, + label: 'ShoppingAgent', +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/agent.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/agent.ts new file mode 100644 index 00000000..732ebf0b --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/agent.ts @@ -0,0 +1,66 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from "@google/adk"; +import { DEBUG_MODE_INSTRUCTIONS } from "../../../../common/constants/index.js"; +import { getPaymentMethods, getPaymentCredentialToken } from "./tools.js"; + +/** + * Payment Method Collector Agent (ADK) + * + * Collects payment method information from users. + */ +export const paymentCollectorAgent = new LlmAgent({ + name: "payment_method_collector_agent", + model: "gemini-2.5-flash", + description: + "A subagent that collects payment method information from users.", + instruction: `You are an agent responsible for obtaining the user's payment method for a purchase. + +When asked to complete a task, follow these instructions: +1. Ensure a CartMandate object was provided to you. +2. Present a clear and organized summary of the cart to the user. The + summary should be divided into two main sections: + a. Order Summary: + Merchant: The name of the merchant. + Item: Display the item_name clearly. + Price Breakdown: + Shipping: The shipping cost from the shippingOptions. + Tax: The tax amount, if available. + Total: The final total price from the total field in the + payment_request. + Format all amounts with commas and the currency symbol. + Expires: Convert the cart_expiry into a human-readable format + (e.g., "in 2 hours," "by tomorrow at 5 PM"). Convert the time to the + user's timezone. + Refund Period: Convert the refund_period into a human-readable format + (e.g., "30 days," "14 days"). + b. Show the full shipping address collected earlier in a well-formatted + manner. + Ensure the entire presentation is well-formatted and easy to read. +3. Call the get_payment_methods tool to get eligible + payment_method_aliases with the method_data from the CartMandate's + payment_request. Present the payment_method_aliases to the user in + a numbered list. +4. Ask the user to choose which of their forms of payment they would + like to use for the payment. Remember that payment_method_alias. +5. Call the get_payment_credential_token tool to get the payment + credential token with the user_email and payment_method_alias. +6. Once you have the token, respond to the user confirming their selected payment method alias. Do NOT call any transfer tool. Just state the chosen payment method alias clearly. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [getPaymentMethods, getPaymentCredentialToken], +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/tools.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/tools.ts new file mode 100644 index 00000000..42579a85 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/payment-method-collector/tools.ts @@ -0,0 +1,227 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from "@google/adk"; +import { z } from "zod"; +import { v4 as uuidv4 } from "uuid"; +import { A2AClient } from "@a2a-js/sdk/client"; +import type { + Artifact, + DataPart, + MessageSendParams, + SendMessageSuccessResponse, + Task, +} from "@a2a-js/sdk"; +import type { CartMandate } from "../../../../common/types/cart-mandate.js"; +import { AGENT_URLS } from "../../../index.js"; +import { A2A_DATA_KEYS } from "../../../../common/constants/index.js"; + +const PAYMENT_METHOD_DATA_DATA_KEY = A2A_DATA_KEYS.PAYMENT_METHOD_DATA; + +// Helper function +function getFirstDataPart( + artifacts: Artifact[] +): Record | null { + for (const artifact of artifacts) { + for (const part of artifact.parts) { + if (part.kind === "data") { + return (part as DataPart).data as Record; + } + } + } + return null; +} + +/** + * Tool 1: Get Payment Methods + * + * Gets the user's payment methods from the credentials provider. + */ +export const getPaymentMethods = new FunctionTool({ + name: "get_payment_methods", + description: "Gets the user's payment methods from the credentials provider.", + parameters: z.object({ + userEmail: z.string().describe("The user's email address"), + }), + execute: async (input, context) => { + if (!context) throw new Error("Missing execution context"); + const { userEmail } = input; + + // Read cartMandate from shared session state (set by parent shopping agent) + const cartMandate = context.state.get("cartMandate") as + | CartMandate + | undefined; + if (!cartMandate) { + throw new Error("No cart mandate found in session state."); + } + + const shoppingContextId = context.state.get("shoppingContextId") as + | string + | undefined; + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: "user", + contextId: shoppingContextId || uuidv4(), + parts: [ + { + kind: "text", + text: "Get the user's payment methods.", + }, + { + kind: "data", + data: { + user_email: userEmail, + }, + }, + ], + kind: "message", + }, + }; + + // Add payment method data from cart mandate + for (const methodData of cartMandate.contents.paymentRequest.methodData) { + sendParams.message.parts.push({ + kind: "data", + data: { + [PAYMENT_METHOD_DATA_DATA_KEY]: methodData, + }, + }); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.CREDENTIALS_PROVIDER); + const response = await client.sendMessage(sendParams); + + if ("error" in response) { + console.error( + "Error in credentials provider agent:", + response.error.message + ); + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + + if (result.kind !== "task") { + throw new Error("Expected task response"); + } + + const task = result as Task; + const paymentMethods = getFirstDataPart(task.artifacts ?? []); + return paymentMethods; + }, +}); + +/** + * Tool 2: Get Payment Credential Token + * + * Gets a payment credential token from the credentials provider. + */ +export const getPaymentCredentialToken = new FunctionTool({ + name: "get_payment_credential_token", + description: "Gets a payment credential token from the credentials provider.", + parameters: z.object({ + userEmail: z.string().describe("The user's email address"), + paymentMethodAlias: z + .string() + .describe("The payment method alias chosen by the user"), + }), + execute: async (input, context) => { + if (!context) throw new Error("Missing execution context"); + const { userEmail, paymentMethodAlias } = input; + + const shoppingContextId = context.state.get("shoppingContextId") as + | string + | undefined; + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: "user", + contextId: shoppingContextId || uuidv4(), + parts: [ + { + kind: "text", + text: "Get a payment credential token for the user's payment method.", + }, + { + kind: "data", + data: { + user_email: userEmail, + payment_method_alias: paymentMethodAlias, + }, + }, + ], + kind: "message", + }, + }; + + const client = await A2AClient.fromCardUrl(AGENT_URLS.CREDENTIALS_PROVIDER); + const response = await client.sendMessage(sendParams); + + if ("error" in response) { + console.error("Error:", response.error.message); + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + + if (result.kind !== "task") { + throw new Error("Expected task response"); + } + + const task = result as Task; + + // Extract data parts from artifacts + const extractedDataParts = (task.artifacts ?? []).map((artifact) => { + const parts: unknown[] = []; + for (const part of artifact.parts) { + if (part.kind === "data") { + parts.push((part as DataPart).data); + } + } + return parts; + }); + + // Get first data part + const getFirstItem = ( + dataParts: unknown[][] + ): Record | null => { + for (const dataPart of dataParts) { + for (const item of dataPart) { + return item as Record; + } + } + return null; + }; + + const data = getFirstItem(extractedDataParts); + const token = data?.token as string | undefined; + + const credentialsProviderUrl = AGENT_URLS.CREDENTIALS_PROVIDER; + context.state.set("paymentCredentialToken", token); + context.state.set("paymentCredentialTokenObject", { + value: token, + url: credentialsProviderUrl, + }); + + return { + status: "success", + token, + }; + }, +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/agent.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/agent.ts new file mode 100644 index 00000000..316b5db7 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/agent.ts @@ -0,0 +1,73 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from '@google/adk'; +import { DEBUG_MODE_INSTRUCTIONS } from '../../../../common/constants/index.js'; +import { getShippingAddress, saveManualShippingAddress } from './tools.js'; + +/** + * Shipping Address Collector Agent (ADK) + * + * Collects shipping address information from users, either from digital wallet + * or manual entry. + */ +export const shippingCollectorAgent = new LlmAgent({ + name: 'shipping_address_collector_agent', + model: 'gemini-2.5-flash', + description: 'A subagent that collects shipping address information from users.', + instruction: `You are an agent responsible for obtaining the user's shipping address. + +When asked to complete a task, follow these instructions: +1. Ask the user "Would you prefer to use a digital wallet to access +your credentials for this purchase, or would you like to enter +your shipping address manually?" +2. Proceed depending on the following scenarios: + +Scenario 1: +The user wants to use their digital wallet (e.g. PayPal or Google Wallet). +Do not add any additional digital wallet options to the list. +Instructions: +1. Collect the info that what is the digital wallet the user would + like to use for this transaction. +2. Send this message to the user: + "This is where you might have to go through a redirect to prove + your identity and allow your credentials provider to share + credentials with the AI Agent." +3. Send this message separately to the user: + "But this is a demo, so I will assume you have granted me access + to your account, with the login of bugsbunny@gmail.com. + + Is that ok?" +4. Collect the user's agreement to access their account. +5. Once the user agrees, delegate to the 'get_shipping_address' tool + to collect the user's shipping address. Give bugsbunny@gmail.com + as the user's email address. +6. The get_shipping_address tool will return the user's shipping + address. Transfer back to the root_agent with the shipping address. + +Scenario 2: +Condition: The user wants to enter their shipping address manually. +Instructions: +1. Collect the user's shipping address. Ensure you have collected all + of the necessary parts of a US address (recipient name, street address, + city, state, zip code, country, and optionally phone number). +2. Once you have all the address details, call the 'save_manual_shipping_address' + tool to save the address. +3. Transfer back to the root_agent with the shipping address. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [getShippingAddress, saveManualShippingAddress], +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/tools.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/tools.ts new file mode 100644 index 00000000..ad37a7a6 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/shipping-address-collector/tools.ts @@ -0,0 +1,134 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from '@google/adk'; +import { z } from 'zod'; +import { v4 as uuidv4 } from 'uuid'; +import { A2AClient } from '@a2a-js/sdk/client'; +import type { + Artifact, + MessageSendParams, + SendMessageSuccessResponse, + Task, +} from '@a2a-js/sdk'; +import { AGENT_URLS } from '../../../index.js'; + +// Helper function +function parseShippingAddress(artifacts: Artifact[]): unknown[] { + return artifacts.map((artifact) => { + const dataPart = artifact.parts.find((part) => part.kind === 'data'); + return dataPart ? (dataPart as { kind: 'data'; data: unknown }).data : undefined; + }); +} + +/** + * Tool: Get Shipping Address + * + * Gets the user's shipping address from the credentials provider. + */ +export const getShippingAddress = new FunctionTool({ + name: 'get_shipping_address', + description: 'Gets the user\'s shipping address from the credentials provider.', + parameters: z.object({ + userEmail: z.string().describe('The user\'s email address'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const shoppingContextId = context.state.get('shoppingContextId') as string | undefined; + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + contextId: shoppingContextId || uuidv4(), + parts: [ + { + kind: 'text', + text: 'Get the user\'s shipping address.', + }, + { + kind: 'data', + data: { + user_email: input.userEmail, + }, + }, + ], + kind: 'message', + }, + }; + + const client = await A2AClient.fromCardUrl(AGENT_URLS.CREDENTIALS_PROVIDER); + const response = await client.sendMessage(sendParams); + + if ('error' in response) { + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === 'task') { + const task = result as Task; + if (task.status.state !== 'completed') { + throw new Error( + `Failed to get shipping address: ${task.status.state}` + ); + } + + const shippingAddress = parseShippingAddress(task.artifacts ?? [])?.[0]; + + // Store in session state + context.state.set('shippingAddress', shippingAddress); + context.state.set('userEmail', input.userEmail); + + return shippingAddress; + } + + throw new Error('Unexpected response type from credentials provider'); + }, +}); + +/** + * Tool: Save Manual Shipping Address + * + * Saves a manually entered shipping address to session state so that + * postprocessResult can publish it as an artifact. + */ +export const saveManualShippingAddress = new FunctionTool({ + name: 'save_manual_shipping_address', + description: 'Saves a manually entered shipping address. Call this after the user provides their full address.', + parameters: z.object({ + recipient: z.string().describe('Full name of the recipient'), + address_line: z.array(z.string()).describe('Street address lines'), + city: z.string().describe('City'), + region: z.string().describe('State or region'), + postal_code: z.string().describe('Zip or postal code'), + country: z.string().describe('Country code (e.g. US)'), + phone_number: z.string().optional().describe('Phone number'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const shippingAddress = { + recipient: input.recipient, + address_line: input.address_line, + city: input.city, + region: input.region, + postal_code: input.postal_code, + country: input.country, + phone_number: input.phone_number || '', + }; + context.state.set('shippingAddress', shippingAddress); + return shippingAddress; + }, +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/agent.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/agent.ts new file mode 100644 index 00000000..9277f0f5 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/agent.ts @@ -0,0 +1,96 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { LlmAgent } from '@google/adk'; +import { DEBUG_MODE_INSTRUCTIONS } from '../../../../common/constants/index.js'; +import { createIntentMandate, findProducts, updateChosenCartMandate } from './tools.js'; + +/** + * Shopper Agent (ADK) + * + * Helps users shop for products by collecting their intent, finding products, + * and managing cart selection. + */ +export const shopperAgent = new LlmAgent({ + name: 'shopper_agent', + model: 'gemini-2.5-flash', + description: 'An agent responsible for helping the user shop for products.', + instruction: `You are an agent responsible for helping the user shop for products. + +When asked to complete a task, follow these instructions: +1. Find out what the user is interested in purchasing. +2. Ask clarifying questions one at a time to understand their needs fully. + The shopping agent delegates responsibility for helping the user shop for + products to this subagent. Help the user craft an IntentMandate that will + be used to find relevant products for their purchase. Reason about the + user's instructions and the information needed for the IntentMandate. The + IntentMandate will be shown back to the user for confirmation so it's okay + to make reasonable assumptions about the IntentMandate criteria initially. + For example, inquire about: + - A detailed description of the item. + - Any preferred merchants or specific SKUs. + - Whether the item needs to be refundable. +3. After you have gathered what you believe is sufficient information, + use the 'create_intent_mandate' tool with the collected information + (user's description, and any other details they provided). Do not include + any user guidance on price in the intent mandate. Use user's preference for + the price as a filter when recommending products for the user to select + from. +4. Present the IntentMandate to the user in a clear, well-formatted summary. + Start with the statement: "Please confirm the following details for your + purchase. Note that this information will be shared with the merchant." + And then has a row space and a breakdown of the details: + Item Description: The natural_language_description. Never include any + user guidance on price in the intent mandate. + User Confirmation Required: A human-readable version of + user_cart_confirmation_required (e.g., 'Yes', 'No'). + Merchants: A comma-separated list of merchants, or + 'Any' if not specified. + SKUs: A comma-separated list of SKUs, or + 'Any' if not specified. + Refundable: 'Yes' or 'No'. + Expires: Convert the intent_expiry timestamp into a + human-readable relative time (e.g., "in 1 hour", "in 2 days"). + + After the breakdown, leave a blank line and end with: "Shall I proceed?" +5. Once the user confirms, use the 'find_products' tool. It will + return a list of CartMandate objects. +6. For each CartMandate object in the list, create a visually distinct entry + that includes the following details from the object: + Item: Display the item_name clearly and in bold. + Price: Present the total_price with the currency. Format the price + with commas, and use the currency symbol (e.g., "$1,234.56"). + Expires: Convert the cart_expiry into a human-readable format + (e.g., "in 2 hours," "by tomorrow at 5 PM"). + Refund Period: Convert the refund_period into a human-readable format + (e.g., "30 days," "14 days"). + Present these details to the user in a clear way. If there are more than + one CartMandate object, present them as a numbered list. + At the bottom, present Sold by: Show the merchant_name + associate the first Transaction. + Ensure the cart you think matches the user's intent the most is presented + at the top of the list. Add a 2-3 line summary of why you recommended the + first option to the user. +7. Ask the user which item they would like to purchase. +8. After they choose, call the update_chosen_cart_mandate tool with the + cart ID (contents.id from the CartMandate). +9. Monitor the tool's output. If the cart ID is not found, you must inform + the user and prompt them to try again. If the selection is successful, + signal a successful update and hand off the process to the root_agent. + +${DEBUG_MODE_INSTRUCTIONS}`, + tools: [createIntentMandate, findProducts, updateChosenCartMandate], +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/tools.ts b/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/tools.ts new file mode 100644 index 00000000..987e7354 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/subagents/shopper/tools.ts @@ -0,0 +1,239 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from '@google/adk'; +import { z } from 'zod'; +import { v4 as uuidv4 } from 'uuid'; +import { A2AClient } from '@a2a-js/sdk/client'; +import type { + Artifact, + DataPart, + MessageSendParams, + SendMessageSuccessResponse, + Task, +} from '@a2a-js/sdk'; +import { AGENT_URLS } from '../../../index.js'; +import { DATA_KEYS } from '../../../../common/constants/index.js'; + +const INTENT_MANDATE_DATA_KEY = DATA_KEYS.INTENT_MANDATE; +const CART_MANDATE_DATA_KEY = DATA_KEYS.CART_MANDATE; + +// Helper functions +function parseCartMandates(artifacts: Artifact[]): Record[] { + const cartMandates: Record[] = []; + + for (const artifact of artifacts) { + for (const part of artifact.parts) { + if (part.kind === 'data') { + const dataPart = part as DataPart; + const data = dataPart.data as Record; + if (CART_MANDATE_DATA_KEY in data) { + cartMandates.push( + data[CART_MANDATE_DATA_KEY] as Record + ); + } + } + } + } + + return cartMandates; +} + +function collectRiskData(): { riskData: string } { + return { + riskData: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...fake_risk_data', + }; +} + +/** + * Tool 1: Create Intent Mandate + * + * Creates an IntentMandate with the user's shopping intent. + */ +export const createIntentMandate = new FunctionTool({ + name: 'create_intent_mandate', + description: 'Create an IntentMandate with the user\'s shopping intent and preferences.', + parameters: z.object({ + naturalLanguageDescription: z + .string() + .describe('The description of the user\'s intent.'), + userCartConfirmationRequired: z + .boolean() + .describe('If the user must confirm the cart.'), + merchants: z.array(z.string()).describe('A list of allowed merchants.'), + skus: z.array(z.string()).describe('A list of allowed SKUs.'), + requiresRefundability: z + .boolean() + .describe('If the items must be refundable.'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { + naturalLanguageDescription, + userCartConfirmationRequired, + merchants, + skus, + requiresRefundability, + } = input; + + const intentMandate = { + naturalLanguageDescription, + userCartConfirmationRequired, + merchants, + skus, + requiresRefundability, + intentExpiry: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(), + }; + + // Store in session state + context.state.set('intentMandate', intentMandate); + + return intentMandate; + }, +}); + +/** + * Tool 2: Find Products + * + * Calls the merchant agent to find products matching the user's intent. + */ +export const findProducts = new FunctionTool({ + name: 'find_products', + description: 'Calls the merchant agent to find products matching the user\'s intent.', + parameters: z.object({ + debugMode: z + .boolean() + .optional() + .default(false) + .describe('If the agent is in debug mode.'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const intentMandate = context.state.get('intentMandate'); + if (!intentMandate) { + throw new Error('No IntentMandate found in session state.'); + } + + const riskData = collectRiskData(); + if (!riskData) { + throw new Error('No risk data available.'); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.MERCHANT); + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + parts: [ + { + kind: 'text', + text: 'Find products that match the user\'s IntentMandate.', + }, + { + kind: 'data', + data: { + [INTENT_MANDATE_DATA_KEY]: intentMandate, + }, + }, + { + kind: 'data', + data: { + risk_data: riskData.riskData, + }, + }, + { + kind: 'data', + data: { + debug_mode: input.debugMode, + }, + }, + { + kind: 'data', + data: { + shopping_agent_id: 'trusted_shopping_agent', + }, + }, + ], + kind: 'message', + }, + }; + + const response = await client.sendMessage(sendParams); + + if ('error' in response) { + console.error('Error:', response.error.message); + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === 'task') { + const task = result as Task; + if (task.status.state !== 'completed') { + throw new Error(`Failed to find products: ${JSON.stringify(task.status)}`); + } + + const cartMandates = parseCartMandates(task.artifacts ?? []); + + // Store in session state + context.state.set('shoppingContextId', task.contextId); + context.state.set('cartMandates', cartMandates); + context.state.set('riskData', riskData.riskData); + + return { cartMandates }; + } + + throw new Error('Unexpected response type from merchant agent'); + }, +}); + +/** + * Tool 3: Update Chosen Cart Mandate + * + * Updates the chosen CartMandate in the session state. + */ +export const updateChosenCartMandate = new FunctionTool({ + name: 'update_chosen_cart_mandate', + description: 'Updates the chosen CartMandate in the session state. Use the cart ID (contents.id) from the CartMandate the user selected.', + parameters: z.object({ + cartId: z + .string() + .describe('The cart ID (contents.id) of the CartMandate the user selected.'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { cartId } = input; + const cartMandates = context.state.get('cartMandates') as Record[] || []; + + if (cartMandates.length === 0) { + return 'No products available. Please search for products first.'; + } + + const selectedCart = cartMandates.find((cm) => { + const contents = cm.contents as Record | undefined; + return contents?.id === cartId; + }); + + if (!selectedCart) { + return `Cart with ID "${cartId}" not found. Please choose a valid cart ID.`; + } + + // Store in session state + context.state.set('chosenCartId', cartId); + context.state.set('cartMandate', selectedCart); + + return `Cart ${cartId} selected successfully.`; + }, +}); diff --git a/code/samples/typescript/src/roles/shopping-agent/tools.ts b/code/samples/typescript/src/roles/shopping-agent/tools.ts new file mode 100644 index 00000000..83e95dc9 --- /dev/null +++ b/code/samples/typescript/src/roles/shopping-agent/tools.ts @@ -0,0 +1,487 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FunctionTool } from '@google/adk'; +import { z } from 'zod'; +import { v4 as uuidv4 } from 'uuid'; +import { A2AClient } from '@a2a-js/sdk/client'; +import type { + DataPart, + MessageSendParams, + SendMessageSuccessResponse, + Task, +} from '@a2a-js/sdk'; +import type { CartMandate } from '../../common/types/cart-mandate.js'; +import type { PaymentMandate } from '../../common/types/payment-mandate.js'; +import { DATA_KEYS } from '../../common/constants/index.js'; +import { AGENT_URLS } from '../index.js'; + +/** Wrap a promise with a timeout to prevent hanging on unresponsive agents. */ +function withTimeout(promise: Promise, ms: number, label: string): Promise { + return Promise.race([ + promise, + new Promise((_, reject) => + setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms) + ), + ]); +} + +const A2A_TIMEOUT_MS = 30_000; + +/** + * Tool 1: Update Cart + * + * Updates the cart with shipping address and gets signed CartMandate from merchant. + */ +export const updateCart = new FunctionTool({ + name: 'updateCart', + description: 'Updates the cart with the shipping address. Call this after receiving the shipping address from the shipping_address_collector subagent.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const cartMandate = context.state.get('cartMandate') as CartMandate | undefined; + const shippingAddress = context.state.get('shippingAddress'); + const shoppingContextId = context.state.get('shoppingContextId') as string | undefined; + const riskData = context.state.get('riskData') as string | undefined; + + if (!cartMandate) { + throw new Error('No cart mandate found. Ensure the shopper subagent has provided a cart.'); + } + + if (!shippingAddress) { + throw new Error('No shipping address found. Ensure the shipping address collector has provided an address.'); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.MERCHANT); + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + contextId: shoppingContextId, + parts: [ + { kind: 'text', text: 'Update the cart with the shipping address.' }, + { kind: 'data', data: { cart_id: cartMandate.contents.id } }, + { kind: 'data', data: { shipping_address: shippingAddress } }, + { kind: 'data', data: { shopping_agent_id: 'trusted_shopping_agent' } }, + ], + kind: 'message', + }, + }; + + if (riskData) { + sendParams.message.parts.push({ kind: 'data', data: { risk_data: riskData } }); + } + + const response = await withTimeout(client.sendMessage(sendParams), A2A_TIMEOUT_MS, 'updateCart'); + + if ('error' in response) { + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === 'task') { + const task = result as Task; + if (task.status.state !== 'completed') { + throw new Error(`Failed to update cart: ${task.status.state}`); + } + + // Extract updated cart mandate + for (const artifact of task.artifacts ?? []) { + for (const part of artifact.parts) { + if (part.kind === 'data') { + const data = (part as DataPart).data as Record; + if (data[DATA_KEYS.CART_MANDATE]) { + context.state.set('cartMandate', data[DATA_KEYS.CART_MANDATE]); + return { status: 'success', message: 'Cart updated with shipping address' }; + } + } + } + } + + throw new Error('No updated cart mandate received from merchant'); + } + + throw new Error('Unexpected response type from merchant'); + }, +}); + +/** + * Tool 2: Create Payment Mandate + * + * Creates a PaymentMandate from the cart and payment method. + */ +export const createPaymentMandate = new FunctionTool({ + name: 'createPaymentMandate', + description: 'Creates a payment mandate from the cart mandate and payment credential token.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const cartMandate = context.state.get('cartMandate') as CartMandate | undefined; + const paymentCredentialToken = context.state.get('paymentCredentialToken') as string | undefined; + + if (!cartMandate) { + throw new Error('No cart mandate found'); + } + + if (!paymentCredentialToken) { + throw new Error('No payment credential token found'); + } + + const shippingAddress = context.state.get('shippingAddress') as Record | undefined; + const userEmail = context.state.get('userEmail') as string | undefined; + const paymentRequest = cartMandate.contents.paymentRequest; + + const paymentMandate: PaymentMandate = { + paymentMandateContents: { + paymentMandateId: uuidv4(), + paymentDetailsId: paymentRequest.details.id, + paymentDetailsTotal: paymentRequest.details.total, + paymentResponse: { + requestId: paymentRequest.details.id, + methodName: paymentRequest.methodData[0].supportedMethods, + details: { token: paymentCredentialToken }, + shippingAddress: shippingAddress || undefined, + payerEmail: userEmail || undefined, + }, + merchantAgent: cartMandate.contents.merchantName, + timestamp: new Date().toISOString(), + }, + }; + + context.state.set('paymentMandate', paymentMandate); + + return { status: 'success', paymentMandate }; + }, +}); + +/** + * Tool 3: Sign Mandates on User Device + * + * Simulates cryptographic signing on a trusted user device. + */ +export const signMandatesOnUserDevice = new FunctionTool({ + name: 'signMandatesOnUserDevice', + description: 'Signs the payment mandate on the user\'s trusted device (simulated for demo).', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const paymentMandate = context.state.get('paymentMandate') as PaymentMandate | undefined; + + if (!paymentMandate) { + throw new Error('No payment mandate found to sign'); + } + + // Simulate signing with hash-based user authorization (matching Python) + const cartMandateHash = `cart_hash_${Date.now()}`; + const paymentMandateHash = `payment_hash_${Date.now()}`; + const signedPaymentMandate: PaymentMandate = { + ...paymentMandate, + userAuthorization: `${cartMandateHash}_${paymentMandateHash}`, + }; + + context.state.set('signedPaymentMandate', signedPaymentMandate); + + return { status: 'success', message: 'Payment mandate signed on user device' }; + }, +}); + +/** + * Tool 4: Send Signed Payment Mandate to Credentials Provider + * + * Sends the signed payment mandate to the credentials provider for validation. + */ +export const sendSignedPaymentMandateToCredentialsProvider = new FunctionTool({ + name: 'sendSignedPaymentMandateToCredentialsProvider', + description: 'Sends the signed payment mandate to the credentials provider.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const signedPaymentMandate = context.state.get('signedPaymentMandate') as PaymentMandate | undefined; + const shoppingContextId = context.state.get('shoppingContextId') as string | undefined; + const riskData = context.state.get('riskData') as string | undefined; + + if (!signedPaymentMandate) { + throw new Error('No signed payment mandate found'); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.CREDENTIALS_PROVIDER); + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + contextId: shoppingContextId, + parts: [ + { kind: 'text', text: 'Store this signed payment mandate.' }, + { kind: 'data', data: { [DATA_KEYS.PAYMENT_MANDATE]: signedPaymentMandate } }, + ], + kind: 'message', + }, + }; + + if (riskData) { + sendParams.message.parts.push({ kind: 'data', data: { risk_data: riskData } }); + } + + const response = await withTimeout(client.sendMessage(sendParams), A2A_TIMEOUT_MS, 'sendSignedPaymentMandate'); + + if ('error' in response) { + throw new Error(response.error.message); + } + + const result = (response as SendMessageSuccessResponse).result; + if (result.kind === 'task') { + const task = result as Task; + if (task.status.state !== 'completed') { + throw new Error(`Failed to send signed mandate: ${task.status.state}`); + } + + return { status: 'success', message: 'Signed payment mandate sent to credentials provider' }; + } + + throw new Error('Unexpected response type from credentials provider'); + }, +}); + +/** + * Tool 5: Initiate Payment + * + * Initiates payment by sending the payment mandate to the merchant. + */ +export const initiatePayment = new FunctionTool({ + name: 'initiatePayment', + description: 'Initiates the payment by sending the payment mandate to the merchant.', + parameters: z.object({ + _trigger: z.boolean().optional().describe('Tool trigger'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const signedPaymentMandate = context.state.get('signedPaymentMandate') as PaymentMandate | undefined; + const shoppingContextId = context.state.get('shoppingContextId') as string | undefined; + const riskData = context.state.get('riskData') as string | undefined; + + if (!signedPaymentMandate) { + throw new Error('No signed payment mandate found'); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.MERCHANT); + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + contextId: shoppingContextId, + parts: [ + { kind: 'text', text: 'Initiate payment for this signed mandate.' }, + { kind: 'data', data: { [DATA_KEYS.PAYMENT_MANDATE]: signedPaymentMandate } }, + { kind: 'data', data: { shopping_agent_id: 'trusted_shopping_agent' } }, + ], + kind: 'message', + }, + }; + + if (riskData) { + sendParams.message.parts.push({ kind: 'data', data: { risk_data: riskData } }); + } + + const initiatePaymentTaskId = context.state.get('initiatePaymentTaskId') as string | undefined; + if (initiatePaymentTaskId) { + sendParams.message.taskId = initiatePaymentTaskId; + } + + const stream = client.sendMessageStream(sendParams); + let finalTask: Task | null = initiatePaymentTaskId + ? { + kind: 'task' as const, + id: initiatePaymentTaskId, + contextId: '', + status: { state: 'working' as const, timestamp: new Date().toISOString() }, + artifacts: [], + } + : null; + let challengeData: unknown = null; + + for await (const event of stream) { + if (event.kind === 'task') { + finalTask = event; + } else if (event.kind === 'artifact-update') { + if (finalTask) { + if (!finalTask.artifacts) finalTask.artifacts = []; + finalTask.artifacts.push(event.artifact); + } + } else if (event.kind === 'status-update') { + if (finalTask) { + finalTask.status = event.status; + if (event.taskId) finalTask.id = event.taskId; + if (event.contextId) finalTask.contextId = event.contextId; + } + if (event.status.state === 'input-required') { + const message = event.status.message; + if (message?.parts) { + for (const part of message.parts) { + if (part.kind === 'data') { + const data = (part as DataPart).data as Record; + if (data.challenge) { + challengeData = data.challenge; + } + } + } + } + } + } + } + + if (!finalTask) { + throw new Error('No final task received from merchant'); + } + + context.state.set('initiatePaymentTaskId', finalTask.id); + + if (finalTask.status.state === 'input-required' && challengeData) { + return { + status: 'input-required', + challenge: challengeData, + message: 'OTP challenge required', + }; + } + + if (finalTask.status.state === 'completed') { + // Extract payment receipt using canonical key + for (const artifact of finalTask.artifacts ?? []) { + for (const part of artifact.parts) { + if (part.kind === 'data') { + const data = (part as DataPart).data as Record; + if (data[DATA_KEYS.PAYMENT_RECEIPT]) { + context.state.set('paymentReceipt', data[DATA_KEYS.PAYMENT_RECEIPT]); + return { status: 'success', receipt: data[DATA_KEYS.PAYMENT_RECEIPT] }; + } + } + } + } + return { status: 'success', message: 'Payment completed' }; + } + + throw new Error(`Payment failed: ${finalTask.status.state}`); + }, +}); + +/** + * Tool 6: Initiate Payment with OTP + * + * Retries payment with OTP challenge response. + */ +export const initiatePaymentWithOtp = new FunctionTool({ + name: 'initiatePaymentWithOtp', + description: 'Retries the payment with the OTP challenge response.', + parameters: z.object({ + challengeResponse: z.string().describe('The OTP or challenge response from the user'), + }), + execute: async (input, context) => { + if (!context) throw new Error('Missing execution context'); + const { challengeResponse } = input; + const signedPaymentMandate = context.state.get('signedPaymentMandate') as PaymentMandate | undefined; + const shoppingContextId = context.state.get('shoppingContextId') as string | undefined; + const riskData = context.state.get('riskData') as string | undefined; + const initiatePaymentTaskId = context.state.get('initiatePaymentTaskId') as string | undefined; + + if (!signedPaymentMandate) { + throw new Error('No signed payment mandate found'); + } + + if (!initiatePaymentTaskId) { + throw new Error('No existing payment task found'); + } + + const client = await A2AClient.fromCardUrl(AGENT_URLS.MERCHANT); + + const sendParams: MessageSendParams = { + message: { + messageId: uuidv4(), + role: 'user', + taskId: initiatePaymentTaskId, + contextId: shoppingContextId, + parts: [ + { kind: 'text', text: 'Retry payment with OTP response.' }, + { kind: 'data', data: { [DATA_KEYS.PAYMENT_MANDATE]: signedPaymentMandate } }, + { kind: 'data', data: { challenge_response: challengeResponse } }, + { kind: 'data', data: { shopping_agent_id: 'trusted_shopping_agent' } }, + ], + kind: 'message', + }, + }; + + if (riskData) { + sendParams.message.parts.push({ kind: 'data', data: { risk_data: riskData } }); + } + + const stream = client.sendMessageStream(sendParams); + let finalTask: Task | null = { + kind: 'task' as const, + id: initiatePaymentTaskId, + contextId: shoppingContextId || '', + status: { state: 'working' as const, timestamp: new Date().toISOString() }, + artifacts: [], + }; + + for await (const event of stream) { + if (event.kind === 'task') { + finalTask = event; + } else if (event.kind === 'artifact-update') { + if (finalTask) { + if (!finalTask.artifacts) finalTask.artifacts = []; + finalTask.artifacts.push(event.artifact); + } + } else if (event.kind === 'status-update') { + if (finalTask) { + finalTask.status = event.status; + if (event.taskId) finalTask.id = event.taskId; + if (event.contextId) finalTask.contextId = event.contextId; + } + } + } + + if (!finalTask) { + throw new Error('No final task received from merchant'); + } + + if (finalTask.status.state === 'completed') { + // Extract payment receipt using canonical key + for (const artifact of finalTask.artifacts ?? []) { + for (const part of artifact.parts) { + if (part.kind === 'data') { + const data = (part as DataPart).data as Record; + if (data[DATA_KEYS.PAYMENT_RECEIPT]) { + context.state.set('paymentReceipt', data[DATA_KEYS.PAYMENT_RECEIPT]); + return { status: 'success', receipt: data[DATA_KEYS.PAYMENT_RECEIPT] }; + } + } + } + } + return { status: 'success', message: 'Payment completed' }; + } + + throw new Error(`Payment failed: ${finalTask.status.state}`); + }, +}); diff --git a/code/samples/typescript/src/web-agents/shopping-agent/agent.ts b/code/samples/typescript/src/web-agents/shopping-agent/agent.ts new file mode 100644 index 00000000..33f71bd2 --- /dev/null +++ b/code/samples/typescript/src/web-agents/shopping-agent/agent.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * ADK web entry: a dedicated agents directory so `adk web src/web-agents` + * lists the app under the folder name ("shopping-agent") instead of the + * generic "agent" you get when pointing adk web directly at an agent folder. + * Pointing adk web at src/roles is not viable — its heterogeneous siblings + * (the *-mcp stdio servers and shopping-agent-v2) collide in ADK's loader. + */ + +export { rootAgent, shoppingAgent } from '../../roles/shopping-agent/agent.js'; diff --git a/code/samples/typescript/test/e2e/connectivity.test.ts b/code/samples/typescript/test/e2e/connectivity.test.ts new file mode 100644 index 00000000..7be40b4c --- /dev/null +++ b/code/samples/typescript/test/e2e/connectivity.test.ts @@ -0,0 +1,51 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, it, expect } from 'vitest'; +import { A2AClient } from '@a2a-js/sdk/client'; +import { v4 as uuidv4 } from 'uuid'; + +const SHOPPING_AGENT_URL = 'http://localhost:8001/.well-known/agent-card.json'; + +describe('Shopping Agent connectivity', () => { + it('serves an agent card', async () => { + const response = await fetch(SHOPPING_AGENT_URL); + expect(response.ok).toBe(true); + const card = await response.json(); + expect(card.name).toBeTruthy(); + }); + + it('responds to a basic message via A2A', async () => { + const client = await A2AClient.fromCardUrl(SHOPPING_AGENT_URL); + + const stream = client.sendMessageStream({ + message: { + kind: 'message', + messageId: uuidv4(), + role: 'user', + contextId: uuidv4(), + parts: [{ kind: 'text', text: 'Hello, are you working?' }], + }, + }); + + const events: unknown[] = []; + for await (const event of stream) { + events.push(event); + if (events.length >= 5) break; + } + expect(events.length).toBeGreaterThan(0); + }, 15_000); +}); diff --git a/code/samples/typescript/test/e2e/payment-flow.test.ts b/code/samples/typescript/test/e2e/payment-flow.test.ts new file mode 100644 index 00000000..c5cd215b --- /dev/null +++ b/code/samples/typescript/test/e2e/payment-flow.test.ts @@ -0,0 +1,53 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * End-to-end smoke test for the AP2 payment flow: + * user request → cart → shipping → payment method → mandate → receipt. + * + * Assumes the four agents are already running locally (see scenario README). + */ + +import { describe, it, expect } from 'vitest'; +import { A2AClient } from '@a2a-js/sdk/client'; +import type { Task } from '@a2a-js/sdk'; +import { v4 as uuidv4 } from 'uuid'; + +const SHOPPING_AGENT_URL = 'http://localhost:8001/.well-known/agent-card.json'; + +describe('AP2 payment flow (e2e)', () => { + it('initiates a shopping flow and reaches a working, completed, or input-required state', async () => { + const client = await A2AClient.fromCardUrl(SHOPPING_AGENT_URL); + + const stream = client.sendMessageStream({ + message: { + kind: 'message', + messageId: uuidv4(), + role: 'user', + contextId: uuidv4(), + parts: [{ kind: 'text', text: 'I want to buy running shoes' }], + }, + }); + + let lastTask: Task | null = null; + for await (const event of stream) { + if (event.kind === 'task') lastTask = event; + } + + expect(lastTask).not.toBeNull(); + expect(['working', 'completed', 'input-required']).toContain( + lastTask!.status.state, + ); + }, 60_000); +}); diff --git a/code/samples/typescript/test/unit/credentials-token.test.ts b/code/samples/typescript/test/unit/credentials-token.test.ts new file mode 100644 index 00000000..8ae19e62 --- /dev/null +++ b/code/samples/typescript/test/unit/credentials-token.test.ts @@ -0,0 +1,68 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Phase 2: proves the credentials-provider payment token round-trips through + * SD-JWT (replacing the W3C VC token). createToken issues an ES256 SD-JWT + * credential; verifyToken cryptographically verifies it and reconstructs the + * payment method. Runs without any server. + */ + +import { describe, it, expect, beforeAll } from 'vitest'; +import { + initIssuerKey, + createToken, + updateToken, + verifyToken, +} from '../../src/roles/credentials-provider-agent/account-manager.js'; + +const EMAIL = 'bugsbunny@gmail.com'; +const ALIAS = 'American Express ending in 4444'; +const MANDATE_ID = 'pm_test_123'; + +describe('credentials-provider SD-JWT token (Phase 2)', () => { + beforeAll(async () => { + await initIssuerKey(); + }); + + it('issues an SD-JWT token (compact form, not JSON-LD VC)', async () => { + const token = await createToken(EMAIL, ALIAS); + // SD-JWT compact form is tilde-separated; a W3C VC would be a JSON object. + expect(token).toContain('~'); + expect(token.trimStart().startsWith('{')).toBe(false); + }); + + it('round-trips the payment method through createToken -> verifyToken', async () => { + const token = await createToken(EMAIL, ALIAS); + updateToken(token, MANDATE_ID); + + const pm = await verifyToken(token, MANDATE_ID); + expect(pm).not.toBeNull(); + expect(pm?.alias).toBe(ALIAS); + expect(pm?.type).toBe('CARD'); // restored from payment_method_type + // selectively-disclosable sensitive fields survive a full presentation + expect((pm as Record).token).toBe('1111000000000000'); + expect((pm as Record).cryptogram).toBe('fake_cryptogram_abc123'); + // credential metadata must NOT leak into the reconstructed payment method + expect((pm as Record).sub).toBeUndefined(); + expect((pm as Record).cnf).toBeUndefined(); + expect((pm as Record).payment_method_alias).toBeUndefined(); + }); + + it('rejects a token whose mandate binding does not match', async () => { + const token = await createToken(EMAIL, ALIAS); + updateToken(token, MANDATE_ID); + await expect(verifyToken(token, 'wrong_mandate')).rejects.toThrow('Invalid token'); + }); + + it('rejects an unknown token', async () => { + await expect(verifyToken('not-a-real-token', MANDATE_ID)).rejects.toThrow('Invalid token'); + }); +}); +// SD-JWT signature/key-binding forgery is covered at the crypto layer in +// sdjwt-mandate.test.ts ("rejects key binding signed by the wrong holder key"). diff --git a/code/samples/typescript/test/unit/es256-jwt.test.ts b/code/samples/typescript/test/unit/es256-jwt.test.ts new file mode 100644 index 00000000..d292e542 --- /dev/null +++ b/code/samples/typescript/test/unit/es256-jwt.test.ts @@ -0,0 +1,42 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Proves the plain ES256 JWS helpers used for the merchant checkout JWT and + * the PSP payment receipt: sign, verify, and reject tampered / wrong-key tokens. + */ + +import { describe, it, expect } from 'vitest'; +import { generateKeyPair, signJwtEs256, verifyJwtEs256 } from '../../src/common/sdjwt/index.js'; + +describe('ES256 plain JWT (checkout JWT / PSP receipt)', () => { + it('signs and verifies a compact ES256 JWS', async () => { + const key = await generateKeyPair(); + const jwt = await signJwtEs256({ iss: 'merchant-agent', amount: 15000 }, key.privateKey); + expect(jwt.split('.').length).toBe(3); + const payload = await verifyJwtEs256(jwt, key.publicKey); + expect(payload.iss).toBe('merchant-agent'); + expect(payload.amount).toBe(15000); + }); + + it('rejects a token verified with the wrong key', async () => { + const signer = await generateKeyPair(); + const other = await generateKeyPair(); + const jwt = await signJwtEs256({ iss: 'merchant-payment-processor' }, signer.privateKey); + await expect(verifyJwtEs256(jwt, other.publicKey)).rejects.toThrow(); + }); + + it('rejects a tampered payload', async () => { + const key = await generateKeyPair(); + const jwt = await signJwtEs256({ status: 'settled' }, key.privateKey); + const [h, , s] = jwt.split('.'); + const forgedPayload = Buffer.from(JSON.stringify({ status: 'refunded' })).toString('base64url'); + const tampered = `${h}.${forgedPayload}.${s}`; + await expect(verifyJwtEs256(tampered, key.publicKey)).rejects.toThrow(); + }); +}); diff --git a/code/samples/typescript/test/unit/vi-chain-negative.test.ts b/code/samples/typescript/test/unit/vi-chain-negative.test.ts new file mode 100644 index 00000000..cbf285a9 --- /dev/null +++ b/code/samples/typescript/test/unit/vi-chain-negative.test.ts @@ -0,0 +1,284 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Rejection-path tests for the Verifiable Intent chain — the security + * properties that MUST hold: expired credentials, missing/wrong issuer key, and + * delegation to an out-of-mandate payee are all refused. Seed batch for the + * autonomous improvement loop (see BACKLOG.md). Runs in-process, no servers. + */ + +import { describe, it, expect } from 'vitest'; +import { + ACCEPTABLE_ITEMS, + MERCHANT_AUD, + MERCHANTS, + NETWORK_AUD, + PAYMENT_INSTRUMENT, + ROLE_KIDS, + type ViKeyPair, + createAgentFulfillment, + createCheckoutJwt, + checkoutHashFromJwt, + createUserMandateAutonomous, + createUserMandateImmediate, + decodeSdJwt, + findProduct, + generateEs256Key, + issueIssuerCredential, + verifyChain, + verifyCheckoutChain, + verifyPaymentChainAndConstraints, +} from '../../src/common/vi/index.js'; + +async function makeKey(name: string): Promise { + const { publicKey, privateKey } = await generateEs256Key(); + return { publicKey, privateKey, kid: ROLE_KIDS[name] ?? `${name}-key-1` }; +} + +const NOW = 1_900_000_000; + +/** Build a full, valid autonomous fulfillment for the tennis-racket scenario. */ +async function buildChain() { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'racket', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 0, + amountMax: 40000, + }); + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + const fulfillment = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + return { issuer, user, agent, merchant, l1, l2, checkoutJwt, checkoutHash, fulfillment, racket }; +} + +describe('Verifiable Intent — rejection paths', () => { + it('rejects an expired L3 (verified well after its exp)', async () => { + const { issuer, l1, fulfillment } = await buildChain(); + // L3 exp = iat + 300; verify ~1h later → expired. + const outcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: fulfillment.l2PaymentSerialized, + l3PaymentSerialized: fulfillment.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW + 3600, + }); + expect(outcome.valid).toBe(false); + expect(outcome.result.valid).toBe(false); + }); + + it('fails closed when no issuer key is provided and verification is not skipped', async () => { + const { l1, fulfillment } = await buildChain(); + const result = await verifyChain( + decodeSdJwt(l1), + decodeSdJwt(fulfillment.l2PaymentSerialized), + { + l3Payment: decodeSdJwt(fulfillment.l3PaymentSerialized), + l1Serialized: l1, + l2PaymentSerialized: fulfillment.l2PaymentSerialized, + currentTime: NOW, + // intentionally: no issuerPublicJwk, no skipIssuerVerification + }, + ); + expect(result.valid).toBe(false); + }); + + it('rejects a chain verified against the wrong issuer key', async () => { + const { l1, fulfillment } = await buildChain(); + const wrongIssuer = await makeKey('issuer'); + const outcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: fulfillment.l2PaymentSerialized, + l3PaymentSerialized: fulfillment.l3PaymentSerialized, + issuerPublicJwk: wrongIssuer.publicKey, + currentTime: NOW, + }); + expect(outcome.valid).toBe(false); + }); + + it('rejects a checkout presentation addressed to a different audience', async () => { + const { issuer, l1, fulfillment } = await buildChain(); // L3b aud defaults to MERCHANT_AUD + const good = await verifyCheckoutChain({ + l1Serialized: l1, + l2CheckoutSerialized: fulfillment.l2CheckoutSerialized, + l3CheckoutSerialized: fulfillment.l3CheckoutSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3CheckoutAud: MERCHANT_AUD, + }); + expect(good.valid).toBe(true); + + const wrong = await verifyCheckoutChain({ + l1Serialized: l1, + l2CheckoutSerialized: fulfillment.l2CheckoutSerialized, + l3CheckoutSerialized: fulfillment.l3CheckoutSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3CheckoutAud: 'https://evil.example', + }); + expect(wrong.valid).toBe(false); + }); + + it('refuses to build a fulfillment for a payee outside the mandate', async () => { + const { agent, l2, checkoutJwt, checkoutHash, racket } = await buildChain(); + await expect( + createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: { id: 'merchant-unknown', name: 'Not Allowed', website: 'https://nope.example' }, + itemId: racket.sku, + amount: racket.price, + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }), + ).rejects.toThrow(); + }); + + it('rejects an L3 signed by a non-delegated agent key', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const delegated = await makeKey('agent'); // bound into L2 cnf.jwk + const impostor = await makeKey('agent'); // same kid, different key + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: delegated.publicKey, + agentKid: delegated.kid, + promptSummary: 'racket', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 0, + amountMax: 40000, + }); + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + // The impostor (not the cnf-bound agent) builds the fulfillment. + const f = await createAgentFulfillment({ + l2Serialized: l2, + agent: impostor, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + const outcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: f.l2PaymentSerialized, + l3PaymentSerialized: f.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3PaymentAud: NETWORK_AUD, + }); + expect(outcome.result.valid).toBe(false); // L3 not signed by the delegated agent key + }); + + it('rejects a tampered L2 presentation (mutated signature)', async () => { + const { issuer, l1, fulfillment } = await buildChain(); + // Flip the last char of the L2 base-JWT signature segment of the network view. + const parts = fulfillment.l2PaymentSerialized.split('~'); + const [h, p, sig] = parts[0].split('.'); + parts[0] = [h, p, sig.slice(0, -1) + (sig.endsWith('A') ? 'B' : 'A')].join('.'); + const tampered = parts.join('~'); + const outcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: tampered, + l3PaymentSerialized: fulfillment.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3PaymentAud: NETWORK_AUD, + }); + expect(outcome.result.valid).toBe(false); + }); +}); + +describe('Verifiable Intent — immediate (2-layer) rejection paths', () => { + it('rejects an immediate L2 verified against a different L1 (sd_hash binding)', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const merchant = await makeKey('merchant'); + // Two issuer credentials for the SAME user key but different content → different serialization. + const l1a = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'alice', iat: NOW }); + const l1b = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'bob', iat: NOW }); + const checkoutJwt = await createCheckoutJwt([{ sku: 'BAB86345' }], merchant); + const l2 = await createUserMandateImmediate({ + l1Serialized: l1a, + user, + checkoutJwt, + paymentInstrument: PAYMENT_INSTRUMENT, + payee: MERCHANTS[0], + amount: 27999, + iat: NOW, + }); + // L2's sd_hash binds it to l1a; verifying it against l1b must fail. + const result = await verifyChain(decodeSdJwt(l1b), decodeSdJwt(l2), { + issuerPublicJwk: issuer.publicKey, + l1Serialized: l1b, + currentTime: NOW, + }); + expect(result.valid).toBe(false); + }); + + it('rejects an immediate chain verified against the wrong issuer key', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const merchant = await makeKey('merchant'); + const wrongIssuer = await makeKey('issuer'); + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const checkoutJwt = await createCheckoutJwt([{ sku: 'BAB86345' }], merchant); + const l2 = await createUserMandateImmediate({ + l1Serialized: l1, + user, + checkoutJwt, + paymentInstrument: PAYMENT_INSTRUMENT, + payee: MERCHANTS[0], + amount: 27999, + iat: NOW, + }); + const result = await verifyChain(decodeSdJwt(l1), decodeSdJwt(l2), { + issuerPublicJwk: wrongIssuer.publicKey, + l1Serialized: l1, + currentTime: NOW, + }); + expect(result.valid).toBe(false); + }); +}); diff --git a/code/samples/typescript/test/unit/vi-chain.test.ts b/code/samples/typescript/test/unit/vi-chain.test.ts new file mode 100644 index 00000000..eda01377 --- /dev/null +++ b/code/samples/typescript/test/unit/vi-chain.test.ts @@ -0,0 +1,267 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * End-to-end Verifiable Intent chain tests — the TypeScript replication of the + * official Python reference flows (verifiable_intent/python/examples): + * - autonomous_flow.py: L1 issuer -> L2 user (open, agent delegation) + * -> L3a/L3b agent fulfillment -> merchant + network verification + constraints + * - immediate_flow.py: L1 issuer -> L2 user (final values, no L3) -> verification + * + * Runs entirely in-process (no servers / no Gemini), using @verifiable-intent/core + * via src/common/vi. A fixed `currentTime` keeps verification deterministic. + */ + +import { describe, it, expect } from 'vitest'; +import { + ACCEPTABLE_ITEMS, + MERCHANTS, + PAYMENT_INSTRUMENT, + ROLE_KIDS, + type ViKeyPair, + createAgentFulfillment, + createCheckoutJwt, + checkoutHashFromJwt, + createUserMandateAutonomous, + createUserMandateImmediate, + decodeSdJwt, + findProduct, + generateEs256Key, + issueIssuerCredential, + verifyChain, + verifyCheckoutChain, + verifyPaymentChainAndConstraints, +} from '../../src/common/vi/index.js'; + +async function makeKey(name: string): Promise { + const { publicKey, privateKey } = await generateEs256Key(); + return { publicKey, privateKey, kid: ROLE_KIDS[name] ?? `${name}-key-1` }; +} + +const NOW = 1_900_000_000; // fixed, deterministic timestamp + +describe('Verifiable Intent — autonomous (3-layer) flow', () => { + it('issues L1->L2->L3a/L3b and verifies merchant + network chains with constraints', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + // L1 — Credentials Provider issues the issuer credential, binding the user key. + const l1 = await issueIssuerCredential({ + userPublicJwk: user.publicKey, + issuer, + sub: 'user-alice-001', + iat: NOW, + email: 'alice@example.com', + panLastFour: '1234', + }); + + // L2 — User signs the autonomous mandate, delegating to the agent. + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'Buy a Babolat tennis racket under $400', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 10000, + amountMax: 40000, + recurrence: { frequency: 'YEAR', startDate: '2026-01-01', endDate: '2028-01-01', number: 3 }, + }); + + // Merchant produces a checkout JWT for the agent-selected racket. + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku, quantity: 1 }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + + // L3 — Agent builds split fulfillment + per-recipient L2 presentations. + const fulfillment = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + + // Merchant verifies the checkout-side chain (full L2 for pairing, as the example does). + const merchantResult = await verifyCheckoutChain({ + l1Serialized: l1, + l2CheckoutSerialized: fulfillment.l2CheckoutSerialized, + l3CheckoutSerialized: fulfillment.l3CheckoutSerialized, + issuerPublicJwk: issuer.publicKey, + l2Serialized: l2, + currentTime: NOW, + }); + expect(merchantResult.valid).toBe(true); + expect(merchantResult.errors).toEqual([]); + expect(merchantResult.l2CheckoutDisclosed).toBe(true); + + // Network verifies the payment-side chain and enforces constraints (STRICT). + const networkOutcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: fulfillment.l2PaymentSerialized, + l3PaymentSerialized: fulfillment.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + l2Serialized: l2, + currentTime: NOW, + }); + expect(networkOutcome.result.valid).toBe(true); + expect(networkOutcome.constraints).not.toBeNull(); + expect(networkOutcome.constraints!.satisfied).toBe(true); + expect(networkOutcome.valid).toBe(true); + }); + + it('verifies the merchant chain without the full L2 (privacy-strict: checkout presentation only)', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'racket', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 10000, + amountMax: 40000, + }); + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + const fulfillment = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + + // No l2Serialized → defaults to the checkout presentation the merchant actually receives. + const merchantResult = await verifyCheckoutChain({ + l1Serialized: l1, + l2CheckoutSerialized: fulfillment.l2CheckoutSerialized, + l3CheckoutSerialized: fulfillment.l3CheckoutSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + }); + expect(merchantResult.valid).toBe(true); + }); + + it('rejects an over-budget payment via STRICT constraint enforcement', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'cheap racket only', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 1000, + amountMax: 20000, // cap BELOW the racket price (27999) + }); + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + const fulfillment = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, // 27999 > 20000 cap + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + + const networkOutcome = await verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: fulfillment.l2PaymentSerialized, + l3PaymentSerialized: fulfillment.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + l2Serialized: l2, + currentTime: NOW, + }); + // Chain is cryptographically valid, but the amount violates the mandate. + expect(networkOutcome.result.valid).toBe(true); + expect(networkOutcome.constraints!.satisfied).toBe(false); + expect(networkOutcome.valid).toBe(false); + expect(networkOutcome.errors.length).toBeGreaterThan(0); + }); +}); + +describe('Verifiable Intent — immediate (2-layer) flow', () => { + it('issues L1->L2 with final values and verifies the 2-layer chain', async () => { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ + userPublicJwk: user.publicKey, + issuer, + sub: 'user-bob-001', + iat: NOW, + email: 'bob@example.com', + panLastFour: '5678', + }); + + const checkoutJwt = await createCheckoutJwt([{ sku: 'BAB86345', quantity: 1 }], merchant); + const l2 = await createUserMandateImmediate({ + l1Serialized: l1, + user, + checkoutJwt, + paymentInstrument: PAYMENT_INSTRUMENT, + payee: MERCHANTS[0], + amount: 27999, + iat: NOW, + promptSummary: 'Purchase Babolat Pure Aero racket', + }); + + // Merchant: structural check (issuer signature verified out of band). + const merchantResult = await verifyChain(decodeSdJwt(l1), decodeSdJwt(l2), { + skipIssuerVerification: true, + currentTime: NOW, + }); + expect(merchantResult.valid).toBe(true); + + // Network: full verification with the issuer key. + const networkResult = await verifyChain(decodeSdJwt(l1), decodeSdJwt(l2), { + issuerPublicJwk: issuer.publicKey, + l1Serialized: l1, + currentTime: NOW, + }); + expect(networkResult.valid).toBe(true); + expect(networkResult.errors).toEqual([]); + }); +}); diff --git a/code/samples/typescript/test/unit/vi-constraints.test.ts b/code/samples/typescript/test/unit/vi-constraints.test.ts new file mode 100644 index 00000000..1dffb382 --- /dev/null +++ b/code/samples/typescript/test/unit/vi-constraints.test.ts @@ -0,0 +1,108 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Boundary tests for the payment amount/currency constraint — the core VI + * guarantee that an autonomous agent cannot spend beyond the user's mandate. + * Exercises the exact cap boundary and a currency mismatch through the network + * verification path. Runs in-process (no servers / no Gemini). + */ + +import { describe, it, expect } from 'vitest'; +import { + ACCEPTABLE_ITEMS, + MERCHANTS, + NETWORK_AUD, + PAYMENT_INSTRUMENT, + ROLE_KIDS, + type ViKeyPair, + createAgentFulfillment, + createCheckoutJwt, + checkoutHashFromJwt, + createUserMandateAutonomous, + findProduct, + generateEs256Key, + issueIssuerCredential, + verifyPaymentChainAndConstraints, +} from '../../src/common/vi/index.js'; + +const NOW = 1_900_000_000; + +async function makeKey(name: string): Promise { + const { publicKey, privateKey } = await generateEs256Key(); + return { publicKey, privateKey, kid: ROLE_KIDS[name] ?? `${name}-key-1` }; +} + +/** Build + verify a payment chain with a given mandate cap and fulfilled amount/currency. */ +async function settle(opts: { amountMax: number; amount: number; currency?: string }) { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'racket', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 0, + amountMax: opts.amountMax, + currency: 'USD', + }); + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + const f = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: opts.amount, + currency: opts.currency ?? 'USD', + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + return verifyPaymentChainAndConstraints({ + l1Serialized: l1, + l2PaymentSerialized: f.l2PaymentSerialized, + l3PaymentSerialized: f.l3PaymentSerialized, + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3PaymentAud: NETWORK_AUD, + }); +} + +describe('VI payment amount/currency constraint boundaries', () => { + it('allows an amount exactly at the cap', async () => { + const outcome = await settle({ amountMax: 27999, amount: 27999 }); + expect(outcome.constraints?.satisfied).toBe(true); + expect(outcome.valid).toBe(true); + }); + + it('rejects an amount one minor unit over the cap', async () => { + const outcome = await settle({ amountMax: 27998, amount: 27999 }); + expect(outcome.result.valid).toBe(true); // chain is cryptographically valid + expect(outcome.constraints?.satisfied).toBe(false); // amount violates the cap + expect(outcome.valid).toBe(false); + }); + + it('rejects a currency that differs from the mandate', async () => { + const outcome = await settle({ amountMax: 40000, amount: 27999, currency: 'EUR' }); + expect(outcome.result.valid).toBe(true); + expect(outcome.constraints?.satisfied).toBe(false); + expect(outcome.valid).toBe(false); + }); +}); diff --git a/code/samples/typescript/test/unit/vi-integration.test.ts b/code/samples/typescript/test/unit/vi-integration.test.ts new file mode 100644 index 00000000..60f18552 --- /dev/null +++ b/code/samples/typescript/test/unit/vi-integration.test.ts @@ -0,0 +1,158 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Cross-role integration test — exercises the exact persisted-file contract the + * MCP servers use (the serialized SD-JWTs written by shopping-agent-v2 and read + * back by merchant-agent-mcp / credentials-provider-mcp), with the same + * aud-pinned verification each role performs. This locks the wiring end-to-end + * without spawning servers or calling Gemini. + * + * File contract (TEMP_DB): + * l1.sdjwt, l2.sdjwt (agent: assembleAndSignMandates) + * .sdjwt, .l2.sdjwt (agent: createMandateFulfillment — merchant view) + * .sdjwt, .l2.sdjwt (agent: createMandateFulfillment — network view) + */ + +import { afterEach, beforeEach, describe, it, expect } from 'vitest'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + ACCEPTABLE_ITEMS, + MERCHANT_AUD, + MERCHANTS, + NETWORK_AUD, + PAYMENT_INSTRUMENT, + ROLE_KIDS, + type ViKeyPair, + createAgentFulfillment, + createCheckoutJwt, + checkoutHashFromJwt, + createUserMandateAutonomous, + findProduct, + generateEs256Key, + issueIssuerCredential, + verifyCheckoutChain, + verifyPaymentChainAndConstraints, +} from '../../src/common/vi/index.js'; + +const NOW = 1_900_000_000; + +async function makeKey(name: string): Promise { + const { publicKey, privateKey } = await generateEs256Key(); + return { publicKey, privateKey, kid: ROLE_KIDS[name] ?? `${name}-key-1` }; +} + +let TEMP_DB: string; +beforeEach(() => { + TEMP_DB = fs.mkdtempSync(path.join(os.tmpdir(), 'vi-it-')); +}); +afterEach(() => { + fs.rmSync(TEMP_DB, { recursive: true, force: true }); +}); + +const persist = (name: string, content: string): void => + fs.writeFileSync(path.join(TEMP_DB, name), content); +const read = (name: string): string => fs.readFileSync(path.join(TEMP_DB, name), 'utf-8'); + +/** + * Drive the agent side (issuer L1, user L2, merchant checkout, split L3) and + * persist every artifact under TEMP_DB exactly as the role servers expect. + */ +async function runAgentSide(amountMaxCents: number) { + const issuer = await makeKey('issuer'); + const user = await makeKey('user'); + const agent = await makeKey('agent'); + const merchant = await makeKey('merchant'); + + const l1 = await issueIssuerCredential({ userPublicJwk: user.publicKey, issuer, sub: 'u', iat: NOW }); + const l2 = await createUserMandateAutonomous({ + l1Serialized: l1, + user, + agentPublicJwk: agent.publicKey, + agentKid: agent.kid, + promptSummary: 'racket', + iat: NOW, + merchants: MERCHANTS, + acceptableItems: ACCEPTABLE_ITEMS, + paymentInstrument: PAYMENT_INSTRUMENT, + amountMin: 0, + amountMax: amountMaxCents, + }); + persist('l1.sdjwt', l1); + persist('l2.sdjwt', l2); + + const racket = findProduct('BAB86345')!; + const checkoutJwt = await createCheckoutJwt([{ sku: racket.sku }], merchant); + const checkoutHash = checkoutHashFromJwt(checkoutJwt); + const f = await createAgentFulfillment({ + l2Serialized: l2, + agent, + checkoutJwt, + checkoutHash, + payee: MERCHANTS[0], + itemId: racket.sku, + amount: racket.price, // 27999 + paymentInstrument: PAYMENT_INSTRUMENT, + iat: NOW, + }); + const chk = 'chk_test'; + const pay = 'pay_test'; + persist(`${chk}.sdjwt`, f.l3CheckoutSerialized); + persist(`${chk}.l2.sdjwt`, f.l2CheckoutSerialized); + persist(`${pay}.sdjwt`, f.l3PaymentSerialized); + persist(`${pay}.l2.sdjwt`, f.l2PaymentSerialized); + + return { issuer, chk, pay, price: racket.price }; +} + +describe('Verifiable Intent — cross-role file contract', () => { + it('completes a purchase: merchant + network verify from disk with aud pinning', async () => { + const { issuer, chk, pay } = await runAgentSide(40000); + + // Merchant role: read its files, verify the checkout chain (aud-pinned). + const merchantResult = await verifyCheckoutChain({ + l1Serialized: read('l1.sdjwt'), + l2CheckoutSerialized: read(`${chk}.l2.sdjwt`), + l3CheckoutSerialized: read(`${chk}.sdjwt`), + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3CheckoutAud: MERCHANT_AUD, + }); + expect(merchantResult.valid).toBe(true); + + // Network/CP role: read its files, verify the payment chain + constraints. + const networkOutcome = await verifyPaymentChainAndConstraints({ + l1Serialized: read('l1.sdjwt'), + l2PaymentSerialized: read(`${pay}.l2.sdjwt`), + l3PaymentSerialized: read(`${pay}.sdjwt`), + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3PaymentAud: NETWORK_AUD, + }); + expect(networkOutcome.valid).toBe(true); + expect(networkOutcome.constraints?.satisfied).toBe(true); + }); + + it('rejects settlement when the amount exceeds the mandate cap', async () => { + const { issuer, pay } = await runAgentSide(20000); // cap below the 27999 price + + const networkOutcome = await verifyPaymentChainAndConstraints({ + l1Serialized: read('l1.sdjwt'), + l2PaymentSerialized: read(`${pay}.l2.sdjwt`), + l3PaymentSerialized: read(`${pay}.sdjwt`), + issuerPublicJwk: issuer.publicKey, + currentTime: NOW, + expectedL3PaymentAud: NETWORK_AUD, + }); + expect(networkOutcome.result.valid).toBe(true); // chain is cryptographically valid + expect(networkOutcome.valid).toBe(false); // but the amount violates the mandate + expect(networkOutcome.constraints?.satisfied).toBe(false); + }); +}); diff --git a/code/samples/typescript/test/unit/vi-keys.test.ts b/code/samples/typescript/test/unit/vi-keys.test.ts new file mode 100644 index 00000000..7c9fe4aa --- /dev/null +++ b/code/samples/typescript/test/unit/vi-keys.test.ts @@ -0,0 +1,84 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Tests for the file-backed ES256 key store (src/common/vi/keys.ts) — the + * shared infrastructure every role server uses to persist + resolve keys across + * processes. Previously 0% covered. Runs against a throwaway temp TEMP_DB. + */ + +import { afterEach, beforeEach, describe, it, expect } from 'vitest'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + ROLE_KIDS, + decodeSdJwt, + generateEs256Key, + issueIssuerCredential, + loadOrCreateViKey, + loadViPublicJwk, + verifySdJwtSignature, +} from '../../src/common/vi/index.js'; + +let TEMP_DB: string; +beforeEach(() => { + TEMP_DB = fs.mkdtempSync(path.join(os.tmpdir(), 'vi-keys-')); +}); +afterEach(() => { + fs.rmSync(TEMP_DB, { recursive: true, force: true }); +}); + +describe('VI key store', () => { + it('generates + persists a keypair on first use and reloads it unchanged', async () => { + const first = await loadOrCreateViKey(TEMP_DB, 'issuer'); + expect(first.publicKey.kty).toBe('EC'); + expect(first.privateKey.d).toBeTruthy(); // private scalar present + expect(fs.existsSync(path.join(TEMP_DB, 'issuer_key.jwk.json'))).toBe(true); + + const second = await loadOrCreateViKey(TEMP_DB, 'issuer'); + expect(second).toEqual(first); // same jwk + kid, loaded from disk + }); + + it('assigns the documented per-role kids and falls back to -key-1', async () => { + for (const role of ['issuer', 'user', 'agent', 'merchant', 'psp']) { + const pair = await loadOrCreateViKey(TEMP_DB, role); + expect(pair.kid).toBe(ROLE_KIDS[role]); + } + const unknown = await loadOrCreateViKey(TEMP_DB, 'auditor'); + expect(unknown.kid).toBe('auditor-key-1'); + }); + + it('loadViPublicJwk returns the public jwk after creation and null when missing', async () => { + expect(loadViPublicJwk(TEMP_DB, 'merchant')).toBeNull(); + const pair = await loadOrCreateViKey(TEMP_DB, 'merchant'); + const pub = loadViPublicJwk(TEMP_DB, 'merchant'); + expect(pub).toEqual(pair.publicKey); + expect((pub as { d?: string }).d).toBeUndefined(); // no private scalar leaked + }); + + it('loads a legacy keypair (no kid) with the default kid', async () => { + const { publicKey, privateKey } = await generateEs256Key(); + fs.writeFileSync(path.join(TEMP_DB, 'merchant_key.jwk.json'), JSON.stringify({ publicKey, privateKey })); + const pair = await loadOrCreateViKey(TEMP_DB, 'merchant'); + expect(pair.kid).toBe('merchant-key-1'); + expect(pair.publicKey).toEqual(publicKey); + }); + + it('a persisted issuer key actually signs a verifiable credential', async () => { + const issuer = await loadOrCreateViKey(TEMP_DB, 'issuer'); + const user = await loadOrCreateViKey(TEMP_DB, 'user'); + const l1 = await issueIssuerCredential({ + userPublicJwk: user.publicKey, + issuer, + sub: 'u', + iat: 1_900_000_000, + }); + expect(await verifySdJwtSignature(decodeSdJwt(l1), issuer.publicKey)).toBe(true); + }); +}); diff --git a/code/samples/typescript/tsconfig.json b/code/samples/typescript/tsconfig.json new file mode 100644 index 00000000..ad3d3656 --- /dev/null +++ b/code/samples/typescript/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "strict": true, + "skipLibCheck": true, + "outDir": "dist", + "esModuleInterop": true, + "resolveJsonModule": true, + "sourceMap": true, + "declaration": true + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} diff --git a/code/samples/typescript/vitest.config.ts b/code/samples/typescript/vitest.config.ts new file mode 100644 index 00000000..eb4e7f7a --- /dev/null +++ b/code/samples/typescript/vitest.config.ts @@ -0,0 +1,32 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['test/**/*.test.ts'], + testTimeout: 30000, + hookTimeout: 15000, + coverage: { + provider: 'v8', + reporter: ['text', 'json-summary'], + // Scope to the Verifiable Intent integration core (the unit-tested glue). + // The role servers / mandate-tools need stdio servers to exercise, so they + // are covered by e2e, not the unit suite — see BACKLOG.md. + include: ['src/common/vi/**/*.ts'], + exclude: ['src/common/vi/index.ts'], + }, + }, + resolve: { + extensions: ['.ts', '.js'], + alias: { + // Allow .js imports to resolve to .ts source files + }, + conditions: ['import', 'module', 'browser', 'default'], + }, + // Vite will strip .js extensions from imports automatically in resolve + // But for NodeNext module resolution we need this: + esbuild: { + target: 'node18', + }, +});