diff --git a/AGENTS.md b/AGENTS.md index 0243a082a..1dbd1b518 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,9 +32,9 @@ These options are available on all commands: - `create` - Create new AgentCore project - `add` - Add resources (agent, memory, credential, evaluator, online-eval, gateway, gateway-target, policy-engine, - policy) + policy, payment-manager, payment-connector) - `remove` - Remove resources (agent, memory, credential, evaluator, online-eval, gateway, gateway-target, - policy-engine, policy, all) + policy-engine, policy, payment-manager, payment-connector, all) - `deploy` - Deploy infrastructure to AWS - `status` - Check deployment status - `dev` - Local development server (CodeZip: uvicorn with hot-reload; Container: Docker build + run with volume mount) @@ -88,6 +88,8 @@ Current primitives: - `GatewayTargetPrimitive` — gateway target creation/removal with code generation - `PolicyEnginePrimitive` — Cedar policy engine creation/removal - `PolicyPrimitive` — Cedar policy creation/removal within policy engines +- `PaymentManagerPrimitive` — payment manager creation/removal with agent code wiring +- `PaymentConnectorPrimitive` — payment connector creation/removal with credential management Singletons are created in `registry.ts` and wired into CLI commands via `cli.ts`. See `src/cli/AGENTS.md` for details on adding new primitives. diff --git a/docs/commands.md b/docs/commands.md index b5a304a70..a569c03df 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -136,14 +136,14 @@ agentcore status --runtime-id abc123 agentcore status --json ``` -| Flag | Description | -| ------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `--runtime-id ` | Look up a specific runtime by ID | -| `--target ` | Select deployment target | -| `--type ` | Filter by resource type: `agent`, `memory`, `credential`, `gateway`, `evaluator`, `online-eval`, `policy-engine`, `policy` | -| `--state ` | Filter by deployment state: `deployed`, `local-only`, `pending-removal` | -| `--runtime ` | Filter to a specific runtime | -| `--json` | JSON output | +| Flag | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| `--runtime-id ` | Look up a specific runtime by ID | +| `--target ` | Select deployment target | +| `--type ` | Filter by resource type: `agent`, `memory`, `credential`, `gateway`, `evaluator`, `online-eval`, `payment`, `policy-engine`, `policy` | +| `--state ` | Filter by deployment state: `deployed`, `local-only`, `pending-removal` | +| `--runtime ` | Filter to a specific runtime | +| `--json` | JSON output | ### validate @@ -388,6 +388,85 @@ agentcore add gateway-target \ > `open-api-schema` requires `--outbound-auth` (`oauth` or `api-key`). `api-gateway` supports `api-key` or `none`. > `mcp-server` supports `oauth` or `none`. +### add payment-manager + +Add a payment manager to the project. See [Payments](payments.md) for full usage guide. + +```bash +# Minimal (defaults: AWS_IAM, interceptor, auto-payment enabled) +agentcore add payment-manager --name MyManager + +# With CUSTOM_JWT authorization +agentcore add payment-manager \ + --name MyManager \ + --authorizer-type CUSTOM_JWT \ + --discovery-url https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX/.well-known/openid-configuration \ + --allowed-clients "client-id-1,client-id-2" + +# With advanced options +agentcore add payment-manager \ + --name MyManager \ + --auto-payment true \ + --default-spend-limit 25.00 \ + --tool-allowlist "web_search,fetch_url" \ + --network-preferences "eip155:84532" +``` + +| Flag | Description | +| ---------------------------------- | ----------------------------------------------------- | +| `--name ` | Manager name (required in non-interactive mode) | +| `--authorizer-type ` | `AWS_IAM` (default) or `CUSTOM_JWT` | +| `--discovery-url ` | OIDC discovery URL (required for CUSTOM_JWT) | +| `--allowed-clients ` | Comma-separated client IDs (CUSTOM_JWT only) | +| `--allowed-audience ` | Comma-separated allowed audiences (CUSTOM_JWT only) | +| `--allowed-scopes ` | Comma-separated allowed scopes (CUSTOM_JWT only) | +| `--pattern ` | `interceptor` (default) or `tool-based` | +| `--auto-payment [value]` | Enable automatic payment: `true` (default) or `false` | +| `--default-spend-limit ` | Default session spend limit in USD (default: `10.00`) | +| `--tool-allowlist ` | Comma-separated tool names eligible for payment | +| `--network-preferences ` | Comma-separated network IDs (e.g., `eip155:84532`) | +| `--description ` | Human-readable description | +| `--json` | JSON output | + +### add payment-connector + +Add a payment connector to an existing payment manager. See [Payments](payments.md) for credential details. + +```bash +# CoinbaseCDP provider +agentcore add payment-connector \ + --manager MyManager \ + --name MyCDPConnector \ + --provider CoinbaseCDP \ + --api-key-id your-api-key-id \ + --api-key-secret your-api-key-secret \ + --wallet-secret your-wallet-secret + +# StripePrivy provider +agentcore add payment-connector \ + --manager MyManager \ + --name MyStripeConnector \ + --provider StripePrivy \ + --app-id your-app-id \ + --app-secret your-app-secret \ + --authorization-private-key your-private-key \ + --authorization-id your-auth-id +``` + +| Flag | Description | +| ----------------------------------- | ------------------------------------------ | +| `--manager ` | Parent payment manager (required) | +| `--name ` | Connector name (required) | +| `--provider ` | `CoinbaseCDP` (default) or `StripePrivy` | +| `--api-key-id ` | Coinbase CDP API Key ID | +| `--api-key-secret ` | Coinbase CDP API Key Secret | +| `--wallet-secret ` | Coinbase CDP Wallet Secret | +| `--app-id ` | Privy App ID (StripePrivy) | +| `--app-secret ` | Privy App Secret (StripePrivy) | +| `--authorization-private-key ` | ECDSA P-256 private key (StripePrivy) | +| `--authorization-id ` | Authorization key identifier (StripePrivy) | +| `--json` | JSON output | + ### add credential Add a credential to the project. Supports API key and OAuth credential types. @@ -476,18 +555,21 @@ agentcore remove evaluator --name ResponseQuality agentcore remove online-eval --name QualityMonitor agentcore remove gateway --name MyGateway agentcore remove gateway-target --name WeatherTools +agentcore remove payment-manager --name MyManager -y +agentcore remove payment-connector --name MyCDPConnector --manager MyManager -y # Reset everything agentcore remove all -y agentcore remove all --dry-run # Preview ``` -| Flag | Description | -| --------------- | ------------------------- | -| `--name ` | Resource name | -| `-y, --yes` | Skip confirmation | -| `--dry-run` | Preview (remove all only) | -| `--json` | JSON output | +| Flag | Description | +| ------------------ | --------------------------------------------------------- | +| `--name ` | Resource name | +| `--manager ` | Parent payment manager (required for `payment-connector`) | +| `-y, --yes` | Skip confirmation | +| `--dry-run` | Preview (remove all only) | +| `--json` | JSON output | --- @@ -549,23 +631,26 @@ agentcore invoke --exec "cat /etc/os-release" --json The prompt can come from four sources, resolved in this precedence order: `--prompt` > positional > `--prompt-file` > piped stdin. `--prompt-file` combined with piped stdin content returns a collision error — pick one. -| Flag | Description | -| ---------------------- | ---------------------------------------------------------------- | -| `[prompt]` | Prompt text (positional argument) | -| `--prompt ` | Prompt text (flag, takes precedence over positional) | -| `--prompt-file ` | Read the prompt from a file (useful for long / structured input) | -| `--runtime ` | Specific runtime | -| `--target ` | Deployment target | -| `--session-id ` | Continue a specific session | -| `--user-id ` | User ID for runtime invocation (default: `default-user`) | -| `--stream` | Stream response in real-time | -| `--tool ` | MCP tool name (use with `call-tool` prompt) | -| `--input ` | MCP tool arguments as JSON (use with `--tool`) | -| `-H, --header ` | Custom header (`"Name: Value"`, repeatable) | -| `--bearer-token ` | Bearer token for CUSTOM_JWT auth | -| `--exec` | Execute a shell command in the runtime container | -| `--timeout ` | Timeout in seconds for `--exec` commands | -| `--json` | JSON output | +| Flag | Description | +| ------------------------------ | ---------------------------------------------------------------- | +| `[prompt]` | Prompt text (positional argument) | +| `--prompt ` | Prompt text (flag, takes precedence over positional) | +| `--prompt-file ` | Read the prompt from a file (useful for long / structured input) | +| `--runtime ` | Specific runtime | +| `--target ` | Deployment target | +| `--session-id ` | Continue a specific session | +| `--user-id ` | User ID for runtime invocation (default: `default-user`) | +| `--stream` | Stream response in real-time | +| `--tool ` | MCP tool name (use with `call-tool` prompt) | +| `--input ` | MCP tool arguments as JSON (use with `--tool`) | +| `-H, --header ` | Custom header (`"Name: Value"`, repeatable) | +| `--bearer-token ` | Bearer token for CUSTOM_JWT auth | +| `--payment-instrument-id ` | Payment instrument ID for x402 payments | +| `--payment-session-id ` | Payment session ID for budget tracking | +| `--auto-session` | Auto-create/reuse a payment session for testing | +| `--exec` | Execute a shell command in the runtime container | +| `--timeout ` | Timeout in seconds for `--exec` commands | +| `--json` | JSON output | Piped stdin is auto-detected: when no prompt is supplied and stdin is not a TTY, the prompt is read from stdin. diff --git a/docs/configuration.md b/docs/configuration.md index 05f580107..ef1c41e14 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -38,6 +38,7 @@ Main project configuration using a **flat resource model**. Agents, memories, an ], "memories": [], "credentials": [], + "payments": [], "evaluators": [], "onlineEvalConfigs": [], "agentCoreGateways": [], @@ -57,6 +58,7 @@ Main project configuration using a **flat resource model**. Agents, memories, an | `credentials` | Yes | Array of credential providers (API key or OAuth) | | `evaluators` | Yes | Array of custom evaluator definitions | | `onlineEvalConfigs` | Yes | Array of online eval configurations | +| `payments` | No | Array of payment manager configurations | | `policyEngines` | No | Array of policy engine configurations | | `agentCoreGateways` | No | Array of gateway definitions | | `mcpRuntimeTools` | No | Array of MCP runtime tool definitions | @@ -482,6 +484,88 @@ implementations. --- +## Payment Manager Resource + +Payment managers define how agents handle x402 microtransactions. Each manager has one or more connectors that provide +wallet credentials. See [Payments](payments.md) for the full usage guide. + +```json +{ + "payments": [ + { + "name": "MyManager", + "authorizerType": "AWS_IAM", + "pattern": "interceptor", + "autoPayment": true, + "defaultSpendLimit": "10.00", + "paymentToolAllowlist": ["web_search", "fetch_url"], + "networkPreferences": ["eip155:84532"], + "description": "Production payment manager", + "connectors": [ + { + "name": "MyCDPConnector", + "provider": "CoinbaseCDP", + "credentialName": "my-cdp-creds" + } + ] + } + ] +} +``` + +### Payment Manager Fields + +| Field | Required | Description | +| ------------------------- | -------- | -------------------------------------------------------------------- | +| `name` | Yes | Manager name (alphanumeric + underscore, max 48, starts with letter) | +| `authorizerType` | No | `"AWS_IAM"` (default) or `"CUSTOM_JWT"` | +| `authorizerConfiguration` | Cond. | Required when `authorizerType` is `"CUSTOM_JWT"` (see below) | +| `pattern` | No | `"interceptor"` (default) or `"tool-based"` | +| `connectors` | Yes | Array of payment connector objects | +| `autoPayment` | No | Enable automatic payment (default: `true`) | +| `defaultSpendLimit` | No | Default session budget in USD (e.g., `"10.00"`) | +| `paymentToolAllowlist` | No | Array of tool names eligible for payment | +| `networkPreferences` | No | Array of network identifiers (e.g., `"eip155:84532"`) | +| `description` | No | Human-readable description | + +### Authorizer Configuration (CUSTOM_JWT) + +```json +{ + "authorizerConfiguration": { + "customJWTAuthorizer": { + "discoveryUrl": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX/.well-known/openid-configuration", + "allowedClients": ["client-id-1"], + "allowedAudience": ["https://api.example.com"], + "allowedScopes": ["payments:read", "payments:write"] + } + } +} +``` + +| Field | Required | Description | +| ----------------- | -------- | --------------------------- | +| `discoveryUrl` | Yes | OIDC discovery URL | +| `allowedClients` | No | Array of allowed client IDs | +| `allowedAudience` | No | Array of allowed audiences | +| `allowedScopes` | No | Array of allowed scopes | + +### Payment Connector + +| Field | Required | Description | +| ---------------- | -------- | -------------------------------------------------- | +| `name` | Yes | Connector name (alphanumeric + underscore, max 48) | +| `provider` | No | `"CoinbaseCDP"` (default) or `"StripePrivy"` | +| `credentialName` | Yes | Name of the credential (maps to `.env.local` vars) | + +### Payment Credential Provider + +Payment connectors use a `PaymentCredentialProvider` credential type, distinct from `ApiKeyCredentialProvider` and +`OAuthCredentialProvider`. The credential is automatically created during `agentcore deploy` from values in +`.env.local`. You do not need to add it to the `credentials` array manually. + +--- + ## aws-targets.json Deployment target @@ -524,6 +608,19 @@ AGENTCORE_CREDENTIAL_{projectName}GEMINI=... # OAuth credentials AGENTCORE_CREDENTIAL_{projectName}{credentialName}_CLIENT_ID=my-client-id AGENTCORE_CREDENTIAL_{projectName}{credentialName}_CLIENT_SECRET=my-client-secret + +# Payment credentials - CoinbaseCDP (3 variables per connector) +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_API_KEY_ID=your-api-key-id +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_API_KEY_SECRET=your-api-key-secret +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_WALLET_SECRET=your-wallet-secret + +# Payment credentials - StripePrivy (4 variables per connector) +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_APP_ID=your-app-id +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_APP_SECRET=your-app-secret +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_AUTHORIZATION_PRIVATE_KEY=your-private-key +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_AUTHORIZATION_ID=your-auth-id ``` -Environment variable names should match the credential names in your configuration. +Environment variable names should match the credential names in your configuration. For payment credentials, +`{CREDENTIAL_NAME}` is the connector's `credentialName` uppercased with hyphens replaced by underscores (e.g., +`my-cdp-creds` becomes `MY_CDP_CREDS`). See [Payments](payments.md#credential-storage) for details. diff --git a/docs/payments.md b/docs/payments.md new file mode 100644 index 000000000..9239d5eb0 --- /dev/null +++ b/docs/payments.md @@ -0,0 +1,343 @@ +# Payments + +Payments enable agents to process microtransactions using the [x402 protocol](https://www.x402.org/). When an agent's +HTTP tool call receives a `402 Payment Required` response, the payments system automatically signs and submits payment, +then retries the original request. This lets agents access paid APIs and services without manual intervention. + +For a full overview of the payment architecture, see +[AgentCore Payments](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments.html) in the AWS developer +guide. + +## Quick Start + +```bash +# 1. Create a project with payments capability +agentcore create --name MyProject --defaults +cd MyProject + +# 2. Add a payment manager +agentcore add payment-manager --name MyManager --pattern interceptor + +# 3. Add a payment connector with CoinbaseCDP credentials +agentcore add payment-connector \ + --manager MyManager \ + --name MyCDPConnector \ + --provider CoinbaseCDP \ + --api-key-id your-api-key-id \ + --api-key-secret your-api-key-secret \ + --wallet-secret your-wallet-secret + +# 4. Deploy (creates payment infrastructure on AWS) +agentcore deploy -y + +# 5. Invoke with auto-session (creates a test payment session) +agentcore invoke --auto-session --prompt "Use a paid tool" +``` + +> **Note**: `--auto-session` requires a successful deploy first because it reads from deployed state to locate the +> payment manager ARN and create a session. + +## How It Works + +When an agent makes an HTTP request to a paid endpoint, the server returns a `402 Payment Required` response containing +payment requirements (amount, recipient, network). The AgentCore payments plugin intercepts this response, calls +`ProcessPayment` to sign a USDC transaction, and retries the original request with payment proof headers attached. + +For the full runtime flow, see +[How AgentCore payments works](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-how-it-works.html). + +### Payment Patterns + +| Pattern | Behavior | +| ----------- | ------------------------------------------------------------ | +| interceptor | Automatically handles 402 responses (transparent to agent) | +| tool-based | Exposes payment as an agent tool (agent decides when to pay) | + +## Adding a Payment Manager + +A payment manager is the top-level resource that orchestrates payment operations. It defines authorization, spending +patterns, and budget defaults. + +### CLI Command + +```bash +# Minimal (defaults: AWS_IAM auth, interceptor pattern, auto-payment enabled) +agentcore add payment-manager --name MyManager + +# With all advanced options +agentcore add payment-manager \ + --name MyManager \ + --authorizer-type AWS_IAM \ + --pattern interceptor \ + --auto-payment true \ + --default-spend-limit 25.00 \ + --tool-allowlist "web_search,fetch_url" \ + --network-preferences "eip155:84532,eip155:8453" \ + --description "Production payment manager" +``` + +| Flag | Description | +| ---------------------------------- | ------------------------------------------------------------------- | +| `--name ` | Manager name (required in non-interactive mode) | +| `--authorizer-type ` | `AWS_IAM` (default) or `CUSTOM_JWT` | +| `--discovery-url ` | OIDC discovery URL (required for CUSTOM_JWT) | +| `--allowed-clients ` | Comma-separated client IDs (CUSTOM_JWT only) | +| `--allowed-audience ` | Comma-separated allowed audiences (CUSTOM_JWT only) | +| `--allowed-scopes ` | Comma-separated allowed scopes (CUSTOM_JWT only) | +| `--pattern ` | `interceptor` (default) or `tool-based` | +| `--auto-payment [value]` | Enable automatic payment: `true` (default) or `false` | +| `--default-spend-limit ` | Default session spend limit in USD (default: `10.00`) | +| `--tool-allowlist ` | Comma-separated tool names eligible for payment | +| `--network-preferences ` | Comma-separated network IDs (e.g., `eip155:84532` for Base Sepolia) | +| `--description ` | Human-readable description | +| `--json` | Output result as JSON | + +Name constraints: must start with a letter, contain only alphanumeric characters and underscores, max 48 characters. + +When you add a payment manager, the CLI automatically patches your agent code to include the payments plugin. The +generated code is at `capabilities/payments/payments.py` in each agent's directory. + +### Authorization Types + +**AWS_IAM** (default): Uses AWS IAM SigV4 signing for payment authorization. No additional configuration needed. + +```bash +agentcore add payment-manager --name MyManager --authorizer-type AWS_IAM +``` + +**CUSTOM_JWT**: Uses a custom JWT authorizer via OIDC discovery. Useful when end users authenticate via an external +identity provider (e.g., Cognito). + +```bash +agentcore add payment-manager \ + --name MyManager \ + --authorizer-type CUSTOM_JWT \ + --discovery-url https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXX/.well-known/openid-configuration \ + --allowed-clients "client-id-1,client-id-2" \ + --allowed-audience "https://api.example.com" \ + --allowed-scopes "payments:read,payments:write" +``` + +For details on IAM role separation (ManagementRole vs ProcessPaymentRole), see +[IAM roles for AgentCore payments](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html). + +## Adding a Payment Connector + +A payment connector links a credential provider (wallet credentials) to a payment manager. Each manager needs at least +one connector before it can process payments. + +### CoinbaseCDP Provider + +```bash +agentcore add payment-connector \ + --manager MyManager \ + --name MyCDPConnector \ + --provider CoinbaseCDP \ + --api-key-id your-api-key-id \ + --api-key-secret your-api-key-secret \ + --wallet-secret your-wallet-secret +``` + +| Flag | Description | +| --------------------------- | ---------------------------------------- | +| `--manager ` | Parent payment manager (required) | +| `--name ` | Connector name (required) | +| `--provider ` | `CoinbaseCDP` (default) or `StripePrivy` | +| `--api-key-id ` | Coinbase CDP API Key ID | +| `--api-key-secret ` | Coinbase CDP API Key Secret | +| `--wallet-secret ` | Coinbase CDP Wallet Secret (ECDSA P-256) | +| `--json` | Output result as JSON | + +### StripePrivy Provider + +```bash +agentcore add payment-connector \ + --manager MyManager \ + --name MyStripeConnector \ + --provider StripePrivy \ + --app-id your-privy-app-id \ + --app-secret your-privy-app-secret \ + --authorization-private-key your-ecdsa-private-key \ + --authorization-id your-authorization-key-id +``` + +| Flag | Description | +| ----------------------------------- | ----------------------------------- | +| `--manager ` | Parent payment manager (required) | +| `--name ` | Connector name (required) | +| `--provider ` | Must be `StripePrivy` | +| `--app-id ` | Privy App ID | +| `--app-secret ` | Privy App Secret | +| `--authorization-private-key ` | ECDSA P-256 private key for signing | +| `--authorization-id ` | Authorization key identifier | +| `--json` | Output result as JSON | + +### Credential Storage + +Connector credentials are stored in `agentcore/.env.local` and never committed to source control. The env var naming +convention is: + +**CoinbaseCDP** (3 variables): + +``` +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_API_KEY_ID=... +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_API_KEY_SECRET=... +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_WALLET_SECRET=... +``` + +**StripePrivy** (4 variables): + +``` +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_APP_ID=... +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_APP_SECRET=... +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_AUTHORIZATION_PRIVATE_KEY=... +AGENTCORE_CREDENTIAL_{CREDENTIAL_NAME}_AUTHORIZATION_ID=... +``` + +`{CREDENTIAL_NAME}` is the connector's credential name uppercased with hyphens replaced by underscores. For example, a +credential named `my-cdp-creds` becomes `AGENTCORE_CREDENTIAL_MY_CDP_CREDS_API_KEY_ID`. + +### Credential Rotation + +To rotate credentials: + +1. Update the values in `agentcore/.env.local` +2. Run `agentcore deploy -y` + +Deploy automatically updates the PaymentCredentialProvider on AWS with the new secret values. + +## Deploying with Payments + +When you run `agentcore deploy`, the CLI creates payment infrastructure via direct API calls (not CloudFormation). The +deploy sequence for each payment manager: + +1. Reads credentials from `.env.local` +2. Creates or updates a **PaymentCredentialProvider** with the connector secrets +3. Creates **IAM roles** (ProcessPaymentRole and ResourceRetrievalRole) if they don't exist +4. Creates the **PaymentManager** (skipped if it already exists) +5. Creates or updates the **PaymentConnector** linking credentials to the manager + +### Prerequisites + +- `agentcore/.env.local` must exist with all required credential variables +- Each manager must have at least one connector configured +- AWS credentials with sufficient permissions (see + [IAM roles](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html)) + +> **Note**: First-time deployment takes extra time for IAM role creation and propagation. Subsequent deploys are faster. + +## Invoking with Payment Context + +After deploying, use `agentcore invoke` to test agents with payment capabilities. + +### Payment Flags + +| Flag | Description | +| ------------------------------ | --------------------------------------------------------- | +| `--payment-instrument-id ` | Payment instrument ID (a funded wallet) for x402 payments | +| `--payment-session-id ` | Payment session ID for budget tracking | +| `--auto-session` | Auto-create or reuse a payment session for testing | + +### Auto-Session Mode + +`--auto-session` creates a temporary payment session with the default spend limit, or reuses an existing one from the +current testing context. This is the simplest way to test payment flows without manually creating instruments and +sessions via the AWS API. + +```bash +agentcore invoke --auto-session --prompt "Search for paid research papers" +``` + +### Explicit Payment Context + +For production testing with specific instruments and sessions: + +```bash +agentcore invoke \ + --payment-instrument-id payment-instrument-abc123 \ + --payment-session-id payment-session-xyz789 \ + --prompt "Process a payment for the weather API" +``` + +For details on creating instruments and sessions, see +[Create a payment instrument](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-create-instrument.html). + +## Status and Removal + +### Checking Status + +```bash +agentcore status --type payment +``` + +Shows each payment manager's deployment state, connector count, and live health from the AWS API. The status command +queries the deployed payment manager to verify it's reachable. + +### Removing a Connector + +```bash +agentcore remove payment-connector --name MyCDPConnector --manager MyManager -y +``` + +The `--manager` flag is required when a connector name exists under multiple managers. + +### Removing a Manager + +```bash +agentcore remove payment-manager --name MyManager -y +``` + +Removing a payment manager cascades: it deletes all associated connectors and credential providers from the local +configuration. + +## Validation + +`agentcore validate` checks payment configuration for common issues: + +- Credential cross-references: verifies each connector's `credentialName` maps to a valid credential entry +- `.env.local` existence: confirms the secrets file exists when payment connectors are configured +- Missing environment variables: checks that all required `AGENTCORE_CREDENTIAL_*` variables are present + +```bash +agentcore validate +``` + +## Troubleshooting + +| Error | Cause | Fix | +| ------------------------------------- | ---------------------------------------- | -------------------------------------------------------------- | +| `.env.local not found` | No secrets file in project | Create `agentcore/.env.local` with credential vars | +| `Missing credentials for connector` | Env vars not set for a connector | Add the required `AGENTCORE_CREDENTIAL_*` vars to `.env.local` | +| `ServiceQuotaExceededException` | Account limit on payment managers | Request a quota increase via AWS Support | +| `No connectors for payment manager` | Manager has zero connectors | Add at least one connector before deploying | +| `PaymentCredentialProvider not found` | Orphaned reference after manual deletion | Re-run `agentcore deploy` to recreate | +| `Request timeout` | Network or service availability | Retry deploy; check internet connectivity | +| `Invalid authorizer type` | Typo in `--authorizer-type` flag | Use `AWS_IAM` or `CUSTOM_JWT` (case-sensitive) | + +For additional troubleshooting, see +[Troubleshooting AgentCore payments](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-troubleshooting.html). + +## Further Reading + +**AWS Documentation:** + +- [AgentCore Payments overview](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments.html) +- [Core concepts](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-concepts.html) +- [How it works](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-how-it-works.html) +- [Getting started](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-getting-started.html) +- [Prerequisites](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-prerequisites.html) +- [IAM roles](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html) +- [Create manager and connector](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-create-manager.html) +- [Create instrument](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-create-instrument.html) +- [Process a payment](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-process-payment.html) +- [Coinbase Bazaar via Gateway](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-connect-bazaar.html) +- [Observability](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-observability.html) +- [Troubleshooting](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-troubleshooting.html) + +**Blog:** + +- [Agents that transact: Introducing Amazon Bedrock AgentCore Payments](https://aws.amazon.com/blogs/machine-learning/agents-that-transact-introducing-amazon-bedrock-agentcore-payments-built-with-coinbase-and-stripe/) + +**Samples:** + +- [x402 Payments with CloudFront](https://github.com/aws-samples/sample-agentcore-cloudfront-x402-payments) diff --git a/e2e-tests/payment-strands-bedrock.test.ts b/e2e-tests/payment-strands-bedrock.test.ts new file mode 100644 index 000000000..33c1eb63c --- /dev/null +++ b/e2e-tests/payment-strands-bedrock.test.ts @@ -0,0 +1,212 @@ +/** + * E2E test: Payment manager + connector → deploy → status + * + * Creates a Strands/Bedrock project with a payment manager and connector, + * deploys it to AWS, and verifies payment infrastructure is created correctly. + * + * Required env vars: + * - AWS credentials (via profile or env vars) + * - CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET (for connector creation) + * - CDK_TARBALL (optional — path to payment-aware CDK constructs tgz) + */ +import { hasAwsCredentials, parseJsonOutput, prereqs, retry } from '../src/test-utils/index.js'; +import { installCdkTarball, runAgentCoreCLI, teardownE2EProject, writeAwsTargets } from './e2e-helper.js'; +import { randomUUID } from 'node:crypto'; +import { mkdir, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +const hasAws: boolean = hasAwsCredentials(); +const hasCdpCreds = !!(process.env.CDP_API_KEY_ID && process.env.CDP_API_KEY_SECRET && process.env.CDP_WALLET_SECRET); +const canRun = prereqs.npm && prereqs.git && prereqs.uv && hasAws && hasCdpCreds; + +describe.sequential('e2e: payments — create → add payment → deploy → status', () => { + let testDir: string; + let projectPath: string; + let agentName: string; + const managerName = 'E2ePayMgr'; + const connectorName = 'E2ePayConn'; + + beforeAll(async () => { + if (!canRun) return; + + testDir = join(tmpdir(), `agentcore-e2e-pay-${randomUUID()}`); + await mkdir(testDir, { recursive: true }); + + agentName = `E2ePay${String(Date.now()).slice(-8)}`; + + // Create project + const createResult = await runAgentCoreCLI( + [ + 'create', + '--name', + agentName, + '--language', + 'Python', + '--framework', + 'Strands', + '--model-provider', + 'Bedrock', + '--memory', + 'none', + '--json', + ], + testDir + ); + + expect(createResult.exitCode, `Create failed: ${createResult.stderr}`).toBe(0); + const createJson = parseJsonOutput(createResult.stdout) as { projectPath: string }; + projectPath = createJson.projectPath; + + // Add payment manager + const mgrResult = await runAgentCoreCLI( + ['add', 'payment-manager', '--name', managerName, '--pattern', 'interceptor', '--json'], + projectPath + ); + expect(mgrResult.exitCode, `Add manager failed: ${mgrResult.stderr}`).toBe(0); + + // Add payment connector with CDP credentials + const connResult = await runAgentCoreCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName, + '--provider', + 'CoinbaseCDP', + '--api-key-id', + process.env.CDP_API_KEY_ID!, + '--api-key-secret', + process.env.CDP_API_KEY_SECRET!, + '--wallet-secret', + process.env.CDP_WALLET_SECRET!, + '--json', + ], + projectPath + ); + expect(connResult.exitCode, `Add connector failed: ${connResult.stderr}`).toBe(0); + + // Write AWS targets + install CDK tarball + await writeAwsTargets(projectPath); + installCdkTarball(projectPath); + }, 300000); + + afterAll(async () => { + if (projectPath && hasAws) { + await teardownE2EProject(projectPath, agentName, 'Bedrock'); + } + if (testDir) await rm(testDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 1000 }); + }, 600000); + + it.skipIf(!canRun)('has correct agentcore.json structure', async () => { + const configPath = join(projectPath, 'agentcore', 'agentcore.json'); + const config = JSON.parse(await readFile(configPath, 'utf-8')); + + // Manager exists with correct fields + const manager = config.payments?.find((p: Record) => p.name === managerName); + expect(manager).toBeTruthy(); + expect(manager.authorizerType).toBe('AWS_IAM'); + expect(manager.pattern).toBe('interceptor'); + + // Connector nested inside manager + const connector = manager.connectors?.find((c: Record) => c.name === connectorName); + expect(connector).toBeTruthy(); + expect(connector.provider).toBe('CoinbaseCDP'); + + // Credential exists + const cred = config.credentials?.find( + (c: Record) => c.authorizerType === 'PaymentCredentialProvider' + ); + expect(cred).toBeTruthy(); + }); + + it.skipIf(!canRun)('has payment capability code in agent', async () => { + const config = JSON.parse(await readFile(join(projectPath, 'agentcore', 'agentcore.json'), 'utf-8')); + const runtimeName = config.runtimes?.[0]?.name; + expect(runtimeName).toBeTruthy(); + + // payments.py exists with per-invocation factory + const paymentsCode = await readFile( + join(projectPath, 'app', runtimeName, 'capabilities', 'payments', 'payments.py'), + 'utf-8' + ); + expect(paymentsCode).toContain('create_payments_plugin'); + expect(paymentsCode).toContain('user_id'); + expect(paymentsCode).toContain('instrument_id'); + expect(paymentsCode).toContain('session_id'); + }); + + it.skipIf(!canRun)( + 'deploys to AWS successfully', + async () => { + expect(projectPath).toBeTruthy(); + + await retry( + async () => { + const result = await runAgentCoreCLI(['deploy', '--yes', '--json'], projectPath); + + if (result.exitCode !== 0) { + console.log('Deploy stdout:', result.stdout); + console.log('Deploy stderr:', result.stderr); + } + + expect(result.exitCode, `Deploy failed: ${result.stderr}`).toBe(0); + + const json = parseJsonOutput(result.stdout) as { success: boolean }; + expect(json.success).toBe(true); + }, + 1, + 30000 + ); + }, + 600000 + ); + + it.skipIf(!canRun)('status shows payment manager', async () => { + expect(projectPath).toBeTruthy(); + + const result = await runAgentCoreCLI(['status', '--json'], projectPath); + expect(result.exitCode).toBe(0); + + const json = parseJsonOutput(result.stdout) as { + success: boolean; + resources: { resourceType: string; name: string; deploymentState: string }[]; + }; + expect(json.success).toBe(true); + + // Find payment resource + const paymentResource = json.resources?.find(r => r.resourceType === 'payment' && r.name === managerName); + expect(paymentResource, 'Payment manager should appear in status').toBeTruthy(); + expect(paymentResource!.deploymentState).toBe('deployed'); + }); + + it.skipIf(!canRun)('deployed-state.json has payment manager and connector info', async () => { + // Read deployed state from the CLI's internal state + const statePath = join(projectPath, 'agentcore', '.cli', 'deployed-state.json'); + const state = JSON.parse(await readFile(statePath, 'utf-8')); + + const targetState = Object.values(state.targets)[0] as Record; + const resources = targetState?.resources as Record; + const payments = resources?.payments as Record; + + expect(payments).toBeTruthy(); + const managerState = payments[managerName] as Record; + expect(managerState).toBeTruthy(); + expect(managerState.managerId).toBeTruthy(); + expect(managerState.managerArn).toBeTruthy(); + expect(managerState.processPaymentRoleArn).toBeTruthy(); + expect(managerState.resourceRetrievalRoleArn).toBeTruthy(); + expect(managerState.roleCreatedByCli).toBe(true); + + // Connector info + const connectors = managerState.connectors as Record>; + expect(connectors).toBeTruthy(); + const connState = connectors[connectorName]; + expect(connState).toBeTruthy(); + expect(connState!.connectorId).toBeTruthy(); + expect(connState!.credentialProviderArn).toBeTruthy(); + }); +}); diff --git a/e2e-tests/payment-validation.test.ts b/e2e-tests/payment-validation.test.ts new file mode 100644 index 000000000..6e625c05f --- /dev/null +++ b/e2e-tests/payment-validation.test.ts @@ -0,0 +1,179 @@ +/** + * E2E test: Payment validation, config fields, and remove lifecycle + * + * Tests payment-specific validation (whitespace creds, StripePrivy key format), + * config fields (autoPayment, defaultSpendLimit, paymentToolAllowlist, networkPreferences), + * and remove cascading behavior. No AWS deploy needed — all local. + */ +import { parseJsonOutput, prereqs } from '../src/test-utils/index.js'; +import { runAgentCoreCLI } from './e2e-helper.js'; +import { randomUUID } from 'node:crypto'; +import { mkdir, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +const canRun = prereqs.npm && prereqs.git && prereqs.uv; + +describe.sequential('e2e: payments — validation, config, and remove lifecycle', () => { + let testDir: string; + let projectPath: string; + + beforeAll(async () => { + if (!canRun) return; + + testDir = join(tmpdir(), `agentcore-e2e-payval-${randomUUID()}`); + await mkdir(testDir, { recursive: true }); + + const createResult = await runAgentCoreCLI( + ['create', '--name', 'PayVal', '--language', 'Python', '--framework', 'Strands', '--model-provider', 'Bedrock', '--memory', 'none', '--json'], + testDir + ); + expect(createResult.exitCode, `Create failed: stdout=${createResult.stdout} stderr=${createResult.stderr}`).toBe(0); + const createJson = parseJsonOutput(createResult.stdout) as { projectPath: string }; + projectPath = createJson.projectPath; + }, 120000); + + afterAll(async () => { + if (testDir) await rm(testDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 1000 }); + }); + + // ── Config fields ───────────────────────────────────────────────────────── + + it.skipIf(!canRun)('add payment-manager with --auto-payment and --default-spend-limit', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-manager', '--name', 'cfgMgr', '--pattern', 'interceptor', '--auto-payment', 'false', '--default-spend-limit', '7.50', '--json'], + projectPath + ); + expect(result.exitCode).toBe(0); + + const config = JSON.parse(await readFile(join(projectPath, 'agentcore', 'agentcore.json'), 'utf-8')); + const mgr = config.payments.find((p: Record) => p.name === 'cfgMgr'); + expect(mgr.autoPayment).toBe(false); + expect(mgr.defaultSpendLimit).toBe('7.50'); + }); + + it.skipIf(!canRun)('agentcore.json accepts paymentToolAllowlist and networkPreferences', async () => { + const configPath = join(projectPath, 'agentcore', 'agentcore.json'); + const config = JSON.parse(await readFile(configPath, 'utf-8')); + const mgr = config.payments.find((p: Record) => p.name === 'cfgMgr'); + mgr.paymentToolAllowlist = ['http_request', 'fetch_url']; + mgr.networkPreferences = ['eip155:84532']; + const { writeFile: wf } = await import('node:fs/promises'); + await wf(configPath, JSON.stringify(config, null, 2)); + + const valResult = await runAgentCoreCLI(['validate'], projectPath); + expect(valResult.exitCode).toBe(0); + }); + + // ── Validation: whitespace credentials ──────────────────────────────────── + + it.skipIf(!canRun)('rejects whitespace-only CoinbaseCDP credentials', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'cfgMgr', '--name', 'wsConn', '--provider', 'CoinbaseCDP', + '--api-key-id', ' ', '--api-key-secret', ' ', '--wallet-secret', ' ', '--json'], + projectPath + ); + expect(result.exitCode).toBe(1); + const json = parseJsonOutput(result.stdout) as { success: boolean; error: string }; + expect(json.success).toBe(false); + expect(json.error).toContain('Missing required options'); + }); + + // ── Validation: StripePrivy key format ──────────────────────────────────── + + it.skipIf(!canRun)('rejects non-base64 StripePrivy authorizationPrivateKey', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'cfgMgr', '--name', 'badKey', '--provider', 'StripePrivy', + '--app-id', 'test', '--app-secret', 'test', '--authorization-private-key', 'not-base64!', '--authorization-id', 'test', '--json'], + projectPath + ); + expect(result.exitCode).toBe(1); + const json = parseJsonOutput(result.stdout) as { success: boolean; error: string }; + expect(json.success).toBe(false); + expect(json.error).toContain('base64'); + }); + + it.skipIf(!canRun)('rejects too-short StripePrivy authorizationPrivateKey', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'cfgMgr', '--name', 'shortKey', '--provider', 'StripePrivy', + '--app-id', 'test', '--app-secret', 'test', '--authorization-private-key', 'dGVzdA==', '--authorization-id', 'test', '--json'], + projectPath + ); + expect(result.exitCode).toBe(1); + const json = parseJsonOutput(result.stdout) as { success: boolean; error: string }; + expect(json.success).toBe(false); + expect(json.error).toContain('EC P-256'); + }); + + it.skipIf(!canRun)('accepts valid StripePrivy credentials (PKCS#8 P-256 key)', async () => { + const validKey = 'MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgX172itZu99Ae6bmVpS+6bwKyFmbuy9vkHAIEXwi1IduhRANCAAS160HztG9NZvTv05zfg76koloQ5G+NJwN8lVR5rRKmCLqe+pyc0znwF9Q+LsENdGqi7zTWVVJhhEq3Xa5Tm4F4'; + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'cfgMgr', '--name', 'spConn', '--provider', 'StripePrivy', + '--app-id', 'privy-app', '--app-secret', 'privy-secret', '--authorization-private-key', validKey, '--authorization-id', 'auth-123', '--json'], + projectPath + ); + expect(result.exitCode).toBe(0); + const json = parseJsonOutput(result.stdout) as { success: boolean }; + expect(json.success).toBe(true); + }); + + // ── Validation: duplicate names ─────────────────────────────────────────── + + it.skipIf(!canRun)('rejects duplicate manager name', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-manager', '--name', 'cfgMgr', '--pattern', 'interceptor', '--json'], + projectPath + ); + expect(result.exitCode).toBe(1); + const json = parseJsonOutput(result.stdout) as { success: boolean; error: string }; + expect(json.error).toContain('already exists'); + }); + + it.skipIf(!canRun)('rejects connector on non-existent manager', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'ghostMgr', '--name', 'x', '--provider', 'CoinbaseCDP', + '--api-key-id', 'a', '--api-key-secret', 'b', '--wallet-secret', 'c', '--json'], + projectPath + ); + expect(result.exitCode).toBe(1); + const json = parseJsonOutput(result.stdout) as { success: boolean; error: string }; + expect(json.error).toContain('not found'); + }); + + // ── Remove lifecycle ────────────────────────────────────────────────────── + + it.skipIf(!canRun)('add CDP connector for remove testing', async () => { + const result = await runAgentCoreCLI( + ['add', 'payment-connector', '--manager', 'cfgMgr', '--name', 'cdpConn', '--provider', 'CoinbaseCDP', + '--api-key-id', 'key-id', '--api-key-secret', 'key-secret', '--wallet-secret', 'wallet-secret', '--json'], + projectPath + ); + expect(result.exitCode).toBe(0); + }); + + it.skipIf(!canRun)('remove connector cleans env vars', async () => { + const result = await runAgentCoreCLI( + ['remove', 'payment-connector', '--manager', 'cfgMgr', '--name', 'cdpConn', '--yes', '--json'], + projectPath + ); + expect(result.exitCode).toBe(0); + + const envContent = await readFile(join(projectPath, 'agentcore', '.env.local'), 'utf-8'); + expect(envContent).not.toContain('CDPCONN_CDP_API_KEY_ID'); + }); + + it.skipIf(!canRun)('remove manager cascades (removes remaining connectors + env vars)', async () => { + const result = await runAgentCoreCLI( + ['remove', 'payment-manager', '--name', 'cfgMgr', '--yes', '--json'], + projectPath + ); + expect(result.exitCode).toBe(0); + + const config = JSON.parse(await readFile(join(projectPath, 'agentcore', 'agentcore.json'), 'utf-8')); + expect(config.payments).toEqual([]); + + const envContent = await readFile(join(projectPath, 'agentcore', '.env.local'), 'utf-8'); + expect(envContent.trim()).toBe(''); + }); +}); diff --git a/integ-tests/add-remove-payment.test.ts b/integ-tests/add-remove-payment.test.ts new file mode 100644 index 000000000..68d28c013 --- /dev/null +++ b/integ-tests/add-remove-payment.test.ts @@ -0,0 +1,511 @@ +import { createTestProject, readProjectConfig, runCLI } from '../src/test-utils/index.js'; +import type { TestProject } from '../src/test-utils/index.js'; +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +describe('integration: add and remove payment managers and connectors', () => { + let project: TestProject; + + beforeAll(async () => { + project = await createTestProject({ + language: 'Python', + framework: 'Strands', + modelProvider: 'Bedrock', + memory: 'none', + }); + }); + + afterAll(async () => { + await project.cleanup(); + }); + + describe('payment manager lifecycle', () => { + const managerName = `IntegMgr${Date.now().toString().slice(-6)}`; + + it('adds an AWS_IAM payment manager', async () => { + const result = await runCLI( + ['add', 'payment-manager', '--name', managerName, '--pattern', 'interceptor', '--json'], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + expect(json.managerName).toBe(managerName); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + expect(manager, `Payment manager "${managerName}" should be in config`).toBeTruthy(); + expect(manager!.authorizerType).toBe('AWS_IAM'); + expect(manager!.pattern).toBe('interceptor'); + expect(manager!.connectors).toEqual([]); + }); + + it('rejects duplicate payment manager name', async () => { + const result = await runCLI(['add', 'payment-manager', '--name', managerName, '--json'], project.projectPath); + + expect(result.exitCode).toBe(1); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(false); + expect(json.error).toContain('already exists'); + }); + + it('generates payment capability code for agents', async () => { + const config = await readProjectConfig(project.projectPath); + const agentName = config.runtimes?.[0]?.name; + expect(agentName).toBeTruthy(); + + const paymentsPath = join(project.projectPath, 'app', agentName!, 'capabilities', 'payments', 'payments.py'); + const paymentsCode = await readFile(paymentsPath, 'utf-8'); + expect(paymentsCode).toContain('create_payments_plugin'); + expect(paymentsCode).toContain('instrument_id'); + expect(paymentsCode).toContain('session_id'); + }); + + it('removes the payment manager', async () => { + const result = await runCLI( + ['remove', 'payment-manager', '--name', managerName, '--yes', '--json'], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const found = config.payments?.some((p: Record) => p.name === managerName); + expect(found, `Payment manager "${managerName}" should be removed`).toBeFalsy(); + }); + }); + + describe('CUSTOM_JWT payment manager', () => { + const jwtManagerName = `IntegJwt${Date.now().toString().slice(-6)}`; + + it('adds a CUSTOM_JWT payment manager with OIDC config', async () => { + const result = await runCLI( + [ + 'add', + 'payment-manager', + '--name', + jwtManagerName, + '--authorizer-type', + 'CUSTOM_JWT', + '--discovery-url', + 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_test/.well-known/openid-configuration', + '--allowed-clients', + 'client-1,client-2', + '--pattern', + 'interceptor', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === jwtManagerName); + expect(manager).toBeTruthy(); + expect(manager!.authorizerType).toBe('CUSTOM_JWT'); + expect((manager as any).authorizerConfiguration?.customJWTAuthorizer?.discoveryUrl).toContain( + 'openid-configuration' + ); + expect((manager as any).authorizerConfiguration?.customJWTAuthorizer?.allowedClients).toEqual([ + 'client-1', + 'client-2', + ]); + }); + + it('rejects CUSTOM_JWT without discovery-url', async () => { + const result = await runCLI( + ['add', 'payment-manager', '--name', 'noUrl', '--authorizer-type', 'CUSTOM_JWT', '--json'], + project.projectPath + ); + + expect(result.exitCode).toBe(1); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(false); + expect(json.error).toContain('--discovery-url is required'); + }); + + afterAll(async () => { + await runCLI(['remove', 'payment-manager', '--name', jwtManagerName, '--yes'], project.projectPath); + }); + }); + + describe('payment connector lifecycle', () => { + const managerName = `IntegConnMgr${Date.now().toString().slice(-6)}`; + const connectorName1 = `IntegConn1${Date.now().toString().slice(-6)}`; + const connectorName2 = `IntegConn2${Date.now().toString().slice(-6)}`; + + beforeAll(async () => { + await runCLI(['add', 'payment-manager', '--name', managerName, '--pattern', 'interceptor'], project.projectPath); + }); + + it('adds a payment connector to the manager', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName1, + '--provider', + 'CoinbaseCDP', + '--api-key-id', + 'test-key-id', + '--api-key-secret', + 'test-key-secret', + '--wallet-secret', + 'test-wallet-secret', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + const connector = (manager?.connectors as Record[])?.find( + (c: Record) => c.name === connectorName1 + ); + expect(connector, `Connector "${connectorName1}" should be in manager's connectors`).toBeTruthy(); + + // Verify credential was created + const cred = config.credentials?.find( + (c: Record) => c.authorizerType === 'PaymentCredentialProvider' + ); + expect(cred, 'PaymentCredentialProvider credential should exist').toBeTruthy(); + }); + + it('stores CDP secrets in .env.local', async () => { + const envPath = join(project.projectPath, 'agentcore', '.env.local'); + const envContent = await readFile(envPath, 'utf-8'); + expect(envContent).toContain('API_KEY_ID'); + expect(envContent).toContain('API_KEY_SECRET'); + expect(envContent).toContain('WALLET_SECRET'); + }); + + it('adds a second connector to the same manager', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName2, + '--provider', + 'CoinbaseCDP', + '--api-key-id', + 'test-key-id-2', + '--api-key-secret', + 'test-key-secret-2', + '--wallet-secret', + 'test-wallet-secret-2', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + const connectors = manager?.connectors as Record[]; + expect(connectors?.length).toBe(2); + }); + + it('rejects duplicate connector name', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName1, + '--provider', + 'CoinbaseCDP', + '--api-key-id', + 'x', + '--api-key-secret', + 'y', + '--wallet-secret', + 'z', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode).toBe(1); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(false); + expect(json.error).toContain('already exists'); + }); + + it('rejects connector for non-existent manager', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + 'noSuchManager', + '--name', + 'x', + '--provider', + 'CoinbaseCDP', + '--api-key-id', + 'x', + '--api-key-secret', + 'y', + '--wallet-secret', + 'z', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode).toBe(1); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(false); + expect(json.error).toContain('not found'); + }); + + it('removes a single connector', async () => { + const result = await runCLI( + ['remove', 'payment-connector', '--manager', managerName, '--name', connectorName1, '--yes', '--json'], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + const connectors = manager?.connectors as Record[]; + expect(connectors?.length).toBe(1); + expect(connectors[0]?.name).toBe(connectorName2); + }); + + it('removes the manager with remaining connector', async () => { + const result = await runCLI( + ['remove', 'payment-manager', '--name', managerName, '--yes', '--json'], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + + const config = await readProjectConfig(project.projectPath); + const found = config.payments?.some((p: Record) => p.name === managerName); + expect(found).toBeFalsy(); + }); + }); + + describe('StripePrivy connector lifecycle', () => { + const managerName = `IntegSpMgr${Date.now().toString().slice(-6)}`; + const connectorName = `IntegSpConn${Date.now().toString().slice(-6)}`; + + beforeAll(async () => { + await runCLI(['add', 'payment-manager', '--name', managerName, '--pattern', 'interceptor'], project.projectPath); + }); + + it('adds a StripePrivy connector to the manager', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName, + '--provider', + 'StripePrivy', + '--app-id', + 'test-app-id', + '--app-secret', + 'test-app-secret', + '--authorization-private-key', + 'RkFLRV9TVFJJUEVfUFJJVllfVEVTVF9LRVlfQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==', + '--authorization-id', + 'test-auth-id', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + const connector = (manager?.connectors as Record[])?.find( + (c: Record) => c.name === connectorName + ); + expect(connector, `Connector "${connectorName}" should be in manager's connectors`).toBeTruthy(); + expect(connector!.provider).toBe('StripePrivy'); + + const cred = config.credentials?.find( + (c: Record) => c.authorizerType === 'PaymentCredentialProvider' && c.provider === 'StripePrivy' + ); + expect(cred, 'StripePrivy PaymentCredentialProvider credential should exist').toBeTruthy(); + }); + + it('stores StripePrivy secrets in .env.local', async () => { + const envPath = join(project.projectPath, 'agentcore', '.env.local'); + const envContent = await readFile(envPath, 'utf-8'); + expect(envContent).toContain('APP_ID'); + expect(envContent).toContain('APP_SECRET'); + expect(envContent).toContain('AUTHORIZATION_PRIVATE_KEY'); + expect(envContent).toContain('AUTHORIZATION_ID'); + }); + + it('rejects duplicate StripePrivy connector name', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + connectorName, + '--provider', + 'StripePrivy', + '--app-id', + 'x', + '--app-secret', + 'y', + '--authorization-private-key', + 'RkFLRV9TVFJJUEVfUFJJVllfVEVTVF9LRVlfQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==', + '--authorization-id', + 'w', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode).toBe(1); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(false); + expect(json.error).toContain('already exists'); + }); + + it('rejects StripePrivy connector missing required credentials', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + managerName, + '--name', + 'incomplete', + '--provider', + 'StripePrivy', + '--app-id', + 'x', + '--json', + ], + project.projectPath + ); + + expect(result.exitCode).toBe(1); + }); + + it('removes the StripePrivy connector', async () => { + const result = await runCLI( + ['remove', 'payment-connector', '--manager', managerName, '--name', connectorName, '--yes', '--json'], + project.projectPath + ); + + expect(result.exitCode, `stdout: ${result.stdout}, stderr: ${result.stderr}`).toBe(0); + const json = JSON.parse(result.stdout); + expect(json.success).toBe(true); + + const config = await readProjectConfig(project.projectPath); + const manager = config.payments?.find((p: Record) => p.name === managerName); + const connectors = manager?.connectors as Record[]; + expect(connectors?.length).toBe(0); + }); + + afterAll(async () => { + await runCLI(['remove', 'payment-manager', '--name', managerName, '--yes'], project.projectPath); + }); + }); + + describe('validation', () => { + it('passes agentcore validate after add/remove lifecycle', async () => { + const result = await runCLI(['validate'], project.projectPath); + expect(result.exitCode).toBe(0); + }); + + it('rejects invalid authorizer type', async () => { + const result = await runCLI( + ['add', 'payment-manager', '--name', 'x', '--authorizer-type', 'INVALID', '--json'], + project.projectPath + ); + expect(result.exitCode).toBe(1); + }); + + it('rejects invalid pattern', async () => { + const result = await runCLI( + ['add', 'payment-manager', '--name', 'x', '--pattern', 'invalid', '--json'], + project.projectPath + ); + expect(result.exitCode).toBe(1); + }); + + it('rejects invalid provider', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--manager', + 'x', + '--name', + 'y', + '--provider', + 'INVALID', + '--api-key-id', + 'x', + '--api-key-secret', + 'y', + '--wallet-secret', + 'z', + '--json', + ], + project.projectPath + ); + expect(result.exitCode).toBe(1); + }); + + it('requires --manager for payment-connector', async () => { + const result = await runCLI( + [ + 'add', + 'payment-connector', + '--name', + 'x', + '--provider', + 'CoinbaseCDP', + '--api-key-id', + 'x', + '--api-key-secret', + 'y', + '--wallet-secret', + 'z', + ], + project.projectPath + ); + expect(result.exitCode).toBe(1); + }); + }); +}); diff --git a/package-lock.json b/package-lock.json index ad7990d80..77e8dd7d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -91,18 +91,55 @@ "constructs": "^10.0.0" } }, + "../agentcore-l3-cdk-constructs": { + "name": "@aws/agentcore-cdk", + "version": "0.1.0-alpha.21", + "extraneous": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sts": "^3.995.0", + "@aws-sdk/credential-providers": "^3.995.0", + "@smithy/shared-ini-file-loader": "^4.4.3", + "fflate": "^0.8.2", + "zod": "^4.3.5" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@secretlint/secretlint-rule-preset-recommend": "^11.3.0", + "@trivago/prettier-plugin-sort-imports": "6.0.0", + "@types/node": "^25.0.3", + "@typescript-eslint/eslint-plugin": "^8.50.0", + "@typescript-eslint/parser": "^8.50.0", + "@vitest/coverage-v8": "^4.1.1", + "aws-cdk-lib": "^2.248.0", + "constructs": "^10.4.4", + "eslint": "^10.0.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-security": "^4.0.0", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", + "prettier": "^3.7.4", + "secretlint": "^11.3.0", + "typescript": "^5", + "typescript-eslint": "^8.50.1", + "vitest": "^4.1.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "aws-cdk-lib": "^2.248.0", + "constructs": "^10.0.0" + } + }, "node_modules/@ag-ui/core": { "version": "0.0.52", - "resolved": "https://registry.npmjs.org/@ag-ui/core/-/core-0.0.52.tgz", - "integrity": "sha512-Xo0bUaNV56EqylzcrAuhUkQX7et7+SZIrqZZtEByGwEq/I1EHny6ZMkWHLkKR7UNi0FJZwJyhKYmKJS3B2SEgA==", "dependencies": { "zod": "^3.22.4" } }, "node_modules/@ag-ui/core/node_modules/zod": { "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -110,8 +147,6 @@ }, "node_modules/@alcalzone/ansi-tokenize": { "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.2.5.tgz", - "integrity": "sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -123,8 +158,6 @@ }, "node_modules/@alcalzone/ansi-tokenize/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -135,22 +168,16 @@ }, "node_modules/@aws-cdk/asset-awscli-v1": { "version": "2.2.273", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.273.tgz", - "integrity": "sha512-X57HYUtHt9BQrlrzUNcMyRsDUCoakYNnY6qh5lNwRCHPtQoTfXmuISkfLk0AjLkcbS5lw1LLTQFiQhTDXfiTvg==", "dev": true, "license": "Apache-2.0" }, "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.1.tgz", - "integrity": "sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==", "dev": true, "license": "Apache-2.0" }, "node_modules/@aws-cdk/aws-service-spec": { "version": "0.1.166", - "resolved": "https://registry.npmjs.org/@aws-cdk/aws-service-spec/-/aws-service-spec-0.1.166.tgz", - "integrity": "sha512-I5Dt7/39kLxBbG5hIpLKW+meOZPO0o7DX0dKfWqOFMYaYrsIC9thM4LT5T9f4D1vG/DTx/6LyF8e8a7donzKbg==", "license": "Apache-2.0", "dependencies": { "@aws-cdk/service-spec-types": "^0.0.232", @@ -159,8 +186,6 @@ }, "node_modules/@aws-cdk/aws-service-spec/node_modules/@aws-cdk/service-spec-types": { "version": "0.0.232", - "resolved": "https://registry.npmjs.org/@aws-cdk/service-spec-types/-/service-spec-types-0.0.232.tgz", - "integrity": "sha512-GcXA6PJw8fYb3anh8nFzrkPMd1728r2pxeWK21luUCDHgDCqOhqBSmvGbt/s8wH/lxI9CtQgDO+BEWhqEFwSCg==", "license": "Apache-2.0", "dependencies": { "@cdklabs/tskb": "^0.0.4" @@ -168,8 +193,6 @@ }, "node_modules/@aws-cdk/cdk-assets-lib": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@aws-cdk/cdk-assets-lib/-/cdk-assets-lib-1.4.2.tgz", - "integrity": "sha512-RFDITy2nC9LPckAVymApxtLl9wzI0arUh/2h9d2LAjl2zeiVASr89WpRK/bA1RhHw3ElypEMa052DIAzt3RimA==", "license": "Apache-2.0", "dependencies": { "@aws-cdk/cloud-assembly-api": "2.2.1", @@ -194,8 +217,6 @@ }, "node_modules/@aws-cdk/cli-plugin-contract": { "version": "2.182.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cli-plugin-contract/-/cli-plugin-contract-2.182.1.tgz", - "integrity": "sha512-T0VgSVe0uiOCLm79GD+kWba8T+dPRVixZW5eBSiT59h0dIOR7poqhm5lnjId/XPvetRd0tvqNLje6MXQ+3JWzw==", "license": "Apache-2.0", "peer": true, "engines": { @@ -204,8 +225,6 @@ }, "node_modules/@aws-cdk/cloud-assembly-api": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-api/-/cloud-assembly-api-2.2.1.tgz", - "integrity": "sha512-24ARpDQzF39UTickUgDH6RIs5otPG4aaKJZ93XUSNwiPSR9T+h7gXSF982+NZVYK+7SetQaqrVbm4lcF6dmXWw==", "bundleDependencies": [ "jsonschema", "semver" @@ -243,8 +262,6 @@ }, "node_modules/@aws-cdk/cloud-assembly-schema": { "version": "53.18.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-53.18.0.tgz", - "integrity": "sha512-/fa6rOpokkfa5tVIdhsaexQq5MVVTSsZSD1Tu45YcrdyGRusGrM9RlPMCPrwvMS1UfdVFBhcgO9dl9ODWAWOeQ==", "bundleDependencies": [ "jsonschema", "semver" @@ -279,8 +296,6 @@ }, "node_modules/@aws-cdk/cloudformation-diff": { "version": "2.186.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloudformation-diff/-/cloudformation-diff-2.186.0.tgz", - "integrity": "sha512-3NNyQHosDoFnEnOlU6SLg43uGuqR8NfoQpDw+nUL0OcXyrFOmQHV7pETxcwi9djvI1U0AHlwdKtjLnI4DwjNSA==", "license": "Apache-2.0", "dependencies": { "@aws-cdk/aws-service-spec": "^0.1.161", @@ -300,8 +315,6 @@ }, "node_modules/@aws-cdk/cx-api": { "version": "2.244.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/cx-api/-/cx-api-2.244.0.tgz", - "integrity": "sha512-QE1BRNaxKe3+BbH9etBMdVen1AJ555O4R1l0s3CRTP66sx8FW6qYRi1JukquwkEmpf61Oi5fAUNRf8W0IGIoig==", "bundleDependencies": [ "semver", "@aws-cdk/cloud-assembly-api" @@ -369,8 +382,6 @@ }, "node_modules/@aws-cdk/service-spec-types": { "version": "0.0.227", - "resolved": "https://registry.npmjs.org/@aws-cdk/service-spec-types/-/service-spec-types-0.0.227.tgz", - "integrity": "sha512-xQHO0xzItQN5mFxox1iX/0NxDkHMgCval2imn5uJeYh5BA6jwm5XkIVrtS4YaL0B3Eb3U3Q+tG8jK9fD/orGxg==", "license": "Apache-2.0", "dependencies": { "@cdklabs/tskb": "^0.0.4" @@ -378,8 +389,6 @@ }, "node_modules/@aws-cdk/toolkit-lib": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@aws-cdk/toolkit-lib/-/toolkit-lib-1.24.0.tgz", - "integrity": "sha512-tgtH0CJ8/N/CpT1/ebOBfUpxdAMSRsP9LTAjWfa+E0clX4Vuvx0w1J1bGYwtvKY9nQUbFIO4QfgNEHz8hVlMUA==", "license": "Apache-2.0", "dependencies": { "@aws-cdk/cdk-assets-lib": "^1", @@ -438,8 +447,6 @@ }, "node_modules/@aws-cdk/toolkit-lib/node_modules/@aws-cdk/cloud-assembly-api": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-api/-/cloud-assembly-api-2.2.2.tgz", - "integrity": "sha512-iiypKqfpHMqQ9z6Nwxx42Ha4NCevLVDQ8sphIbqHxSJE5kDe/DCzvh8b2HtlAshWjo44HMhYdfKNLR96S3T4sA==", "bundleDependencies": [ "jsonschema", "semver" @@ -477,8 +484,6 @@ }, "node_modules/@aws-cdk/toolkit-lib/node_modules/yaml": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", "license": "ISC", "engines": { "node": ">= 6" @@ -486,8 +491,6 @@ }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -500,8 +503,6 @@ }, "node_modules/@aws-crypto/crc32c": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", - "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -511,8 +512,6 @@ }, "node_modules/@aws-crypto/sha1-browser": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", - "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/supports-web-crypto": "^5.2.0", @@ -525,8 +524,6 @@ }, "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -537,8 +534,6 @@ }, "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -550,8 +545,6 @@ }, "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -563,8 +556,6 @@ }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", @@ -578,8 +569,6 @@ }, "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -590,8 +579,6 @@ }, "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -603,8 +590,6 @@ }, "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -616,8 +601,6 @@ }, "node_modules/@aws-crypto/sha256-js": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -630,8 +613,6 @@ }, "node_modules/@aws-crypto/supports-web-crypto": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -639,8 +620,6 @@ }, "node_modules/@aws-crypto/util": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", @@ -650,8 +629,6 @@ }, "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -662,8 +639,6 @@ }, "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -675,8 +650,6 @@ }, "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -688,8 +661,6 @@ }, "node_modules/@aws-sdk/client-application-signals": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-application-signals/-/client-application-signals-3.1037.0.tgz", - "integrity": "sha512-xnGVyIWU1SXNSnnARvU3U3sic0QWH0wek/X3WpXFCpOm0NBzbTablWiAszNDU9RCvg9KUDm6Wdp0T4jnodXhEg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -738,8 +709,6 @@ }, "node_modules/@aws-sdk/client-appsync": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-appsync/-/client-appsync-3.1036.0.tgz", - "integrity": "sha512-UHrQGSZyEz4ID83lhnC299LYlOT/gUVo5Sfp060Z1mKgE5KcXXwfl0m7jbZ5FfUF/FmV++SOZrA6Ij1yYuM8XA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -789,8 +758,6 @@ }, "node_modules/@aws-sdk/client-bedrock": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock/-/client-bedrock-3.1037.0.tgz", - "integrity": "sha512-XGuJ86vuuEsqp0Gq8fMCSMd/VNCwqTvKwFT99SU2OOLyNp31ChZ+LdIckJZl/A3jpUyZYpXjn7IxP/N/6UFiZA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -840,8 +807,6 @@ }, "node_modules/@aws-sdk/client-bedrock-agent": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agent/-/client-bedrock-agent-3.1037.0.tgz", - "integrity": "sha512-8Uc3zdwfxmjMrXb4qP69bByL054R+jWNaW3/Hq93E1jnag8vZz8YhJlz1x6jr1oXOoOLVErc1L/g8x0sMFZuRA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -890,8 +855,6 @@ }, "node_modules/@aws-sdk/client-bedrock-agentcore": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agentcore/-/client-bedrock-agentcore-3.1037.0.tgz", - "integrity": "sha512-8WmZulMmFnCWFuX2rDBoZdebCMmmrAi1VABsLgm4O73w3+s7tcON1YgspG9gTevuVRtOVdk1B6TLw2Mo8NBHSQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -944,8 +907,6 @@ }, "node_modules/@aws-sdk/client-bedrock-agentcore-control": { "version": "3.1039.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agentcore-control/-/client-bedrock-agentcore-control-3.1039.0.tgz", - "integrity": "sha512-YoJ1rYHikWbsBuTyjADxtYzD+PXmyR2X6NVWkX4AqUtZT1YJC1HW+BsFABlXfItsEOjss3kpsjQHnlMbiCBtig==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -995,8 +956,6 @@ }, "node_modules/@aws-sdk/client-bedrock-runtime": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1037.0.tgz", - "integrity": "sha512-Evla4DUdBf1pQpQa7pbfquj7jRaRktkI0qGoWBJBXWB9wQISzJ8OEI4sHugk/W6SF47C7hMP/o3Z/XBrfnejCw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1053,8 +1012,6 @@ }, "node_modules/@aws-sdk/client-bedrock-runtime/node_modules/@aws-sdk/token-providers": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1037.0.tgz", - "integrity": "sha512-csxa484KboWLs3f8jFQ5v9RwH8FVf0fQ+SO3GSXyu4Jtinhh4qXmOWLSVX30RBpB933dZaKGHGEXzEEY88NqRw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.5", @@ -1071,8 +1028,6 @@ }, "node_modules/@aws-sdk/client-bedrock/node_modules/@aws-sdk/token-providers": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1037.0.tgz", - "integrity": "sha512-csxa484KboWLs3f8jFQ5v9RwH8FVf0fQ+SO3GSXyu4Jtinhh4qXmOWLSVX30RBpB933dZaKGHGEXzEEY88NqRw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.5", @@ -1089,8 +1044,6 @@ }, "node_modules/@aws-sdk/client-cloudcontrol": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudcontrol/-/client-cloudcontrol-3.1036.0.tgz", - "integrity": "sha512-NabrgJpHzZtq4oIq7mHUtWhUgFPlgLQRxQpIoFTYXPEuGjpHqcxz9jYid9a8hCqjlAOUTbQwD/CbZqbBVA3LSg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1140,8 +1093,6 @@ }, "node_modules/@aws-sdk/client-cloudformation": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudformation/-/client-cloudformation-3.1037.0.tgz", - "integrity": "sha512-nLSwtmayv7tjjp6t8Lc20xZCeA+XJ5UzXvauQCnO3aRZVAxrgarQntZjS+eWlRYGRqLBjXSre4xL7XwUlObb2A==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1191,8 +1142,6 @@ }, "node_modules/@aws-sdk/client-cloudwatch-logs": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.1037.0.tgz", - "integrity": "sha512-W0TRDfyBikNR+DzOTBgBLT4TqVHCAasqx2Xu4G4PfTRCansUtEJRydq0CEVOpHlMfme4Va89O/r9sp/VoDsKRg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1244,8 +1193,6 @@ }, "node_modules/@aws-sdk/client-codebuild": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-codebuild/-/client-codebuild-3.1036.0.tgz", - "integrity": "sha512-9uD1Xiqn/BOvk2l5xwUAc5Ec6YLRMjTJf1c8jO9u1mI++iW+lpmCQKBrvK94fGAA778MUo2n/nVmSJubzCUVrA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1294,8 +1241,6 @@ }, "node_modules/@aws-sdk/client-cognito-identity": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.1037.0.tgz", - "integrity": "sha512-/BQAyz98JRQFg3E8de3fGGydIYnsFRd6Cla4+zkviOe641fLCG0ZkPIk9D22HSi8qy9XKx+zk6ed2PcLO8uuPw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1344,8 +1289,6 @@ }, "node_modules/@aws-sdk/client-cognito-identity-provider": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity-provider/-/client-cognito-identity-provider-3.1037.0.tgz", - "integrity": "sha512-w0HuaMNtzcj6bErBX8/TVGbOz0a8JNCzPHLMq2u/ll4uuxl9Xut0njuy7vyY0/pYCuNE+no4uq+yHwn8U3ptgw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1395,8 +1338,6 @@ }, "node_modules/@aws-sdk/client-ec2": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ec2/-/client-ec2-3.1036.0.tgz", - "integrity": "sha512-uX4Tob7pFxyuTXwnZ2ykFy+5JMAsmKHofpx0SiZV2AmfRtA2jvv1egSolSshACqR0eXJ32FI3EO3N50uGX1qTg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1447,8 +1388,6 @@ }, "node_modules/@aws-sdk/client-ecr": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecr/-/client-ecr-3.1036.0.tgz", - "integrity": "sha512-4+Q0nEoAsKD2A5LktgJBH4eBLJ8cS2FNKy4YpYPYC+y+kHHszGp82dkSYPI2pogXHj1+hFZ41WziQcMz9+SBBg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1498,8 +1437,6 @@ }, "node_modules/@aws-sdk/client-ecs": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ecs/-/client-ecs-3.1036.0.tgz", - "integrity": "sha512-Yfw5xf0kcX80xI8Zg4/0xWG+WSFSJ+z752TZ4UqjyoTQrp+DwBXigbyegSC68XsNlz+YIJYNKcuXxxmJrfdjig==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1549,8 +1486,6 @@ }, "node_modules/@aws-sdk/client-elastic-load-balancing-v2": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-elastic-load-balancing-v2/-/client-elastic-load-balancing-v2-3.1036.0.tgz", - "integrity": "sha512-nwEuh1hijoIAYhLPWcFi3ltidlN8EayqtrCkXbP3ggzszkHV0g1fO933f3Sr67Uuo9DlYdhdyLubECbAeTIE+w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1600,8 +1535,6 @@ }, "node_modules/@aws-sdk/client-iam": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.1036.0.tgz", - "integrity": "sha512-cVe1Cg9NnqirhJiJNeJ1K7PFQ7QLKnhcbdZDOa/+nPTZRW9LhAEgDyuNTRFKkLfKtkEOwcqGozmdi2Bk7eaLCA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1651,8 +1584,6 @@ }, "node_modules/@aws-sdk/client-kms": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-kms/-/client-kms-3.1036.0.tgz", - "integrity": "sha512-tpqED4Wxmwx3gKv4czaMBbptyoYYX/2KuJ/F3+ZUQ5xPimQ448Wrx6Ci0aOfnbBIKek8DIL24LdgYSoApgnHoQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1701,8 +1632,6 @@ }, "node_modules/@aws-sdk/client-lambda": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.1036.0.tgz", - "integrity": "sha512-1JwkI5NXsYrwyEhtBWb441c87DJAn+JFa1/7i1xtizuWX1ibEq9jQBGiz+eQfUZNkVMRnpIGiGDOETJobj+i9w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1756,8 +1685,6 @@ }, "node_modules/@aws-sdk/client-resource-groups-tagging-api": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-resource-groups-tagging-api/-/client-resource-groups-tagging-api-3.1037.0.tgz", - "integrity": "sha512-1+sv7vbSSRqVMBTvgFPFopXZ/SGdz3jP9aIHM8eOIuuZGYSmuqiXkNd7Ag5yxIQqEDO8sASevCqscEqN0f4OUw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1806,8 +1733,6 @@ }, "node_modules/@aws-sdk/client-route-53": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-route-53/-/client-route-53-3.1036.0.tgz", - "integrity": "sha512-xfIfxc6MV6sLa7nlNGdFQO/5f4KWWtnDtOJCrWa2ar7HBnQfz2WDG5vKh+MhuQL/ReUoPS0zQKWon7p9vEbDsA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1858,8 +1783,6 @@ }, "node_modules/@aws-sdk/client-s3": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1037.0.tgz", - "integrity": "sha512-DBmA1jAW8ST6C4srBxeL1/RLIir/d8WOm4s4mi59mGp6mBktHM59Kwb7GuURaCO60cotuce5zr0sKpMLPcBQyA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", @@ -1924,8 +1847,6 @@ }, "node_modules/@aws-sdk/client-secrets-manager": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.1036.0.tgz", - "integrity": "sha512-4Q0Rqh1CrNfwmAOrQF9FiuU2QmV51cTSa+rJJNan7/KzYUUlUFmavuWpKH+S3preT8iaTlCT0JyCqO46kg24RA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -1974,8 +1895,6 @@ }, "node_modules/@aws-sdk/client-sfn": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sfn/-/client-sfn-3.1036.0.tgz", - "integrity": "sha512-S03TS4nm3noq7tRW4FpUONLw7fihP/8WMmHk/xI4j1ywr91rJzl1aXMJZUfA9ttDqXc4fr6wz2MZ/L/UU5k+Sw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -2024,8 +1943,6 @@ }, "node_modules/@aws-sdk/client-ssm": { "version": "3.1036.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.1036.0.tgz", - "integrity": "sha512-MGUcW/ITX37ktOQpBI9T2x0bHt1KFi5z8FjkSRC8FrBezxyViMMRbvJcbU3sOojsRvFpZePUgfB4RkcYu7BAbg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -2075,8 +1992,6 @@ }, "node_modules/@aws-sdk/client-sts": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.1037.0.tgz", - "integrity": "sha512-Ye+BEvy1Fd/JtqfF1T9PiodIU52/Cd9sP4oBLnj8QQEyYRUcYG1OQ2xIFXF/gzAAMjfVN8HqGJo9LxdmScxZAQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -2126,8 +2041,6 @@ }, "node_modules/@aws-sdk/client-xray": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-xray/-/client-xray-3.1037.0.tgz", - "integrity": "sha512-cnic610qpFrbR3gNw0pFi6EFrkDhDJOHlOnQzpdjBQ38O3QXwkON6Kco8IyTs7TlyOr7HRmHnBiEYVDZrLVC0w==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -2176,8 +2089,6 @@ }, "node_modules/@aws-sdk/core": { "version": "3.974.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.7.tgz", - "integrity": "sha512-YhRC90ofz5oolTJZlA8voU/oUrCB2azi8Usx51k8hhB5LpWbYQMMXKUqSqkoL0Cru+RQJgWTHpAfEDDIwfUhJw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2201,8 +2112,6 @@ }, "node_modules/@aws-sdk/core/node_modules/@aws-sdk/xml-builder": { "version": "3.972.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.15.tgz", - "integrity": "sha512-PxMRlCFNiQnke9YR29vjFQwz4jq+6Q04rOVFeTDR2K7Qpv9h9FOWOxG+zJjageimYbWqE3bTuLjmryWHAWbvaA==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -2215,8 +2124,6 @@ }, "node_modules/@aws-sdk/core/node_modules/fast-xml-parser": { "version": "5.5.7", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.7.tgz", - "integrity": "sha512-LteOsISQ2GEiDHZch6L9hB0+MLoYVLToR7xotrzU0opCICBkxOPgHAy1HxAvtxfJNXDJpgAsQN30mkrfpO2Prg==", "funding": [ { "type": "github", @@ -2235,8 +2142,6 @@ }, "node_modules/@aws-sdk/crc64-nvme": { "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.7.tgz", - "integrity": "sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -2248,8 +2153,6 @@ }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { "version": "3.972.28", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.28.tgz", - "integrity": "sha512-UXhc4FfxbfNaIqycDnIZ+W8CMAoCtcJJfZkq+cWSUwQRN0V0d0uAoN2qCFyKZip8inlHeKJmNQsPliKKcElP8Q==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/nested-clients": "^3.997.3", @@ -2264,8 +2167,6 @@ }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.972.33", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.33.tgz", - "integrity": "sha512-bJV7eViSJV6GSuuN+VIdNVPdwPsNSf75BiC2v5alPrjR/OCcqgKwSZInKbDFz9mNeizldsyf67jt6YSIiv53Cw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2280,8 +2181,6 @@ }, "node_modules/@aws-sdk/credential-provider-http": { "version": "3.972.35", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.35.tgz", - "integrity": "sha512-x/BQGEIdq0oI+4WxLjKmnQvT7CnF9r8ezdGt7wXwxb7ckHXQz0Zmgxt8v3Ne0JaT3R5YefmuybHX6E8EnsDXyA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2301,8 +2200,6 @@ }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.37.tgz", - "integrity": "sha512-eUTpmWfd/BKsq9medhCRcu+GRAhFP2Zrn7/2jKDHHOOjCkhrMoTp/t4cEthqFoG7gE0VGp5wUxrXTdvBCmSmJg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2326,8 +2223,6 @@ }, "node_modules/@aws-sdk/credential-provider-login": { "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.37.tgz", - "integrity": "sha512-Ty68y8ISSC+g5Q3D0K8uAaoINwvfaOslnNpsF/LgVUxyosYXHawcK2yV4HLXDVugiTTYLQfJfcw0ce5meAGkKw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2345,8 +2240,6 @@ }, "node_modules/@aws-sdk/credential-provider-node": { "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.38.tgz", - "integrity": "sha512-BQ9XYnBDVxR2HuV5huXYQYF/PZMTsY+EnwfGnCU2cA8Zw63XpkOtPY8WqiMIZMQCrKPQQEiFURS/o9CIolRLqg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.33", @@ -2368,8 +2261,6 @@ }, "node_modules/@aws-sdk/credential-provider-process": { "version": "3.972.33", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.33.tgz", - "integrity": "sha512-yfjGksI9WQbdMObb0VeLXqzTLI+a0qXLJT9gCDiv0+X/xjPpI3mTz6a5FibrhpuEKIe0gSgvs3MaoFZy5cx4WA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2385,8 +2276,6 @@ }, "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.37.tgz", - "integrity": "sha512-fpwE+20ntpp3i9Xb9vUuQfXLDKYHH+5I2V+ZG96SX1nBzrruhy10RXDgmN7t1etOz3c55stlA3TeQASUA451NQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2404,8 +2293,6 @@ }, "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.37.tgz", - "integrity": "sha512-aryawqyebf+3WhAFNHfF62rekFpYtVcVN7dQ89qnAWsa4n5hJst8qBG6gXC24WHtW7Nnhkf9ScYnjwo0Brn3bw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2422,8 +2309,6 @@ }, "node_modules/@aws-sdk/credential-providers": { "version": "3.1037.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1037.0.tgz", - "integrity": "sha512-TPPoQzfNkWltNgjJn3RRY1S8VXffDvv49xGGs9K0DrYS9LZCLLsoHmSmShx9HQusPc/4Oz23rfRWTolCU19PdQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-cognito-identity": "3.1037.0", @@ -2453,8 +2338,6 @@ }, "node_modules/@aws-sdk/ec2-metadata-service": { "version": "3.1018.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/ec2-metadata-service/-/ec2-metadata-service-3.1018.0.tgz", - "integrity": "sha512-mb3RlD9JoTyhTYutFSscmsGKbNqYxtJUEabgOZMw7NJByXMRId72ogpZIRHC0ChFL5R+ev4zMyChYwDdxFxCQA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -2471,8 +2354,6 @@ }, "node_modules/@aws-sdk/eventstream-handler-node": { "version": "3.972.14", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.14.tgz", - "integrity": "sha512-m4X56gxG76/CKfxNVbOFuYwnAZcHgS6HOH8lgp15HoGHIAVTcZfZrXvcYzJFOMLEJgVn+JHBu6EiNV+xSNXXFg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2486,8 +2367,6 @@ }, "node_modules/@aws-sdk/lib-storage": { "version": "3.1018.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1018.0.tgz", - "integrity": "sha512-bAFWDZUktLleORG0CXtYkfzMcbIOsJXeGK6Pkq7XLbFjE0QQGze8Y0mH8x0R7ogMrWU43oGmUDG3cs0UsthTOw==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-endpoint": "^4.4.27", @@ -2508,8 +2387,6 @@ }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.10.tgz", - "integrity": "sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2526,8 +2403,6 @@ }, "node_modules/@aws-sdk/middleware-eventstream": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.10.tgz", - "integrity": "sha512-QUqLs7Af1II9X4fCRAu+EGHG3KHyOp4RkuLhRKoA3NuFlh6TL8i+zXBl8w2LUxqm44B/Kom45hgSlwA1SpTsXQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2541,8 +2416,6 @@ }, "node_modules/@aws-sdk/middleware-expect-continue": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.10.tgz", - "integrity": "sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2556,8 +2429,6 @@ }, "node_modules/@aws-sdk/middleware-flexible-checksums": { "version": "3.974.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.13.tgz", - "integrity": "sha512-b6QUe2hQX9XsnCzp6mtzVaERhganDKeb8lmGL6pVhr7rRVH9S9keDFW7uKytuuqmcY5943FixoGqn/QL+sbUBA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", @@ -2581,8 +2452,6 @@ }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz", - "integrity": "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2596,8 +2465,6 @@ }, "node_modules/@aws-sdk/middleware-location-constraint": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.10.tgz", - "integrity": "sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2610,8 +2477,6 @@ }, "node_modules/@aws-sdk/middleware-logger": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz", - "integrity": "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2624,8 +2489,6 @@ }, "node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz", - "integrity": "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2640,8 +2503,6 @@ }, "node_modules/@aws-sdk/middleware-sdk-ec2": { "version": "3.972.22", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-ec2/-/middleware-sdk-ec2-3.972.22.tgz", - "integrity": "sha512-i9BeGH8OIPXmDuu5VZEvq3QVzP2Upt0QJsW/0ziS873CJ+zFiCyobiqQ3QTgJpxIsBBXBswsRQajEG+PvuKxYg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2659,8 +2520,6 @@ }, "node_modules/@aws-sdk/middleware-sdk-route53": { "version": "3.972.12", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-route53/-/middleware-sdk-route53-3.972.12.tgz", - "integrity": "sha512-nj08j4q/Rp8zb3SqwxE+dex22NdXoSKJAh445x0SLGAI23lYfDTujFDG1JRYLRc1uR2/FPPr76L/ki/VE4J9ig==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2673,8 +2532,6 @@ }, "node_modules/@aws-sdk/middleware-sdk-s3": { "version": "3.972.36", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.36.tgz", - "integrity": "sha512-YhPix+0x/MdQrb1Ug1GDKeS5fqylIy+naz800asX8II4jqfTk2KY2KhmmYCwZcky8YWtRQQwWCGdoqeAnip8Uw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2698,8 +2555,6 @@ }, "node_modules/@aws-sdk/middleware-ssec": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.10.tgz", - "integrity": "sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2712,8 +2567,6 @@ }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.37.tgz", - "integrity": "sha512-N1oNpdiLoVAWYD3WFBnUi3LlfoDA06ZHo4ozyjbsJNLvILzvt//0CnR8N+CZ0NWeYgVB/5V59ivixHCWCx2ALw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2731,8 +2584,6 @@ }, "node_modules/@aws-sdk/middleware-websocket": { "version": "3.972.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.16.tgz", - "integrity": "sha512-86+S9oCyRVGzoMRpQhxkArp7kD2K75GPmaNevd9B6EyNhWoNvnCZZ3WbgN4j7ZT+jvtvBCGZvI2XHsWZJ+BRIg==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2754,8 +2605,6 @@ }, "node_modules/@aws-sdk/nested-clients": { "version": "3.997.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.5.tgz", - "integrity": "sha512-jGFr6DxtcMTmzOkG/a0jCZYv4BBDmeNYVeO+/memSoDkYCJu4Y58xviYmzwJfYyIVSts+X/BVjJm1uGBnwHEMg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -2804,8 +2653,6 @@ }, "node_modules/@aws-sdk/region-config-resolver": { "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz", - "integrity": "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2820,8 +2667,6 @@ }, "node_modules/@aws-sdk/signature-v4-multi-region": { "version": "3.996.24", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.24.tgz", - "integrity": "sha512-amP7tLikppN940wbBFISYqiuzVmpzMS9U3mcgtmVLjX4fdWI/SNCvrXv6ZxfVzTT4cT0rPKOLhFah2xLwzREWw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.36", @@ -2837,8 +2682,6 @@ }, "node_modules/@aws-sdk/token-providers": { "version": "3.1039.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1039.0.tgz", - "integrity": "sha512-NMSFL2HwkAOoCeLCQiqoOq5pT3vVbSjww2QZTuYgYknVwhhv125PSDzZIcL5EYnlxuPWjEOdauZK+FspkZDVdw==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.974.7", @@ -2855,8 +2698,6 @@ }, "node_modules/@aws-sdk/types": { "version": "3.973.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", - "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -2868,8 +2709,6 @@ }, "node_modules/@aws-sdk/util-arn-parser": { "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.3.tgz", - "integrity": "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2880,8 +2719,6 @@ }, "node_modules/@aws-sdk/util-endpoints": { "version": "3.996.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz", - "integrity": "sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2896,8 +2733,6 @@ }, "node_modules/@aws-sdk/util-format-url": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.10.tgz", - "integrity": "sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2911,8 +2746,6 @@ }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.965.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", - "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -2923,8 +2756,6 @@ }, "node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz", - "integrity": "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.8", @@ -2935,8 +2766,6 @@ }, "node_modules/@aws-sdk/util-user-agent-node": { "version": "3.973.23", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.23.tgz", - "integrity": "sha512-gGwq8L2Euw0aNG6Ey4EktiAo3fSCVoDy1CaBIthd+oeaKHPXUrNaApMewQ6La5Hv0lcznOtECZaNvYyc5LXXfA==", "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.37", @@ -2982,8 +2811,6 @@ }, "node_modules/@aws/lambda-invoke-store": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", - "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -2991,15 +2818,11 @@ }, "node_modules/@azu/format-text": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", - "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@azu/style-format": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", - "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", "dev": true, "license": "WTFPL", "dependencies": { @@ -3008,8 +2831,6 @@ }, "node_modules/@babel/code-frame": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -3022,8 +2843,6 @@ }, "node_modules/@babel/compat-data": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3031,8 +2850,6 @@ }, "node_modules/@babel/core": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -3061,8 +2878,6 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3070,8 +2885,6 @@ }, "node_modules/@babel/generator": { "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -3086,8 +2899,6 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", @@ -3102,8 +2913,6 @@ }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -3111,8 +2920,6 @@ }, "node_modules/@babel/helper-globals": { "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3120,8 +2927,6 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -3133,8 +2938,6 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", @@ -3150,8 +2953,6 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3159,8 +2960,6 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3168,8 +2967,6 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3177,8 +2974,6 @@ }, "node_modules/@babel/helpers": { "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -3190,8 +2985,6 @@ }, "node_modules/@babel/parser": { "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -3205,8 +2998,6 @@ }, "node_modules/@babel/template": { "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -3219,8 +3010,6 @@ }, "node_modules/@babel/traverse": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -3237,8 +3026,6 @@ }, "node_modules/@babel/types": { "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -3250,8 +3037,6 @@ }, "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": { @@ -3260,665 +3045,172 @@ }, "node_modules/@cdklabs/tskb": { "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@cdklabs/tskb/-/tskb-0.0.4.tgz", - "integrity": "sha512-NFx1X0l7p5DyHtLLEyNeh1hPN4UN9hTkZkzFs/Mp+kFk7dpdINGmGVpCfRDjJ2DrcNSNENUmT+w8g73TvmBbTw==", "license": "Apache-2.0" }, "node_modules/@commander-js/extra-typings": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", - "integrity": "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg==", "license": "MIT", "peerDependencies": { "commander": "~14.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": { + "node_modules/@esbuild/darwin-arm64": { "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "darwin" ], "engines": { "node": ">=18" } }, - "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, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "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/@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, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "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" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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" - ], + "node_modules/@eslint/core": { + "version": "0.17.0", + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "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" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.14.0", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "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/@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, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">= 4" } }, - "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, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "9.39.4", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "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" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "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" - ], + "node_modules/@hono/node-server": { + "version": "1.19.13", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "engines": { - "node": ">=18" - } - }, - "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" - ], - "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==", - "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==", - "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==", - "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-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "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==", - "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==", - "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==", - "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/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/@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==", - "license": "MIT" - }, - "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==", - "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==", - "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==", - "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/@hono/node-server": { - "version": "1.19.13", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.13.tgz", - "integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" + "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==", "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -3926,8 +3218,6 @@ }, "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==", "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -3939,8 +3229,6 @@ }, "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==", "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -3952,8 +3240,6 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -3965,8 +3251,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -3975,8 +3259,6 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3985,8 +3267,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -3994,14 +3274,10 @@ }, "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==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -4010,8 +3286,6 @@ }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4049,29 +3323,8 @@ } } }, - "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/@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", @@ -4083,8 +3336,6 @@ }, "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" @@ -4092,8 +3343,6 @@ }, "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", @@ -4105,8 +3354,6 @@ }, "node_modules/@opentelemetry/api": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", "license": "Apache-2.0", "engines": { "node": ">=8.0.0" @@ -4114,8 +3361,6 @@ }, "node_modules/@opentelemetry/api-logs": { "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.213.0.tgz", - "integrity": "sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.3.0" @@ -4126,8 +3371,6 @@ }, "node_modules/@opentelemetry/core": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.1.tgz", - "integrity": "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4141,8 +3384,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.215.0.tgz", - "integrity": "sha512-FRydO5j7MWnXK9ghfykKxiSM8I5UeiicK/UNl3/mv86xoEKkb+LKz1I3WXgkuYVOQf22VNqbPO58s2W1mVWtEQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4160,8 +3401,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/api-logs": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.215.0.tgz", - "integrity": "sha512-xrFlqhdhUyO8wSRn6DjE0145/HPWSJ5Nm0C7vWua6TdL/FSEAZvEyvdsa9CRXuxo9ebb7j/NEPhEcO62IJ0qUA==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.3.0" @@ -4172,8 +3411,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/core": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.0.tgz", - "integrity": "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4187,8 +3424,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/otlp-transformer": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.215.0.tgz", - "integrity": "sha512-cWwBvaV+vkXHkSoTYR8hGw+AW03UlgTr6xtrUKOMeum3T+8vffYXIfXu6KY5MLu8O9QtoBKqaKWw9I5xoOepng==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.215.0", @@ -4208,8 +3443,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/resources": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.0.tgz", - "integrity": "sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4224,8 +3457,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-logs": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.215.0.tgz", - "integrity": "sha512-y3ucOmphzc4vgBTyIGchs+N/1rkACmoka8QalT2z1LBNM232Z17zMYayHcMl+dgMoOadZ0b72UZv7mDtqy1cFA==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.215.0", @@ -4242,8 +3473,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-metrics": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.0.tgz", - "integrity": "sha512-Vd7h95av/LYRsAVN7wbprvvJnHkq7swMXAo7Uad0Uxf9jl6NSReLa0JNivrcc5BVIx/vl2t+cgdVQQbnVhsR9w==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4258,8 +3487,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.0.tgz", - "integrity": "sha512-Yg9zEXJB50DLVLpsKPk7NmNqlPlS+OvqhJGh0A8oawIOTPOwlm4eXs9BMJV7L79lvEwI+dWtAj+YjTyddV336A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4275,8 +3502,6 @@ }, "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/protobufjs": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.2.0.tgz", - "integrity": "sha512-oI+GC9iPxrQEr6wragljFKH46/r3rNsm6eg7F2fp6kBUMnf6/mesDRdBuF4gK+OyaKJ8N4C1B9s9cCeYdqFikg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -4289,8 +3514,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.215.0.tgz", - "integrity": "sha512-lHrfbmeLSmesGSkkHiqDwOzfaEMSWXdc7q6UoLfbW8byONCb+bE/zkAr0kapN4US1baT/2nbpNT7Cn9XoB96Vg==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4305,8 +3528,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/api-logs": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.215.0.tgz", - "integrity": "sha512-xrFlqhdhUyO8wSRn6DjE0145/HPWSJ5Nm0C7vWua6TdL/FSEAZvEyvdsa9CRXuxo9ebb7j/NEPhEcO62IJ0qUA==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.3.0" @@ -4317,8 +3538,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/core": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.7.0.tgz", - "integrity": "sha512-DT12SXVwV2eoJrGf4nnsvZojxxeQo+LlNAsoYGRRObPWTeN6APiqZ2+nqDCQDvQX40eLi1AePONS0onoASp3yQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4332,8 +3551,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/otlp-transformer": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.215.0.tgz", - "integrity": "sha512-cWwBvaV+vkXHkSoTYR8hGw+AW03UlgTr6xtrUKOMeum3T+8vffYXIfXu6KY5MLu8O9QtoBKqaKWw9I5xoOepng==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.215.0", @@ -4353,8 +3570,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/resources": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.0.tgz", - "integrity": "sha512-K+oi0hNMv94EpZbnW3eyu2X6SGVpD3O5DhG2NIp65Hc7lhAj9brRXTAVzh3wB82+q3ThakEf7Zd7RsFUqcTc7A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4369,8 +3584,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/sdk-logs": { "version": "0.215.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.215.0.tgz", - "integrity": "sha512-y3ucOmphzc4vgBTyIGchs+N/1rkACmoka8QalT2z1LBNM232Z17zMYayHcMl+dgMoOadZ0b72UZv7mDtqy1cFA==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.215.0", @@ -4387,8 +3600,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/sdk-metrics": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.0.tgz", - "integrity": "sha512-Vd7h95av/LYRsAVN7wbprvvJnHkq7swMXAo7Uad0Uxf9jl6NSReLa0JNivrcc5BVIx/vl2t+cgdVQQbnVhsR9w==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4403,8 +3614,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/@opentelemetry/sdk-trace-base": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.7.0.tgz", - "integrity": "sha512-Yg9zEXJB50DLVLpsKPk7NmNqlPlS+OvqhJGh0A8oawIOTPOwlm4eXs9BMJV7L79lvEwI+dWtAj+YjTyddV336A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.0", @@ -4420,8 +3629,6 @@ }, "node_modules/@opentelemetry/otlp-exporter-base/node_modules/protobufjs": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.2.0.tgz", - "integrity": "sha512-oI+GC9iPxrQEr6wragljFKH46/r3rNsm6eg7F2fp6kBUMnf6/mesDRdBuF4gK+OyaKJ8N4C1B9s9cCeYdqFikg==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -4434,8 +3641,6 @@ }, "node_modules/@opentelemetry/otlp-transformer": { "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.213.0.tgz", - "integrity": "sha512-RSuAlxFFPjeK4d5Y6ps8L2WhaQI6CXWllIjvo5nkAlBpmq2XdYWEBGiAbOF4nDs8CX4QblJDv5BbMUft3sEfDw==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.213.0", @@ -4455,8 +3660,6 @@ }, "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/core": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", - "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4470,8 +3673,6 @@ }, "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.0.tgz", - "integrity": "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.6.0", @@ -4486,8 +3687,6 @@ }, "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-metrics": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.6.0.tgz", - "integrity": "sha512-CicxWZxX6z35HR83jl+PLgtFgUrKRQ9LCXyxgenMnz5A1lgYWfAog7VtdOvGkJYyQgMNPhXQwkYrDLujk7z1Iw==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.6.0", @@ -4502,8 +3701,6 @@ }, "node_modules/@opentelemetry/resources": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.7.1.tgz", - "integrity": "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.1", @@ -4518,8 +3715,6 @@ }, "node_modules/@opentelemetry/sdk-logs": { "version": "0.213.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.213.0.tgz", - "integrity": "sha512-00xlU3GZXo3kXKve4DLdrAL0NAFUaZ9appU/mn00S/5kSUdAvyYsORaDUfR04Mp2CLagAOhrzfUvYozY/EZX2g==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api-logs": "0.213.0", @@ -4536,8 +3731,6 @@ }, "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/core": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", - "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4551,8 +3744,6 @@ }, "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.0.tgz", - "integrity": "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.6.0", @@ -4567,8 +3758,6 @@ }, "node_modules/@opentelemetry/sdk-metrics": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.7.1.tgz", - "integrity": "sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.7.1", @@ -4583,8 +3772,6 @@ }, "node_modules/@opentelemetry/sdk-trace-base": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.0.tgz", - "integrity": "sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.6.0", @@ -4600,8 +3787,6 @@ }, "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/core": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.6.0.tgz", - "integrity": "sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" @@ -4615,8 +3800,6 @@ }, "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.6.0.tgz", - "integrity": "sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "2.6.0", @@ -4631,17 +3814,13 @@ }, "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.129.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz", - "integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==", + "version": "0.127.0", "dev": true, "license": "MIT", "funding": { @@ -4650,8 +3829,6 @@ }, "node_modules/@pkgr/core": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -4661,13 +3838,11 @@ } }, "node_modules/@playwright/test": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", - "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "version": "1.59.1", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.60.0" + "playwright": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -4678,342 +3853,74 @@ }, "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.5", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", "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.1", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", - "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", - "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.1", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", - "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", - "license": "BSD-3-Clause" - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz", - "integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", - "integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz", - "integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz", - "integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", - "integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", - "integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz", - "integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz", - "integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", - "integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", - "integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz", - "integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==", - "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.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz", - "integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==", - "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-win32-arm64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", - "integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "@protobufjs/inquire": "^1.1.0" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", - "integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==", + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.1", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ], "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz", - "integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==", + "version": "1.0.0-rc.17", "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==", "license": "MIT" }, "node_modules/@secretlint/config-creator": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-12.3.1.tgz", - "integrity": "sha512-CCRvPfrQLt2fPg3eWTIDGXNcVFQd6ZnvQCZ5lzclV9OF7iRqXQ4l5lfGO8NS68tIZx7YvBKhcO8/eVxdqm89HA==", "dev": true, "license": "MIT", "dependencies": { @@ -5025,8 +3932,6 @@ }, "node_modules/@secretlint/config-loader": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-12.3.1.tgz", - "integrity": "sha512-PNrxz8tnAU/y5PmfOtKfVb+zEA3I+1iZqP1f9fXvIBtauBKs0h0Y+Cmvj0gG1a34kxaD1aQvFh8qHEhRV05gWg==", "dev": true, "license": "MIT", "dependencies": { @@ -5043,8 +3948,6 @@ }, "node_modules/@secretlint/core": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-12.3.1.tgz", - "integrity": "sha512-ulcfARo1TANr8tWzDO/5cFxSNEEfRzgW6YPHYUijgpH3iYfwtUhWEU/r/BiFGl2PNaGzzVE1N9A6nZ74xbYvUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5059,8 +3962,6 @@ }, "node_modules/@secretlint/formatter": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-12.3.1.tgz", - "integrity": "sha512-SXpTiRzuuFNbHa59zk0eUxFOB/LYxnuHSfqq7zU9lIt0z5rox6NrnN9WWkoQai2V9s7n3VqUVUpZqnhxQ2Jzpw==", "dev": true, "license": "MIT", "dependencies": { @@ -5082,8 +3983,6 @@ }, "node_modules/@secretlint/formatter/node_modules/chalk": { "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { @@ -5095,8 +3994,6 @@ }, "node_modules/@secretlint/node": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-12.3.1.tgz", - "integrity": "sha512-1T08nqwWIJqSRrfkebk4Op5MwYgNnB6gwjv9v+X+V+HEIeG1GB/EgH8CJa8jK4uYdhUuaKyXpu36FIbjNa1wqA==", "dev": true, "license": "MIT", "dependencies": { @@ -5115,22 +4012,16 @@ }, "node_modules/@secretlint/profiler": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-12.3.1.tgz", - "integrity": "sha512-lztyqJPTfkY0Ze9P7vNs3zm7p2Wq1+4ilFXVrxin0sDyFVXpkt+0+vsKsmdx9yBHabxrLDZgxa7fIsfV721cLw==", "dev": true, "license": "MIT" }, "node_modules/@secretlint/resolver": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-12.3.1.tgz", - "integrity": "sha512-/QwcX5azKRdz9mBIbTBUsqp+cmWQZYGNdOHLbsMOBTLXa7KoEBffhmeaMSc0kNSrdgbgfu/7j+qeeaF4QwJf3A==", "dev": true, "license": "MIT" }, "node_modules/@secretlint/secretlint-rule-preset-recommend": { "version": "12.2.0", - "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-12.2.0.tgz", - "integrity": "sha512-n4qknL6vYRelmyrAyV/Z8I85c6jS6yF/ZxpgcqebjJuECIiel8OT2wIVIq9vk0MwlQN35skaQu0KvfM8uuGeyA==", "dev": true, "license": "MIT", "engines": { @@ -5139,8 +4030,6 @@ }, "node_modules/@secretlint/source-creator": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-12.3.1.tgz", - "integrity": "sha512-RCkmyKdoe6VFWMzzVm5a9W+a+ptJSusVX+YOrcNy/heklMIWLg0bL+HYFcyYCm8rU2dRq2HuSYTOamDjNs0LZg==", "dev": true, "license": "MIT", "dependencies": { @@ -5153,8 +4042,6 @@ }, "node_modules/@secretlint/types": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-12.3.1.tgz", - "integrity": "sha512-Qv3fKvPkzUJpS9Ps6m2EPjC0RdxS2ZZrRfZAhIdl2u0zSjgf+Z0+AaCngmHRR+3Vtbw6s2FrCf4T6mLirm8Hgg==", "dev": true, "license": "MIT", "engines": { @@ -5163,8 +4050,6 @@ }, "node_modules/@sindresorhus/merge-streams": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, "license": "MIT", "engines": { @@ -5176,8 +4061,6 @@ }, "node_modules/@smithy/chunked-blob-reader": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz", - "integrity": "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5188,8 +4071,6 @@ }, "node_modules/@smithy/chunked-blob-reader-native": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.3.tgz", - "integrity": "sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw==", "license": "Apache-2.0", "dependencies": { "@smithy/util-base64": "^4.3.2", @@ -5201,8 +4082,6 @@ }, "node_modules/@smithy/config-resolver": { "version": "4.4.17", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.17.tgz", - "integrity": "sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.14", @@ -5218,8 +4097,6 @@ }, "node_modules/@smithy/core": { "version": "3.23.17", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.17.tgz", - "integrity": "sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==", "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.14", @@ -5239,8 +4116,6 @@ }, "node_modules/@smithy/credential-provider-imds": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", - "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.14", @@ -5255,8 +4130,6 @@ }, "node_modules/@smithy/eventstream-codec": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.14.tgz", - "integrity": "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", @@ -5270,8 +4143,6 @@ }, "node_modules/@smithy/eventstream-serde-browser": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz", - "integrity": "sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==", "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.14", @@ -5284,8 +4155,6 @@ }, "node_modules/@smithy/eventstream-serde-config-resolver": { "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz", - "integrity": "sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5297,8 +4166,6 @@ }, "node_modules/@smithy/eventstream-serde-node": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz", - "integrity": "sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==", "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.14", @@ -5311,8 +4178,6 @@ }, "node_modules/@smithy/eventstream-serde-universal": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.14.tgz", - "integrity": "sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==", "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-codec": "^4.2.14", @@ -5325,8 +4190,6 @@ }, "node_modules/@smithy/fetch-http-handler": { "version": "5.3.17", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", - "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.14", @@ -5341,8 +4204,6 @@ }, "node_modules/@smithy/hash-blob-browser": { "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.15.tgz", - "integrity": "sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==", "license": "Apache-2.0", "dependencies": { "@smithy/chunked-blob-reader": "^5.2.2", @@ -5356,8 +4217,6 @@ }, "node_modules/@smithy/hash-node": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.14.tgz", - "integrity": "sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5371,8 +4230,6 @@ }, "node_modules/@smithy/hash-stream-node": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.14.tgz", - "integrity": "sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5385,8 +4242,6 @@ }, "node_modules/@smithy/invalid-dependency": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz", - "integrity": "sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5398,8 +4253,6 @@ }, "node_modules/@smithy/is-array-buffer": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", - "integrity": "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5410,8 +4263,6 @@ }, "node_modules/@smithy/md5-js": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.14.tgz", - "integrity": "sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5424,8 +4275,6 @@ }, "node_modules/@smithy/middleware-content-length": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz", - "integrity": "sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==", "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.14", @@ -5438,8 +4287,6 @@ }, "node_modules/@smithy/middleware-endpoint": { "version": "4.4.32", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.32.tgz", - "integrity": "sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.17", @@ -5457,8 +4304,6 @@ }, "node_modules/@smithy/middleware-retry": { "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.7.tgz", - "integrity": "sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.17", @@ -5478,8 +4323,6 @@ }, "node_modules/@smithy/middleware-serde": { "version": "4.2.20", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.20.tgz", - "integrity": "sha512-Lx9JMO9vArPtiChE3wbEZ5akMIDQpWQtlu90lhACQmNOXcGXRbaDywMHDzuDZ2OkZzP+9wQfZi3YJT9F67zTQQ==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.17", @@ -5493,8 +4336,6 @@ }, "node_modules/@smithy/middleware-stack": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz", - "integrity": "sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5506,8 +4347,6 @@ }, "node_modules/@smithy/node-config-provider": { "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz", - "integrity": "sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.14", @@ -5521,8 +4360,6 @@ }, "node_modules/@smithy/node-http-handler": { "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz", - "integrity": "sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==", "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.14", @@ -5536,8 +4373,6 @@ }, "node_modules/@smithy/property-provider": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.14.tgz", - "integrity": "sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5549,8 +4384,6 @@ }, "node_modules/@smithy/protocol-http": { "version": "5.3.14", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.14.tgz", - "integrity": "sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5562,8 +4395,6 @@ }, "node_modules/@smithy/querystring-builder": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.14.tgz", - "integrity": "sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5576,8 +4407,6 @@ }, "node_modules/@smithy/querystring-parser": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.14.tgz", - "integrity": "sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5589,8 +4418,6 @@ }, "node_modules/@smithy/service-error-classification": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.3.1.tgz", - "integrity": "sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1" @@ -5601,8 +4428,6 @@ }, "node_modules/@smithy/shared-ini-file-loader": { "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.9.tgz", - "integrity": "sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5614,8 +4439,6 @@ }, "node_modules/@smithy/signature-v4": { "version": "5.3.14", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", - "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", @@ -5633,8 +4456,6 @@ }, "node_modules/@smithy/smithy-client": { "version": "4.12.13", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.13.tgz", - "integrity": "sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA==", "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.17", @@ -5651,8 +4472,6 @@ }, "node_modules/@smithy/types": { "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", - "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5663,8 +4482,6 @@ }, "node_modules/@smithy/url-parser": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.14.tgz", - "integrity": "sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==", "license": "Apache-2.0", "dependencies": { "@smithy/querystring-parser": "^4.2.14", @@ -5677,8 +4494,6 @@ }, "node_modules/@smithy/util-base64": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz", - "integrity": "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.2", @@ -5691,8 +4506,6 @@ }, "node_modules/@smithy/util-body-length-browser": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz", - "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5703,8 +4516,6 @@ }, "node_modules/@smithy/util-body-length-node": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz", - "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5715,8 +4526,6 @@ }, "node_modules/@smithy/util-buffer-from": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", - "integrity": "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==", "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", @@ -5728,8 +4537,6 @@ }, "node_modules/@smithy/util-config-provider": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz", - "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5740,8 +4547,6 @@ }, "node_modules/@smithy/util-defaults-mode-browser": { "version": "4.3.49", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.49.tgz", - "integrity": "sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.14", @@ -5755,8 +4560,6 @@ }, "node_modules/@smithy/util-defaults-mode-node": { "version": "4.2.54", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.54.tgz", - "integrity": "sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw==", "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^4.4.17", @@ -5773,8 +4576,6 @@ }, "node_modules/@smithy/util-endpoints": { "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz", - "integrity": "sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.14", @@ -5787,8 +4588,6 @@ }, "node_modules/@smithy/util-hex-encoding": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz", - "integrity": "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5799,8 +4598,6 @@ }, "node_modules/@smithy/util-middleware": { "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.14.tgz", - "integrity": "sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5812,8 +4609,6 @@ }, "node_modules/@smithy/util-retry": { "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.6.tgz", - "integrity": "sha512-p6/FO1n2KxMeQyna067i0uJ6TSbb165ZhnRtCpWh4Foxqbfc6oW+XITaL8QkFJj3KFnDe2URt4gOhgU06EP9ew==", "license": "Apache-2.0", "dependencies": { "@smithy/service-error-classification": "^4.3.1", @@ -5826,8 +4621,6 @@ }, "node_modules/@smithy/util-stream": { "version": "4.5.25", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.25.tgz", - "integrity": "sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA==", "license": "Apache-2.0", "dependencies": { "@smithy/fetch-http-handler": "^5.3.17", @@ -5845,8 +4638,6 @@ }, "node_modules/@smithy/util-uri-escape": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz", - "integrity": "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5857,8 +4648,6 @@ }, "node_modules/@smithy/util-utf8": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz", - "integrity": "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==", "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.2", @@ -5870,8 +4659,6 @@ }, "node_modules/@smithy/util-waiter": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.3.0.tgz", - "integrity": "sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.1", @@ -5883,8 +4670,6 @@ }, "node_modules/@smithy/uuid": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz", - "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -5895,22 +4680,16 @@ }, "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/@textlint/ast-node-types": { "version": "15.6.1", - "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.6.1.tgz", - "integrity": "sha512-KXUhbpBctWkSumyNwFQBufwWCcjdxARGVnlH6AfERaFAnpi300L8og+l2Hs/bIqkXu26T5tIs7jNnRgUs20hmQ==", "dev": true, "license": "MIT" }, "node_modules/@textlint/linter-formatter": { "version": "15.6.1", - "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.6.1.tgz", - "integrity": "sha512-mrLdBQkySnUsznPCfOuzyZk3381bJoaK2hPzwmRvOqUeRm04SdPEqN3rkqnbeB4Vw61d1z6gM+kJSS0y8+Zmog==", "dev": true, "license": "MIT", "dependencies": { @@ -5932,8 +4711,6 @@ }, "node_modules/@textlint/linter-formatter/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==", "dev": true, "license": "MIT", "engines": { @@ -5942,15 +4719,11 @@ }, "node_modules/@textlint/linter-formatter/node_modules/pluralize": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", - "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", "dev": true, "license": "MIT" }, "node_modules/@textlint/linter-formatter/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==", "dev": true, "license": "MIT", "dependencies": { @@ -5962,22 +4735,16 @@ }, "node_modules/@textlint/module-interop": { "version": "15.6.1", - "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.6.1.tgz", - "integrity": "sha512-hrsG9S7dlTPoFQ9ImKCHt1I7uPGt25lBXoc/ENP0U47tETAsg8mwjwHBQ4SEEH/X+AXYIEg6+saPyKAj08Aa+Q==", "dev": true, "license": "MIT" }, "node_modules/@textlint/resolver": { "version": "15.6.1", - "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.6.1.tgz", - "integrity": "sha512-kC8MFJH9mIoTtw1IPupsl9k2KF/xj48ZqJoEfVmAqJ2yqd7gvvNRAgndOIBTZOLHDyFK1ouHpFPhW3ID/kNcmw==", "dev": true, "license": "MIT" }, "node_modules/@textlint/types": { "version": "15.6.1", - "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.6.1.tgz", - "integrity": "sha512-dRdyTAMRaqcU5eHpJWgTq9kcKGErs+cVVFwNTP3gUAFDJxEVxdOlJU2zjMgzJAzf/4WfOE6UJ56Mmn09acxmzw==", "dev": true, "license": "MIT", "dependencies": { @@ -5986,8 +4753,6 @@ }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", - "integrity": "sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6025,21 +4790,8 @@ } } }, - "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/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": { @@ -6049,8 +4801,6 @@ }, "node_modules/@types/debug": { "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -6058,21 +4808,15 @@ }, "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==", "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", "license": "MIT", "dependencies": { "@types/estree": "*" @@ -6080,8 +4824,6 @@ }, "node_modules/@types/hast": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -6089,27 +4831,19 @@ }, "node_modules/@types/js-yaml": { "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "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==", "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==", "license": "MIT" }, "node_modules/@types/mdast": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -6117,14 +4851,10 @@ }, "node_modules/@types/ms": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, "node_modules/@types/node": { "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "license": "MIT", "dependencies": { "undici-types": "~7.18.0" @@ -6132,15 +4862,11 @@ }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -6148,14 +4874,10 @@ }, "node_modules/@types/unist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz", - "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==", "dev": true, "license": "MIT", "dependencies": { @@ -6183,8 +4905,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz", - "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==", "dev": true, "license": "MIT", "dependencies": { @@ -6208,8 +4928,6 @@ }, "node_modules/@typescript-eslint/project-service": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz", - "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==", "license": "MIT", "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.2", @@ -6229,8 +4947,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz", - "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==", "license": "MIT", "dependencies": { "@typescript-eslint/types": "8.57.2", @@ -6246,8 +4962,6 @@ }, "node_modules/@typescript-eslint/tsconfig-utils": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz", - "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6262,8 +4976,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz", - "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==", "dev": true, "license": "MIT", "dependencies": { @@ -6287,393 +4999,109 @@ }, "node_modules/@typescript-eslint/types": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz", - "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==", - "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.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz", - "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.57.2", - "@typescript-eslint/tsconfig-utils": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/visitor-keys": "8.57.2", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.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.0.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz", - "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==", - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.2", - "@typescript-eslint/types": "8.57.2", - "@typescript-eslint/typescript-estree": "8.57.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.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz", - "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==", "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.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==", - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "license": "ISC" - }, - "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, + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.57.2", "license": "MIT", - "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" + "@typescript-eslint/project-service": "8.57.2", + "@typescript-eslint/tsconfig-utils": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/visitor-keys": "8.57.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": ">=14.0.0" + "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.0.0" } }, - "node_modules/@unrs/resolver-binding-wasm32-wasi/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, + "node_modules/@typescript-eslint/utils": { + "version": "8.57.2", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.57.2", + "@typescript-eslint/types": "8.57.2", + "@typescript-eslint/typescript-estree": "8.57.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.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, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.57.2", "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@typescript-eslint/types": "8.57.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/@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/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "license": "ISC" }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "node_modules/@unrs/resolver-binding-darwin-arm64": { "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" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ] }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.6.tgz", - "integrity": "sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.6", + "@vitest/utils": "4.1.5", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -6687,8 +5115,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.6", - "vitest": "4.1.6" + "@vitest/browser": "4.1.5", + "vitest": "4.1.5" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -6697,16 +5125,14 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", - "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -6715,13 +5141,11 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", - "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.6", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -6742,9 +5166,7 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", - "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { @@ -6755,13 +5177,11 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", - "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.6", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -6769,14 +5189,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", - "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -6785,9 +5203,7 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", - "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", + "version": "4.1.5", "dev": true, "license": "MIT", "funding": { @@ -6795,13 +5211,11 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", - "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.6", + "@vitest/pretty-format": "4.1.5", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -6811,8 +5225,6 @@ }, "node_modules/@xterm/headless": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@xterm/headless/-/headless-6.0.0.tgz", - "integrity": "sha512-5Yj1QINYCyzrZtf8OFIHi47iQtI+0qYFPHmouEfG8dHNxbZ9Tb9YGSuLcsEwj9Z+OL75GJqPyJbyoFer80a2Hw==", "dev": true, "license": "MIT", "workspaces": [ @@ -6821,8 +5233,6 @@ }, "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" @@ -6833,8 +5243,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -6847,8 +5255,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" @@ -6859,8 +5265,6 @@ }, "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==", "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -6868,8 +5272,6 @@ }, "node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -6884,8 +5286,6 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6902,8 +5302,6 @@ }, "node_modules/ansi-escapes": { "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "license": "MIT", "dependencies": { "environment": "^1.0.0" @@ -6917,8 +5315,6 @@ }, "node_modules/ansi-regex": { "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "license": "MIT", "engines": { "node": ">=12" @@ -6929,8 +5325,6 @@ }, "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" @@ -6944,8 +5338,6 @@ }, "node_modules/archiver": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", - "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", "license": "MIT", "dependencies": { "archiver-utils": "^5.0.2", @@ -6962,8 +5354,6 @@ }, "node_modules/archiver-utils": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", - "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", "license": "MIT", "dependencies": { "glob": "^10.0.0", @@ -6980,14 +5370,10 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -7002,8 +5388,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7024,8 +5408,6 @@ }, "node_modules/array.prototype.findlast": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -7044,8 +5426,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7065,8 +5445,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7083,8 +5461,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7101,8 +5477,6 @@ }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -7117,8 +5491,6 @@ }, "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==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -7138,8 +5510,6 @@ }, "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": { @@ -7148,8 +5518,6 @@ }, "node_modules/ast-v8-to-istanbul": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", - "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -7160,15 +5528,11 @@ }, "node_modules/ast-v8-to-istanbul/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/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "license": "MIT", "engines": { "node": ">=8" @@ -7176,14 +5540,10 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -7191,8 +5551,6 @@ }, "node_modules/auto-bind": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", - "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -7203,8 +5561,6 @@ }, "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==", "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -7218,8 +5574,6 @@ }, "node_modules/aws-cdk-lib": { "version": "2.250.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.250.0.tgz", - "integrity": "sha512-8U8/S9VcmKSc3MHZWiB7P0IecgXoohI8Ya3dgtZMgbzC4mB+MEQmsYBeNgm4vzGQdRos8HjQLnFX1IBlZh7jQA==", "bundleDependencies": [ "@balena/dockerignore", "@aws-cdk/cloud-assembly-api", @@ -7648,8 +6002,6 @@ }, "node_modules/b4a": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", - "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -7662,8 +6014,6 @@ }, "node_modules/bail": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "license": "MIT", "funding": { "type": "github", @@ -7672,8 +6022,6 @@ }, "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" @@ -7681,8 +6029,6 @@ }, "node_modules/bare-events": { "version": "2.8.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", - "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", "license": "Apache-2.0", "peerDependencies": { "bare-abort-controller": "*" @@ -7695,8 +6041,6 @@ }, "node_modules/bare-fs": { "version": "4.5.6", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.6.tgz", - "integrity": "sha512-1QovqDrR80Pmt5HPAsMsXTCFcDYr+NSUKW6nd6WO5v0JBmnItc/irNRzm2KOQ5oZ69P37y+AMujNyNtG+1Rggw==", "license": "Apache-2.0", "dependencies": { "bare-events": "^2.5.4", @@ -7719,8 +6063,6 @@ }, "node_modules/bare-os": { "version": "3.8.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.0.tgz", - "integrity": "sha512-Dc9/SlwfxkXIGYhvMQNUtKaXCaGkZYGcd1vuNUUADVqzu4/vQfvnMkYYOUnt2VwQ2AqKr/8qAVFRtwETljgeFg==", "license": "Apache-2.0", "engines": { "bare": ">=1.14.0" @@ -7728,8 +6070,6 @@ }, "node_modules/bare-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", - "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", "license": "Apache-2.0", "dependencies": { "bare-os": "^3.0.1" @@ -7737,8 +6077,6 @@ }, "node_modules/bare-stream": { "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.11.0.tgz", - "integrity": "sha512-Y/+iQ49fL3rIn6w/AVxI/2+BRrpmzJvdWt5Jv8Za6Ngqc6V227c+pYjYYgLdpR3MwQ9ObVXD0ZrqoBztakM0rw==", "license": "Apache-2.0", "dependencies": { "streamx": "^2.25.0", @@ -7763,8 +6101,6 @@ }, "node_modules/bare-url": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", - "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", "license": "Apache-2.0", "dependencies": { "bare-path": "^3.0.0" @@ -7772,8 +6108,6 @@ }, "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", @@ -7792,8 +6126,6 @@ }, "node_modules/baseline-browser-mapping": { "version": "2.10.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.11.tgz", - "integrity": "sha512-DAKrHphkJyiGuau/cFieRYhcTFeK/lBuD++C7cZ6KZHbMhBrisoi+EvhQ5RZrIfV5qwsW8kgQ07JIC+MDJRAhg==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -7804,8 +6136,6 @@ }, "node_modules/binaryextensions": { "version": "6.11.0", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", - "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", "dev": true, "license": "Artistic-2.0", "dependencies": { @@ -7820,8 +6150,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -7845,21 +6173,15 @@ }, "node_modules/boundary": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", - "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/bowser": { "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", "license": "MIT" }, "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" @@ -7870,8 +6192,6 @@ }, "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" @@ -7882,8 +6202,6 @@ }, "node_modules/browserslist": { "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -7915,8 +6233,6 @@ }, "node_modules/buffer": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "license": "MIT", "dependencies": { "base64-js": "^1.0.2", @@ -7925,8 +6241,6 @@ }, "node_modules/buffer-crc32": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", - "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", "license": "MIT", "engines": { "node": ">=8.0.0" @@ -7934,8 +6248,6 @@ }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", "engines": { @@ -7944,8 +6256,6 @@ }, "node_modules/call-bind": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -7962,8 +6272,6 @@ }, "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", @@ -7975,8 +6283,6 @@ }, "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", @@ -7991,8 +6297,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", "engines": { "node": ">=6" @@ -8000,8 +6304,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001781", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", - "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", "funding": [ { "type": "opencollective", @@ -8020,8 +6322,6 @@ }, "node_modules/ccount": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", "funding": { "type": "github", @@ -8030,14 +6330,10 @@ }, "node_modules/cdk-from-cfn": { "version": "0.295.0", - "resolved": "https://registry.npmjs.org/cdk-from-cfn/-/cdk-from-cfn-0.295.0.tgz", - "integrity": "sha512-HNQu3TfNTHZNlxh/o0XxhMMSt3uDFDtMxxO2wZGvZpHwvjZLLFSCHooMbMGj75vtyqNmqKxQdR9WQSTcW3oIpg==", "license": "MIT OR Apache-2.0" }, "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": { @@ -8046,8 +6342,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -8062,8 +6356,6 @@ }, "node_modules/character-entities": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "license": "MIT", "funding": { "type": "github", @@ -8072,8 +6364,6 @@ }, "node_modules/character-entities-html4": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "license": "MIT", "funding": { "type": "github", @@ -8082,8 +6372,6 @@ }, "node_modules/character-entities-legacy": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "license": "MIT", "funding": { "type": "github", @@ -8092,8 +6380,6 @@ }, "node_modules/character-reference-invalid": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "license": "MIT", "funding": { "type": "github", @@ -8102,8 +6388,6 @@ }, "node_modules/chokidar": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -8117,8 +6401,6 @@ }, "node_modules/cli-boxes": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "license": "MIT", "engines": { "node": ">=10" @@ -8129,8 +6411,6 @@ }, "node_modules/cli-cursor": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "license": "MIT", "dependencies": { "restore-cursor": "^4.0.0" @@ -8144,8 +6424,6 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "license": "MIT", "engines": { "node": ">=6" @@ -8156,8 +6434,6 @@ }, "node_modules/cli-truncate": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", - "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "license": "MIT", "dependencies": { "slice-ansi": "^8.0.0", @@ -8172,8 +6448,6 @@ }, "node_modules/cli-truncate/node_modules/string-width": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "license": "MIT", "dependencies": { "get-east-asian-width": "^1.5.0", @@ -8188,8 +6462,6 @@ }, "node_modules/code-excerpt": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", - "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", "license": "MIT", "dependencies": { "convert-to-spaces": "^2.0.1" @@ -8200,8 +6472,6 @@ }, "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" @@ -8212,21 +6482,15 @@ }, "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/colorette": { "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true, "license": "MIT" }, "node_modules/comma-separated-tokens": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "license": "MIT", "funding": { "type": "github", @@ -8235,8 +6499,6 @@ }, "node_modules/commander": { "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", "license": "MIT", "engines": { "node": ">=20" @@ -8244,8 +6506,6 @@ }, "node_modules/compress-commons": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", - "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", "license": "MIT", "dependencies": { "crc-32": "^1.2.0", @@ -8260,15 +6520,11 @@ }, "node_modules/constructs": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.6.0.tgz", - "integrity": "sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==", "dev": true, "license": "Apache-2.0" }, "node_modules/content-disposition": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", "dev": true, "license": "MIT", "engines": { @@ -8281,8 +6537,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -8291,14 +6545,10 @@ }, "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==", "license": "MIT" }, "node_modules/convert-to-spaces": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", - "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -8306,8 +6556,6 @@ }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -8316,8 +6564,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==", "dev": true, "license": "MIT", "engines": { @@ -8326,14 +6572,10 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, "node_modules/cors": { "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "dev": true, "license": "MIT", "dependencies": { @@ -8350,8 +6592,6 @@ }, "node_modules/crc-32": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" @@ -8362,8 +6602,6 @@ }, "node_modules/crc32-stream": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", - "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", "license": "MIT", "dependencies": { "crc-32": "^1.2.0", @@ -8375,8 +6613,6 @@ }, "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", @@ -8389,14 +6625,10 @@ }, "node_modules/csstype": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8412,8 +6644,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -8429,8 +6659,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8446,8 +6674,6 @@ }, "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" @@ -8463,8 +6689,6 @@ }, "node_modules/decode-named-character-reference": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -8476,14 +6700,10 @@ }, "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==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -8499,8 +6719,6 @@ }, "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==", "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -8516,8 +6734,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -8526,8 +6742,6 @@ }, "node_modules/dequal": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" @@ -8535,8 +6749,6 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -8545,8 +6757,6 @@ }, "node_modules/devlop": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "license": "MIT", "dependencies": { "dequal": "^2.0.0" @@ -8558,8 +6768,6 @@ }, "node_modules/diff": { "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -8567,8 +6775,6 @@ }, "node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -8579,8 +6785,6 @@ }, "node_modules/dotenv": { "version": "17.4.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.0.tgz", - "integrity": "sha512-kCKF62fwtzwYm0IGBNjRUjtJgMfGapII+FslMHIjMR5KTnwEmBmWLDRSnc3XSNP8bNy34tekgQyDT0hr7pERRQ==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -8591,8 +6795,6 @@ }, "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", @@ -8605,8 +6807,6 @@ }, "node_modules/editions": { "version": "6.22.0", - "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", - "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", "dev": true, "license": "Artistic-2.0", "dependencies": { @@ -8622,27 +6822,19 @@ }, "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==", "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.325", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.325.tgz", - "integrity": "sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==", "license": "ISC" }, "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/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -8651,8 +6843,6 @@ }, "node_modules/environment": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "license": "MIT", "engines": { "node": ">=18" @@ -8663,8 +6853,6 @@ }, "node_modules/es-abstract": { "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -8731,8 +6919,6 @@ }, "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" @@ -8740,8 +6926,6 @@ }, "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" @@ -8749,8 +6933,6 @@ }, "node_modules/es-iterator-helpers": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.1.tgz", - "integrity": "sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8777,15 +6959,11 @@ }, "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" @@ -8796,8 +6974,6 @@ }, "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", @@ -8811,8 +6987,6 @@ }, "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==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -8823,8 +6997,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7", @@ -8840,8 +7012,6 @@ }, "node_modules/es-toolkit": { "version": "1.45.1", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", - "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", "license": "MIT", "workspaces": [ "docs", @@ -8850,8 +7020,6 @@ }, "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", @@ -8892,8 +7060,6 @@ }, "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" @@ -8901,15 +7067,11 @@ }, "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==", "dev": true, "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==", "license": "MIT", "engines": { "node": ">=10" @@ -8920,8 +7082,6 @@ }, "node_modules/eslint": { "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", @@ -8979,8 +7139,6 @@ }, "node_modules/eslint-config-prettier": { "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "devOptional": true, "license": "MIT", "bin": { @@ -8995,8 +7153,6 @@ }, "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": { @@ -9020,8 +7176,6 @@ }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "license": "MIT", "dependencies": { "debug": "^3.2.7", @@ -9031,8 +7185,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==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -9040,8 +7192,6 @@ }, "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": { @@ -9075,8 +7225,6 @@ }, "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==", "license": "MIT", "dependencies": { "debug": "^3.2.7" @@ -9092,8 +7240,6 @@ }, "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==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -9101,8 +7247,6 @@ }, "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==", "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", @@ -9134,8 +7278,6 @@ }, "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==", "license": "MIT", "dependencies": { "ms": "^2.1.1" @@ -9143,8 +7285,6 @@ }, "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==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -9152,8 +7292,6 @@ }, "node_modules/eslint-plugin-prettier": { "version": "5.5.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", - "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.1", @@ -9182,8 +7320,6 @@ }, "node_modules/eslint-plugin-react": { "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "license": "MIT", "dependencies": { "array-includes": "^3.1.8", @@ -9214,8 +7350,6 @@ }, "node_modules/eslint-plugin-react-hooks": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", @@ -9233,8 +7367,6 @@ }, "node_modules/eslint-plugin-react-refresh": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", - "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9243,8 +7375,6 @@ }, "node_modules/eslint-plugin-react/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==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -9266,8 +7396,6 @@ }, "node_modules/eslint-plugin-react/node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -9275,8 +7403,6 @@ }, "node_modules/eslint-plugin-security": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-4.0.0.tgz", - "integrity": "sha512-tfuQT8K/Li1ZxhFzyD8wPIKtlzZxqBcPr9q0jFMQ77wWAbKBVEhaMPVQRTMTvCMUDhwBe5vPVqQPwAGk/ASfxQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -9291,8 +7417,6 @@ }, "node_modules/eslint-plugin-testing-library": { "version": "7.16.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-7.16.2.tgz", - "integrity": "sha512-8gleGnQXK2ZA3hHwjCwpYTZvM+9VsrJ+/9kDI8CjqAQGAdMQOdn/rJNu7ZySENuiWlGKQWyZJ4ZjEg2zamaRHw==", "license": "MIT", "dependencies": { "@typescript-eslint/scope-manager": "^8.56.0", @@ -9307,8 +7431,6 @@ }, "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==", "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -9323,8 +7445,6 @@ }, "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==", "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -9335,8 +7455,6 @@ }, "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==", "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -9351,8 +7469,6 @@ }, "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==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9363,8 +7479,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 4" @@ -9372,14 +7486,10 @@ }, "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==", "license": "MIT" }, "node_modules/espree": { "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -9395,8 +7505,6 @@ }, "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==", "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9407,8 +7515,6 @@ }, "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==", "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -9419,8 +7525,6 @@ }, "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==", "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -9431,8 +7535,6 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -9440,8 +7542,6 @@ }, "node_modules/estree-util-is-identifier-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", "license": "MIT", "funding": { "type": "opencollective", @@ -9450,8 +7550,6 @@ }, "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": { @@ -9460,8 +7558,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -9469,8 +7565,6 @@ }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", "engines": { @@ -9479,8 +7573,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" @@ -9488,15 +7580,11 @@ }, "node_modules/eventemitter3": { "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "dev": true, "license": "MIT" }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "license": "MIT", "engines": { "node": ">=0.8.x" @@ -9504,8 +7592,6 @@ }, "node_modules/events-universal": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", - "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", "license": "Apache-2.0", "dependencies": { "bare-events": "^2.7.0" @@ -9513,8 +7599,6 @@ }, "node_modules/eventsource": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "dev": true, "license": "MIT", "dependencies": { @@ -9526,8 +7610,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -9536,8 +7618,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": { @@ -9546,8 +7626,6 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", "dependencies": { @@ -9590,8 +7668,6 @@ }, "node_modules/express-rate-limit": { "version": "8.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.1.tgz", - "integrity": "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9609,32 +7685,22 @@ }, "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-diff": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "license": "Apache-2.0" }, "node_modules/fast-fifo": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -9649,8 +7715,6 @@ }, "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" @@ -9661,20 +7725,14 @@ }, "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==", "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==", "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -9689,8 +7747,6 @@ }, "node_modules/fast-xml-builder": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", - "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -9705,8 +7761,6 @@ }, "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" @@ -9714,8 +7768,6 @@ }, "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" @@ -9731,14 +7783,10 @@ }, "node_modules/fflate": { "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -9749,8 +7797,6 @@ }, "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" @@ -9761,8 +7807,6 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { @@ -9783,8 +7827,6 @@ }, "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==", "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -9799,8 +7841,6 @@ }, "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==", "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -9812,14 +7852,10 @@ }, "node_modules/flatted": { "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "license": "ISC" }, "node_modules/for-each": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -9833,8 +7869,6 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", "engines": { @@ -9843,8 +7877,6 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", "engines": { @@ -9853,8 +7885,6 @@ }, "node_modules/fs-extra": { "version": "11.3.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -9867,10 +7897,7 @@ }, "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": [ @@ -9882,8 +7909,6 @@ }, "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" @@ -9891,8 +7916,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -9911,8 +7934,6 @@ }, "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==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9920,8 +7941,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -9929,8 +7948,6 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -9938,8 +7955,6 @@ }, "node_modules/get-east-asian-width": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "license": "MIT", "engines": { "node": ">=18" @@ -9950,8 +7965,6 @@ }, "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", @@ -9974,8 +7987,6 @@ }, "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", @@ -9987,8 +7998,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -10004,8 +8013,6 @@ }, "node_modules/get-tsconfig": { "version": "4.13.7", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", - "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10017,8 +8024,6 @@ }, "node_modules/glob": { "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.2.2", @@ -10034,8 +8039,6 @@ }, "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==", "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -10046,8 +8049,6 @@ }, "node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "license": "MIT", "engines": { "node": ">=18" @@ -10058,8 +8059,6 @@ }, "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==", "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -10074,8 +8073,6 @@ }, "node_modules/globby": { "version": "16.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.0.tgz", - "integrity": "sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==", "dev": true, "license": "MIT", "dependencies": { @@ -10095,8 +8092,6 @@ }, "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" @@ -10107,14 +8102,10 @@ }, "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/handlebars": { "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "license": "MIT", "dependencies": { "minimist": "^1.2.5", @@ -10134,8 +8125,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10146,8 +8135,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=8" @@ -10155,8 +8142,6 @@ }, "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==", "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -10167,8 +8152,6 @@ }, "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==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.0" @@ -10182,8 +8165,6 @@ }, "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" @@ -10194,8 +8175,6 @@ }, "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" @@ -10209,8 +8188,6 @@ }, "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" @@ -10221,8 +8198,6 @@ }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -10248,8 +8223,6 @@ }, "node_modules/hast-util-whitespace": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -10261,14 +8234,10 @@ }, "node_modules/hermes-estree": { "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "license": "MIT", "dependencies": { "hermes-estree": "0.25.1" @@ -10276,8 +8245,6 @@ }, "node_modules/hono": { "version": "4.12.18", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", - "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", "dev": true, "license": "MIT", "engines": { @@ -10286,8 +8253,6 @@ }, "node_modules/hosted-git-info": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", - "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", "dev": true, "license": "ISC", "dependencies": { @@ -10299,8 +8264,6 @@ }, "node_modules/hosted-git-info/node_modules/lru-cache": { "version": "11.3.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", - "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -10309,15 +8272,11 @@ }, "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/html-url-attributes": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -10326,8 +8285,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -10347,8 +8304,6 @@ }, "node_modules/husky": { "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, "license": "MIT", "bin": { @@ -10363,8 +8318,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -10380,8 +8333,6 @@ }, "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", @@ -10400,8 +8351,6 @@ }, "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": { @@ -10410,8 +8359,6 @@ }, "node_modules/import-fresh": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -10426,8 +8373,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "license": "MIT", "engines": { "node": ">=0.8.19" @@ -10435,8 +8380,6 @@ }, "node_modules/indent-string": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "license": "MIT", "engines": { "node": ">=12" @@ -10447,8 +8390,6 @@ }, "node_modules/index-to-position": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", - "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", "dev": true, "license": "MIT", "engines": { @@ -10460,14 +8401,10 @@ }, "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/ink": { "version": "6.8.0", - "resolved": "https://registry.npmjs.org/ink/-/ink-6.8.0.tgz", - "integrity": "sha512-sbl1RdLOgkO9isK42WCZlJCFN9hb++sX9dsklOvfd1YQ3bQ2AiFu12Q6tFlr0HvEUvzraJntQCCpfEoUe9DSzA==", "license": "MIT", "dependencies": { "@alcalzone/ansi-tokenize": "^0.2.4", @@ -10515,8 +8452,6 @@ }, "node_modules/ink-link": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ink-link/-/ink-link-5.0.0.tgz", - "integrity": "sha512-TFDXc/0mwUW7LMjsr0/LeLxPVV5BnHDuDQff9RCgP4rb3R+V/4dIwGBZbCevcJZtQnVcW+Iz1LUrUbpq+UDwYA==", "license": "MIT", "dependencies": { "terminal-link": "^5.0.0" @@ -10533,8 +8468,6 @@ }, "node_modules/ink-spinner": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ink-spinner/-/ink-spinner-5.0.0.tgz", - "integrity": "sha512-EYEasbEjkqLGyPOUc8hBJZNuC5GvXGMLu0w5gdTNskPc7Izc5vO3tdQEYnzvshucyGCBXc86ig0ujXPMWaQCdA==", "license": "MIT", "dependencies": { "cli-spinners": "^2.7.0" @@ -10549,8 +8482,6 @@ }, "node_modules/ink-testing-library": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ink-testing-library/-/ink-testing-library-4.0.0.tgz", - "integrity": "sha512-yF92kj3pmBvk7oKbSq5vEALO//o7Z9Ck/OaLNlkzXNeYdwfpxMQkSowGTFUCS5MSu9bWfSZMewGpp7bFc66D7Q==", "dev": true, "license": "MIT", "engines": { @@ -10567,8 +8498,6 @@ }, "node_modules/ink/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -10579,8 +8508,6 @@ }, "node_modules/ink/node_modules/chalk": { "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -10591,20 +8518,14 @@ }, "node_modules/ink/node_modules/emoji-regex": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "license": "MIT" }, "node_modules/ink/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" }, "node_modules/ink/node_modules/string-width": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "license": "MIT", "dependencies": { "get-east-asian-width": "^1.5.0", @@ -10619,8 +8540,6 @@ }, "node_modules/ink/node_modules/wrap-ansi": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", @@ -10636,8 +8555,6 @@ }, "node_modules/ink/node_modules/wrap-ansi/node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", @@ -10653,14 +8570,10 @@ }, "node_modules/inline-style-parser": { "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -10673,8 +8586,6 @@ }, "node_modules/ip-address": { "version": "10.2.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", - "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -10683,8 +8594,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -10693,8 +8602,6 @@ }, "node_modules/is-alphabetical": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", "funding": { "type": "github", @@ -10703,8 +8610,6 @@ }, "node_modules/is-alphanumerical": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "license": "MIT", "dependencies": { "is-alphabetical": "^2.0.0", @@ -10717,8 +8622,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -10734,8 +8637,6 @@ }, "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==", "license": "MIT", "dependencies": { "async-function": "^1.0.0", @@ -10753,8 +8654,6 @@ }, "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==", "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -10768,8 +8667,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -10784,8 +8681,6 @@ }, "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": { @@ -10794,8 +8689,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10806,8 +8699,6 @@ }, "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" @@ -10821,8 +8712,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10838,8 +8727,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -10854,8 +8741,6 @@ }, "node_modules/is-decimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "license": "MIT", "funding": { "type": "github", @@ -10864,8 +8749,6 @@ }, "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" @@ -10873,8 +8756,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -10888,8 +8769,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "license": "MIT", "dependencies": { "get-east-asian-width": "^1.3.1" @@ -10903,8 +8782,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -10922,8 +8799,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -10934,8 +8809,6 @@ }, "node_modules/is-hexadecimal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", "funding": { "type": "github", @@ -10944,8 +8817,6 @@ }, "node_modules/is-in-ci": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-2.0.0.tgz", - "integrity": "sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==", "license": "MIT", "bin": { "is-in-ci": "cli.js" @@ -10959,8 +8830,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10971,8 +8840,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -10983,8 +8850,6 @@ }, "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" @@ -10992,8 +8857,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -11008,8 +8871,6 @@ }, "node_modules/is-path-inside": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", - "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", "dev": true, "license": "MIT", "engines": { @@ -11021,8 +8882,6 @@ }, "node_modules/is-plain-obj": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "license": "MIT", "engines": { "node": ">=12" @@ -11033,15 +8892,11 @@ }, "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==", "dev": true, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -11058,8 +8913,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -11070,8 +8923,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -11085,8 +8936,6 @@ }, "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" @@ -11097,8 +8946,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -11113,8 +8960,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -11130,8 +8975,6 @@ }, "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==", "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -11145,8 +8988,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -11157,8 +8998,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -11172,8 +9011,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -11188,20 +9025,14 @@ }, "node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "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": { @@ -11210,8 +9041,6 @@ }, "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": { @@ -11225,8 +9054,6 @@ }, "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": { @@ -11239,8 +9066,6 @@ }, "node_modules/istextorbinary": { "version": "9.5.0", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", - "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", "dev": true, "license": "Artistic-2.0", "dependencies": { @@ -11257,8 +9082,6 @@ }, "node_modules/iterator.prototype": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -11274,15 +9097,11 @@ }, "node_modules/javascript-natural-sort": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", "dev": true, "license": "MIT" }, "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==", "dev": true, "license": "MIT", "funding": { @@ -11291,14 +9110,10 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "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" @@ -11309,8 +9124,6 @@ }, "node_modules/jsesc": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -11321,33 +9134,23 @@ }, "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==", "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==", "dev": true, "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==", "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -11358,8 +9161,6 @@ }, "node_modules/jsonfile": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", - "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", "license": "MIT", "dependencies": { "universalify": "^2.0.0" @@ -11370,8 +9171,6 @@ }, "node_modules/jsx-ast-utils": { "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "license": "MIT", "dependencies": { "array-includes": "^3.1.6", @@ -11385,8 +9184,6 @@ }, "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==", "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -11394,8 +9191,6 @@ }, "node_modules/lazystream": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "license": "MIT", "dependencies": { "readable-stream": "^2.0.5" @@ -11406,14 +9201,10 @@ }, "node_modules/lazystream/node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "license": "MIT" }, "node_modules/lazystream/node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", @@ -11427,14 +9218,10 @@ }, "node_modules/lazystream/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/lazystream/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" @@ -11442,8 +9229,6 @@ }, "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==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -11455,8 +9240,6 @@ }, "node_modules/lightningcss": { "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -11483,31 +9266,8 @@ "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" ], @@ -11525,199 +9285,8 @@ "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/lint-staged": { "version": "16.4.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz", - "integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==", "dev": true, "license": "MIT", "dependencies": { @@ -11740,8 +9309,6 @@ }, "node_modules/listr2": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", "dev": true, "license": "MIT", "dependencies": { @@ -11758,8 +9325,6 @@ }, "node_modules/listr2/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -11771,15 +9336,11 @@ }, "node_modules/listr2/node_modules/emoji-regex": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, "license": "MIT" }, "node_modules/listr2/node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11796,8 +9357,6 @@ }, "node_modules/listr2/node_modules/wrap-ansi": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { @@ -11814,8 +9373,6 @@ }, "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==", "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -11829,33 +9386,23 @@ }, "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==", "dev": true, "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==", "license": "MIT" }, "node_modules/lodash.truncate": { "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "license": "MIT" }, "node_modules/log-update": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "license": "MIT", "dependencies": { @@ -11874,8 +9421,6 @@ }, "node_modules/log-update/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -11887,8 +9432,6 @@ }, "node_modules/log-update/node_modules/cli-cursor": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "license": "MIT", "dependencies": { @@ -11903,15 +9446,11 @@ }, "node_modules/log-update/node_modules/emoji-regex": { "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, "license": "MIT" }, "node_modules/log-update/node_modules/onetime": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11926,8 +9465,6 @@ }, "node_modules/log-update/node_modules/restore-cursor": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "license": "MIT", "dependencies": { @@ -11943,8 +9480,6 @@ }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, "license": "MIT", "dependencies": { @@ -11960,8 +9495,6 @@ }, "node_modules/log-update/node_modules/string-width": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11978,8 +9511,6 @@ }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { @@ -11996,14 +9527,10 @@ }, "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/longest-streak": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "license": "MIT", "funding": { "type": "github", @@ -12012,8 +9539,6 @@ }, "node_modules/loose-envify": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -12024,8 +9549,6 @@ }, "node_modules/lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -12033,8 +9556,6 @@ }, "node_modules/lucide-react": { "version": "0.575.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.575.0.tgz", - "integrity": "sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -12042,8 +9563,6 @@ }, "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": { @@ -12052,8 +9571,6 @@ }, "node_modules/magicast": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12064,8 +9581,6 @@ }, "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": { @@ -12080,8 +9595,6 @@ }, "node_modules/markdown-table": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "license": "MIT", "funding": { "type": "github", @@ -12090,8 +9603,6 @@ }, "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" @@ -12099,8 +9610,6 @@ }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12115,8 +9624,6 @@ }, "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", "engines": { "node": ">=12" @@ -12127,8 +9634,6 @@ }, "node_modules/mdast-util-from-markdown": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz", - "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12151,8 +9656,6 @@ }, "node_modules/mdast-util-gfm": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -12170,8 +9673,6 @@ }, "node_modules/mdast-util-gfm-autolink-literal": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12187,8 +9688,6 @@ }, "node_modules/mdast-util-gfm-footnote": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12204,8 +9703,6 @@ }, "node_modules/mdast-util-gfm-strikethrough": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12219,8 +9716,6 @@ }, "node_modules/mdast-util-gfm-table": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12236,8 +9731,6 @@ }, "node_modules/mdast-util-gfm-task-list-item": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12252,8 +9745,6 @@ }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -12270,8 +9761,6 @@ }, "node_modules/mdast-util-mdx-jsx": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -12294,8 +9783,6 @@ }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -12312,8 +9799,6 @@ }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12326,8 +9811,6 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -12347,8 +9830,6 @@ }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -12368,8 +9849,6 @@ }, "node_modules/mdast-util-to-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" @@ -12381,8 +9860,6 @@ }, "node_modules/media-typer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", "engines": { @@ -12391,8 +9868,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -12404,8 +9879,6 @@ }, "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" @@ -12413,8 +9886,6 @@ }, "node_modules/micromark": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -12448,8 +9919,6 @@ }, "node_modules/micromark-core-commonmark": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -12482,8 +9951,6 @@ }, "node_modules/micromark-extension-gfm": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", @@ -12502,8 +9969,6 @@ }, "node_modules/micromark-extension-gfm-autolink-literal": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", @@ -12518,8 +9983,6 @@ }, "node_modules/micromark-extension-gfm-footnote": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -12538,8 +10001,6 @@ }, "node_modules/micromark-extension-gfm-strikethrough": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -12556,8 +10017,6 @@ }, "node_modules/micromark-extension-gfm-table": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -12573,8 +10032,6 @@ }, "node_modules/micromark-extension-gfm-tagfilter": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" @@ -12586,8 +10043,6 @@ }, "node_modules/micromark-extension-gfm-task-list-item": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -12603,8 +10058,6 @@ }, "node_modules/micromark-factory-destination": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "funding": [ { "type": "GitHub Sponsors", @@ -12624,8 +10077,6 @@ }, "node_modules/micromark-factory-label": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "funding": [ { "type": "GitHub Sponsors", @@ -12646,8 +10097,6 @@ }, "node_modules/micromark-factory-space": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "funding": [ { "type": "GitHub Sponsors", @@ -12666,8 +10115,6 @@ }, "node_modules/micromark-factory-title": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "funding": [ { "type": "GitHub Sponsors", @@ -12688,8 +10135,6 @@ }, "node_modules/micromark-factory-whitespace": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "funding": [ { "type": "GitHub Sponsors", @@ -12710,8 +10155,6 @@ }, "node_modules/micromark-util-character": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "funding": [ { "type": "GitHub Sponsors", @@ -12730,8 +10173,6 @@ }, "node_modules/micromark-util-chunked": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "funding": [ { "type": "GitHub Sponsors", @@ -12749,8 +10190,6 @@ }, "node_modules/micromark-util-classify-character": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "funding": [ { "type": "GitHub Sponsors", @@ -12770,8 +10209,6 @@ }, "node_modules/micromark-util-combine-extensions": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "funding": [ { "type": "GitHub Sponsors", @@ -12790,8 +10227,6 @@ }, "node_modules/micromark-util-decode-numeric-character-reference": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "funding": [ { "type": "GitHub Sponsors", @@ -12809,8 +10244,6 @@ }, "node_modules/micromark-util-decode-string": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "funding": [ { "type": "GitHub Sponsors", @@ -12831,8 +10264,6 @@ }, "node_modules/micromark-util-encode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", "funding": [ { "type": "GitHub Sponsors", @@ -12847,8 +10278,6 @@ }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", "funding": [ { "type": "GitHub Sponsors", @@ -12863,8 +10292,6 @@ }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "funding": [ { "type": "GitHub Sponsors", @@ -12882,8 +10309,6 @@ }, "node_modules/micromark-util-resolve-all": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "funding": [ { "type": "GitHub Sponsors", @@ -12901,8 +10326,6 @@ }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "funding": [ { "type": "GitHub Sponsors", @@ -12922,8 +10345,6 @@ }, "node_modules/micromark-util-subtokenize": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -12944,8 +10365,6 @@ }, "node_modules/micromark-util-symbol": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", "funding": [ { "type": "GitHub Sponsors", @@ -12960,8 +10379,6 @@ }, "node_modules/micromark-util-types": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -12976,8 +10393,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", @@ -12989,8 +10404,6 @@ }, "node_modules/micromatch/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" @@ -13001,8 +10414,6 @@ }, "node_modules/mime": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "license": "MIT", "bin": { "mime": "cli.js" @@ -13013,8 +10424,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -13023,8 +10432,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==", "dev": true, "license": "MIT", "dependencies": { @@ -13040,8 +10447,6 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "license": "MIT", "engines": { "node": ">=6" @@ -13049,8 +10454,6 @@ }, "node_modules/mimic-function": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, "license": "MIT", "engines": { @@ -13062,8 +10465,6 @@ }, "node_modules/minimatch": { "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.2" @@ -13077,8 +10478,6 @@ }, "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" @@ -13086,8 +10485,6 @@ }, "node_modules/minipass": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" @@ -13095,14 +10492,10 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "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==", + "version": "3.3.11", "dev": true, "funding": [ { @@ -13120,8 +10513,6 @@ }, "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": { @@ -13136,14 +10527,10 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "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==", "dev": true, "license": "MIT", "engines": { @@ -13152,21 +10539,15 @@ }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "license": "MIT" }, "node_modules/node-addon-api": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, "license": "MIT" }, "node_modules/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==", "license": "MIT", "dependencies": { "array.prototype.flatmap": "^1.3.3", @@ -13183,8 +10564,6 @@ }, "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==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -13192,8 +10571,6 @@ }, "node_modules/node-pty": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0.tgz", - "integrity": "sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -13203,14 +10580,10 @@ }, "node_modules/node-releases": { "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "license": "MIT" }, "node_modules/normalize-package-data": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", - "integrity": "sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -13224,8 +10597,6 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13233,8 +10604,6 @@ }, "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" @@ -13242,8 +10611,6 @@ }, "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" @@ -13254,8 +10621,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" @@ -13263,8 +10628,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13283,8 +10646,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13298,8 +10659,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -13316,8 +10675,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -13330,8 +10687,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -13348,8 +10703,6 @@ }, "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", @@ -13359,8 +10712,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -13372,8 +10723,6 @@ }, "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==", "dev": true, "license": "ISC", "dependencies": { @@ -13382,8 +10731,6 @@ }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" @@ -13397,8 +10744,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -13414,8 +10759,6 @@ }, "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==", "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", @@ -13431,8 +10774,6 @@ }, "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" @@ -13446,8 +10787,6 @@ }, "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==", "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -13461,8 +10800,6 @@ }, "node_modules/p-map": { "version": "7.0.4", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", - "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", "engines": { @@ -13474,8 +10811,6 @@ }, "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==", "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -13486,8 +10821,6 @@ }, "node_modules/parse-entities": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { "@types/unist": "^2.0.0", @@ -13505,14 +10838,10 @@ }, "node_modules/parse-entities/node_modules/@types/unist": { "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, "node_modules/parse-imports-exports": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13521,8 +10850,6 @@ }, "node_modules/parse-json": { "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13539,8 +10866,6 @@ }, "node_modules/parse-json/node_modules/type-fest": { "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { @@ -13552,15 +10877,11 @@ }, "node_modules/parse-statements": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", "dev": true, "license": "MIT" }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", "engines": { @@ -13569,8 +10890,6 @@ }, "node_modules/patch-console": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", - "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -13578,8 +10897,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=8" @@ -13587,8 +10904,6 @@ }, "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", @@ -13602,8 +10917,6 @@ }, "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" @@ -13611,14 +10924,10 @@ }, "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-scurry": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", @@ -13633,8 +10942,6 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "11.3.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", - "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -13642,8 +10949,6 @@ }, "node_modules/path-to-regexp": { "version": "8.4.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.0.tgz", - "integrity": "sha512-PuseHIvAnz3bjrM2rGJtSgo1zjgxapTLZ7x2pjhzWwlp4SJQgK3f3iZIQwkpEnBaKz6seKBADpM4B4ySkuYypg==", "dev": true, "license": "MIT", "funding": { @@ -13653,21 +10958,15 @@ }, "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/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "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" @@ -13678,8 +10977,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -13687,13 +10984,11 @@ } }, "node_modules/playwright": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", - "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "version": "1.59.1", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0" + "playwright-core": "1.59.1" }, "bin": { "playwright": "cli.js" @@ -13706,9 +11001,7 @@ } }, "node_modules/playwright-core": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", - "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "version": "1.59.1", "dev": true, "license": "Apache-2.0", "bin": { @@ -13720,10 +11013,7 @@ }, "node_modules/playwright/node_modules/fsevents": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -13735,8 +11025,6 @@ }, "node_modules/pluralize": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", "engines": { @@ -13745,17 +11033,13 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", - "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "version": "8.5.10", "dev": true, "funding": [ { @@ -13783,8 +11067,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -13792,8 +11074,6 @@ }, "node_modules/prettier": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" @@ -13807,8 +11087,6 @@ }, "node_modules/prettier-linter-helpers": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", - "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" @@ -13819,8 +11097,6 @@ }, "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" @@ -13828,14 +11104,10 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, "node_modules/prop-types": { "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -13845,8 +11117,6 @@ }, "node_modules/property-information": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "license": "MIT", "funding": { "type": "github", @@ -13855,8 +11125,6 @@ }, "node_modules/protobufjs": { "version": "7.5.8", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.8.tgz", - "integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -13879,8 +11147,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -13893,8 +11159,6 @@ }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "engines": { "node": ">=6" @@ -13902,8 +11166,6 @@ }, "node_modules/qs": { "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -13918,8 +11180,6 @@ }, "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", @@ -13938,8 +11198,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -13948,8 +11206,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==", "dev": true, "license": "MIT", "dependencies": { @@ -13964,8 +11220,6 @@ }, "node_modules/rc-config-loader": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.4.tgz", - "integrity": "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13976,9 +11230,7 @@ } }, "node_modules/react": { - "version": "19.2.6", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", - "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "version": "19.2.5", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13986,8 +11238,6 @@ }, "node_modules/react-dom": { "version": "19.2.5", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", - "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" @@ -13998,14 +11248,10 @@ }, "node_modules/react-is": { "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, "node_modules/react-markdown": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -14031,8 +11277,6 @@ }, "node_modules/react-reconciler": { "version": "0.33.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.33.0.tgz", - "integrity": "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" @@ -14046,8 +11290,6 @@ }, "node_modules/read-pkg": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-10.1.0.tgz", - "integrity": "sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==", "dev": true, "license": "MIT", "dependencies": { @@ -14066,8 +11308,6 @@ }, "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", @@ -14082,8 +11322,6 @@ }, "node_modules/readable-stream/node_modules/buffer": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", "funding": [ { "type": "github", @@ -14106,8 +11344,6 @@ }, "node_modules/readdir-glob": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "license": "Apache-2.0", "dependencies": { "minimatch": "^5.1.0" @@ -14115,8 +11351,6 @@ }, "node_modules/readdirp": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -14128,8 +11362,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -14150,8 +11382,6 @@ }, "node_modules/regexp-tree": { "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", "dev": true, "license": "MIT", "bin": { @@ -14160,8 +11390,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -14180,8 +11408,6 @@ }, "node_modules/remark-gfm": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -14198,8 +11424,6 @@ }, "node_modules/remark-parse": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -14214,8 +11438,6 @@ }, "node_modules/remark-rehype": { "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -14231,8 +11453,6 @@ }, "node_modules/remark-stringify": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -14246,8 +11466,6 @@ }, "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" @@ -14255,8 +11473,6 @@ }, "node_modules/resolve": { "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -14275,8 +11491,6 @@ }, "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==", "license": "MIT", "engines": { "node": ">=4" @@ -14284,8 +11498,6 @@ }, "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": { @@ -14294,8 +11506,6 @@ }, "node_modules/restore-cursor": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "license": "MIT", "dependencies": { "onetime": "^5.1.0", @@ -14310,14 +11520,10 @@ }, "node_modules/restore-cursor/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" }, "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", @@ -14326,20 +11532,16 @@ }, "node_modules/rfdc": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, "license": "MIT" }, "node_modules/rolldown": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz", - "integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==", + "version": "1.0.0-rc.17", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.129.0", - "@rolldown/pluginutils": "1.0.0" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" @@ -14348,27 +11550,25 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0", - "@rolldown/binding-darwin-arm64": "1.0.0", - "@rolldown/binding-darwin-x64": "1.0.0", - "@rolldown/binding-freebsd-x64": "1.0.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", - "@rolldown/binding-linux-arm64-gnu": "1.0.0", - "@rolldown/binding-linux-arm64-musl": "1.0.0", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0", - "@rolldown/binding-linux-s390x-gnu": "1.0.0", - "@rolldown/binding-linux-x64-gnu": "1.0.0", - "@rolldown/binding-linux-x64-musl": "1.0.0", - "@rolldown/binding-openharmony-arm64": "1.0.0", - "@rolldown/binding-wasm32-wasi": "1.0.0", - "@rolldown/binding-win32-arm64-msvc": "1.0.0", - "@rolldown/binding-win32-x64-msvc": "1.0.0" + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14384,8 +11584,6 @@ }, "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", @@ -14407,8 +11605,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -14426,8 +11622,6 @@ }, "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", @@ -14446,8 +11640,6 @@ }, "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==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -14462,8 +11654,6 @@ }, "node_modules/safe-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, "license": "MIT", "dependencies": { @@ -14472,8 +11662,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -14489,21 +11677,15 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "license": "MIT" }, "node_modules/scheduler": { "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, "node_modules/secretlint": { "version": "12.3.1", - "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-12.3.1.tgz", - "integrity": "sha512-wv8TKCjU5hbBxo5jKEX8wIE78VAoL0Ux7pu18+TxtbICMZ2OCbu6EmO3OJLbUbyfUXSPVryNLNmGVgvwY6Z0xw==", "dev": true, "license": "MIT", "dependencies": { @@ -14525,8 +11707,6 @@ }, "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" @@ -14537,8 +11717,6 @@ }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14564,8 +11742,6 @@ }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", "dependencies": { @@ -14584,8 +11760,6 @@ }, "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==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -14601,8 +11775,6 @@ }, "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==", "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -14616,8 +11788,6 @@ }, "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==", "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -14630,15 +11800,11 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "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" @@ -14649,8 +11815,6 @@ }, "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" @@ -14658,8 +11822,6 @@ }, "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", @@ -14677,8 +11839,6 @@ }, "node_modules/side-channel-list": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -14693,8 +11853,6 @@ }, "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", @@ -14711,8 +11869,6 @@ }, "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", @@ -14730,15 +11886,11 @@ }, "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": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, "license": "ISC", "engines": { @@ -14750,8 +11902,6 @@ }, "node_modules/slash": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "license": "MIT", "engines": { @@ -14763,8 +11913,6 @@ }, "node_modules/slice-ansi": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", - "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", "license": "MIT", "dependencies": { "ansi-styles": "^6.2.3", @@ -14779,8 +11927,6 @@ }, "node_modules/slice-ansi/node_modules/ansi-styles": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "license": "MIT", "engines": { "node": ">=12" @@ -14791,8 +11937,6 @@ }, "node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -14800,8 +11944,6 @@ }, "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": { @@ -14810,8 +11952,6 @@ }, "node_modules/space-separated-tokens": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "license": "MIT", "funding": { "type": "github", @@ -14820,8 +11960,6 @@ }, "node_modules/spdx-correct": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14831,15 +11969,11 @@ }, "node_modules/spdx-exceptions": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -14849,15 +11983,11 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.23", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", - "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.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" @@ -14865,8 +11995,6 @@ }, "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": { @@ -14875,8 +12003,6 @@ }, "node_modules/stack-utils": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -14887,8 +12013,6 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "license": "MIT", "engines": { "node": ">=8" @@ -14896,456 +12020,105 @@ }, "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", - "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", - "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==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/stream-browserify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", - "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.4", - "readable-stream": "^3.5.0" - } - }, - "node_modules/stream-browserify/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/streamx": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", - "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", - "license": "MIT", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "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-width/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/string-width/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/string-width/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/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "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==", - "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==", - "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==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "license": "MIT", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "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==", - "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==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strnum": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", - "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, - "node_modules/structured-source": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", - "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boundary": "^2.0.0" - } - }, - "node_modules/style-to-js": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", - "license": "MIT", - "dependencies": { - "style-to-object": "1.0.14" - } - }, - "node_modules/style-to-object": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", + "version": "2.0.2", + "dev": true, "license": "MIT", - "dependencies": { - "inline-style-parser": "0.2.7" + "engines": { + "node": ">= 0.8" } }, - "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==", + "node_modules/std-env": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, - "node_modules/supports-hyperlinks": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.4.0.tgz", - "integrity": "sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==", + "node_modules/stream-browserify": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "has-flag": "^5.0.1", - "supports-color": "^10.2.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", - "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 6" } }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "node_modules/streamx": { + "version": "2.25.0", "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" } }, - "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==", + "node_modules/string_decoder": { + "version": "1.3.0", "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "node_modules/synckit": { - "version": "0.11.12", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", - "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "node_modules/string-argv": { + "version": "0.3.2", + "dev": true, "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.2.9" - }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" + "node": ">=0.6.19" } }, - "node_modules/table": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", - "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", - "license": "BSD-3-Clause", + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=8" } }, - "node_modules/table/node_modules/ansi-regex": { + "node_modules/string-width/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/table/node_modules/is-fullwidth-code-point": { + "node_modules/string-width/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/table/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/table/node_modules/strip-ansi": { + "node_modules/string-width/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" @@ -15354,683 +12127,491 @@ "node": ">=8" } }, - "node_modules/tagged-tag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", - "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "node_modules/string.prototype.matchall": { + "version": "4.0.12", "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, "engines": { - "node": ">=20" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tar-stream": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", - "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "bare-fs": "^4.5.5", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/teex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", - "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "node_modules/string.prototype.repeat": { + "version": "1.0.0", "license": "MIT", "dependencies": { - "streamx": "^2.12.5" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, - "node_modules/terminal-link": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-5.0.0.tgz", - "integrity": "sha512-qFAy10MTMwjzjU8U16YS4YoZD+NQLHzLssFMNqgravjbvIPNiqkGFR4yjhJfmY9R5OFU7+yHxc6y+uGHkKwLRA==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", "license": "MIT", "dependencies": { - "ansi-escapes": "^7.0.0", - "supports-hyperlinks": "^4.1.0" + "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": ">=20" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/terminal-size": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/terminal-size/-/terminal-size-4.0.1.tgz", - "integrity": "sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/text-decoder": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", - "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/textextensions": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", - "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", - "dev": true, - "license": "Artistic-2.0", "dependencies": { - "editions": "^6.21.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.4" }, "funding": { - "url": "https://bevry.me/fund" - } - }, - "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.0.4", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", - "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", "license": "MIT", "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">=12.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "node_modules/stringify-entities": { + "version": "4.0.4", "license": "MIT", - "engines": { - "node": ">=14.0.0" + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } - }, - "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==", + }, + "node_modules/strip-ansi": { + "version": "7.2.0", "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "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==", - "dev": true, + "node_modules/strip-bom": { + "version": "3.0.0", "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=4" } }, - "node_modules/trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "node_modules/strip-json-comments": { + "version": "3.1.1", "license": "MIT", + "engines": { + "node": ">=8" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "node_modules/strnum": { + "version": "2.3.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/structured-source": { + "version": "4.0.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.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==", + "node_modules/style-to-js": { + "version": "1.1.21", "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" + "dependencies": { + "style-to-object": "1.0.14" } }, - "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==", + "node_modules/style-to-object": { + "version": "1.0.14", "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "inline-style-parser": "0.2.7" } }, - "node_modules/tsconfig-paths/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==", + "node_modules/supports-color": { + "version": "7.2.0", "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "has-flag": "^4.0.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=8" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tsx": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", - "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", - "dev": true, + "node_modules/supports-hyperlinks": { + "version": "4.4.0", "license": "MIT", "dependencies": { - "esbuild": "~0.27.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20" }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, - "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, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "5.0.1", "license": "MIT", - "optional": true, - "os": [ - "aix" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "10.2.2", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "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, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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, + "node_modules/synckit": { + "version": "0.11.12", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "@pkgr/core": "^0.2.9" + }, "engines": { - "node": ">=18" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "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, + "node_modules/table": { + "version": "6.9.0", + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=8" } }, - "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, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=8" } }, - "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, + "node_modules/table/node_modules/slice-ansi": { + "version": "4.0.0", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "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, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "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, + "node_modules/tagged-tag": { + "version": "1.0.0", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tar-stream": { + "version": "3.1.8", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" } }, - "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, + "node_modules/teex": { + "version": "1.0.1", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "streamx": "^2.12.5" } }, - "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, + "node_modules/terminal-link": { + "version": "5.0.0", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^4.1.0" + }, "engines": { - "node": ">=18" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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, + "node_modules/terminal-size": { + "version": "4.0.1", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/text-decoder": { + "version": "1.2.7", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" } }, - "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" - ], + "node_modules/text-table": { + "version": "0.2.0", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT" + }, + "node_modules/textextensions": { + "version": "6.11.0", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, "engines": { - "node": ">=18" + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "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" - ], + "node_modules/tinybench": { + "version": "2.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.4", "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, + "node_modules/tinyglobby": { + "version": "0.2.16", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, "engines": { - "node": ">=18" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "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" - ], + "node_modules/tinyrainbow": { + "version": "3.1.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=14.0.0" } }, - "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, + "node_modules/to-regex-range": { + "version": "5.0.1", "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "is-number": "^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8.0" } }, - "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" - ], + "node_modules/toidentifier": { + "version": "1.0.1", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], "engines": { - "node": ">=18" + "node": ">=0.6" } }, - "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, + "node_modules/trim-lines": { + "version": "3.0.1", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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, + "node_modules/trough": { + "version": "2.2.0", "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "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, + "node_modules/ts-api-utils": { + "version": "2.5.0", "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], "engines": { - "node": ">=18" + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "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, + "node_modules/tsconfig-paths": { + "version": "3.15.0", "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "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, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "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" - ], + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { "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" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "darwin" ], "engines": { "node": ">=18" @@ -16038,8 +12619,6 @@ }, "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", @@ -16080,8 +12659,6 @@ }, "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==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -16092,8 +12669,6 @@ }, "node_modules/type-fest": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.5.0.tgz", - "integrity": "sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==", "license": "(MIT OR CC0-1.0)", "dependencies": { "tagged-tag": "^1.0.0" @@ -16107,8 +12682,6 @@ }, "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==", "dev": true, "license": "MIT", "dependencies": { @@ -16122,8 +12695,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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -16136,8 +12707,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -16155,8 +12724,6 @@ }, "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==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -16176,8 +12743,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -16196,8 +12761,6 @@ }, "node_modules/typescript": { "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -16209,8 +12772,6 @@ }, "node_modules/typescript-eslint": { "version": "8.57.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz", - "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==", "dev": true, "license": "MIT", "dependencies": { @@ -16233,8 +12794,6 @@ }, "node_modules/uglify-js": { "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "license": "BSD-2-Clause", "optional": true, "bin": { @@ -16246,8 +12805,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -16264,14 +12821,10 @@ }, "node_modules/undici-types": { "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT" }, "node_modules/unicorn-magic": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", - "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", "dev": true, "license": "MIT", "engines": { @@ -16283,8 +12836,6 @@ }, "node_modules/unified": { "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -16302,8 +12853,6 @@ }, "node_modules/unist-util-is": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -16315,8 +12864,6 @@ }, "node_modules/unist-util-position": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -16328,8 +12875,6 @@ }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -16341,8 +12886,6 @@ }, "node_modules/unist-util-visit": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -16356,8 +12899,6 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -16370,8 +12911,6 @@ }, "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" @@ -16379,8 +12918,6 @@ }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", "engines": { @@ -16389,8 +12926,6 @@ }, "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", @@ -16424,8 +12959,6 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -16454,8 +12987,6 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -16463,14 +12994,10 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/uuid": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", - "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -16482,8 +13009,6 @@ }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -16493,8 +13018,6 @@ }, "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==", "dev": true, "license": "MIT", "engines": { @@ -16503,8 +13026,6 @@ }, "node_modules/version-range": { "version": "4.15.0", - "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", - "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", "dev": true, "license": "Artistic-2.0", "engines": { @@ -16516,8 +13037,6 @@ }, "node_modules/vfile": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -16530,8 +13049,6 @@ }, "node_modules/vfile-message": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -16543,16 +13060,14 @@ } }, "node_modules/vite": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz", - "integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==", + "version": "8.0.10", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "rolldown": "1.0.0", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", "tinyglobby": "^0.2.16" }, "bin": { @@ -16569,7 +13084,7 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.18", + "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", @@ -16621,19 +13136,17 @@ } }, "node_modules/vitest": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", - "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", + "version": "4.1.5", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "4.1.6", - "@vitest/mocker": "4.1.6", - "@vitest/pretty-format": "4.1.6", - "@vitest/runner": "4.1.6", - "@vitest/snapshot": "4.1.6", - "@vitest/spy": "4.1.6", - "@vitest/utils": "4.1.6", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -16661,12 +13174,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.6", - "@vitest/browser-preview": "4.1.6", - "@vitest/browser-webdriverio": "4.1.6", - "@vitest/coverage-istanbul": "4.1.6", - "@vitest/coverage-v8": "4.1.6", - "@vitest/ui": "4.1.6", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -16712,8 +13225,6 @@ }, "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" @@ -16727,8 +13238,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -16746,8 +13255,6 @@ }, "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==", "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -16773,8 +13280,6 @@ }, "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==", "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -16791,8 +13296,6 @@ }, "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==", "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -16812,8 +13315,6 @@ }, "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": { @@ -16829,8 +13330,6 @@ }, "node_modules/widest-line": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-6.0.0.tgz", - "integrity": "sha512-U89AsyEeAsyoF0zVJBkG9zBgekjgjK7yk9sje3F4IQpXBJ10TF6ByLlIfjMhcmHMJgHZI4KHt4rdNfktzxIAMA==", "license": "MIT", "dependencies": { "string-width": "^8.1.0" @@ -16844,8 +13343,6 @@ }, "node_modules/widest-line/node_modules/string-width": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "license": "MIT", "dependencies": { "get-east-asian-width": "^1.5.0", @@ -16860,8 +13357,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -16869,14 +13364,10 @@ }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "license": "MIT" }, "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", @@ -16892,8 +13383,6 @@ }, "node_modules/wrap-ansi/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" @@ -16901,8 +13390,6 @@ }, "node_modules/wrap-ansi/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" @@ -16913,15 +13400,11 @@ }, "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==", "dev": true, "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" @@ -16941,8 +13424,6 @@ }, "node_modules/xml-naming": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", - "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", "funding": [ { "type": "github", @@ -16956,14 +13437,10 @@ }, "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "version": "2.8.3", "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -16977,8 +13454,6 @@ }, "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" @@ -16989,14 +13464,10 @@ }, "node_modules/yoga-layout": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", - "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", "license": "MIT" }, "node_modules/zip-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", - "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", "license": "MIT", "dependencies": { "archiver-utils": "^5.0.0", @@ -17008,9 +13479,7 @@ } }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "4.3.6", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -17018,8 +13487,6 @@ }, "node_modules/zod-to-json-schema": { "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", "dev": true, "license": "ISC", "peerDependencies": { @@ -17028,8 +13495,6 @@ }, "node_modules/zod-validation-error": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", - "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -17040,8 +13505,6 @@ }, "node_modules/zwitch": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "license": "MIT", "funding": { "type": "github", diff --git a/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap b/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap index 241253b59..70ab00826 100644 --- a/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap +++ b/src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap @@ -75,15 +75,11 @@ async function main() { // Extract MCP configuration from project spec. // Gateway fields are stored in agentcore.json but may not yet be on the - // AgentCoreProjectSpec type from @aws/agentcore-cdk, so we read them - // dynamically and cast the resulting object. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const specAny = spec as any; - const mcpSpec = specAny.agentCoreGateways?.length + const mcpSpec = spec.agentCoreGateways?.length ? { - agentCoreGateways: specAny.agentCoreGateways, - mcpRuntimeTools: specAny.mcpRuntimeTools, - unassignedTargets: specAny.unassignedTargets, + agentCoreGateways: spec.agentCoreGateways, + mcpRuntimeTools: spec.mcpRuntimeTools, + unassignedTargets: spec.unassignedTargets, } : undefined; @@ -114,10 +110,31 @@ async function main() { | Record | undefined; + // Payment credential provider ARNs live in the same credentials map as identity credentials + const paymentCredentials = credentials; + + const paymentSpec = spec.payments?.length + ? spec.payments.map(p => ({ + name: p.name, + description: p.description, + authorizerType: p.authorizerType, + authorizerConfiguration: p.authorizerConfiguration, + autoPayment: p.autoPayment, + paymentToolAllowlist: p.paymentToolAllowlist, + networkPreferences: p.networkPreferences, + connectors: p.connectors.map(c => ({ + name: c.name, + provider: c.provider, + credentialProviderArn: paymentCredentials?.[c.credentialName]?.credentialProviderArn ?? '', + })), + })) + : undefined; + new AgentCoreStack(app, stackName, { spec, mcpSpec, credentials, + paymentSpec, env, description: \`AgentCore stack for \${spec.name} deployed to \${target.name} (\${target.region})\`, tags: { @@ -259,12 +276,32 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/lib/cdk-stack.ts shou "import { AgentCoreApplication, AgentCoreMcp, + AgentCorePaymentManager, + AgentCorePaymentConnector, type AgentCoreProjectSpec, type AgentCoreMcpSpec, + type CustomJWTAuthorizerConfig, } from '@aws/agentcore-cdk'; import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; +export interface PaymentConnectorSpec { + name: string; + provider: 'CoinbaseCDP' | 'StripePrivy'; + credentialProviderArn: string; +} + +export interface PaymentSpec { + name: string; + description?: string; + authorizerType: 'AWS_IAM' | 'CUSTOM_JWT'; + authorizerConfiguration?: { customJWTAuthorizer: CustomJWTAuthorizerConfig }; + autoPayment?: boolean; + paymentToolAllowlist?: string[]; + networkPreferences?: string[]; + connectors: PaymentConnectorSpec[]; +} + export interface AgentCoreStackProps extends StackProps { /** * The AgentCore project specification containing agents, memories, and credentials. @@ -278,6 +315,14 @@ export interface AgentCoreStackProps extends StackProps { * Credential provider ARNs from deployed state, keyed by credential name. */ credentials?: Record; + /** + * Payment specifications with resolved credential provider ARNs. + */ + paymentSpec?: PaymentSpec[]; +} + +function toCdkId(name: string): string { + return name.replace(/_/g, ''); } /** @@ -293,7 +338,7 @@ export class AgentCoreStack extends Stack { constructor(scope: Construct, id: string, props: AgentCoreStackProps) { super(scope, id, props); - const { spec, mcpSpec, credentials } = props; + const { spec, mcpSpec, credentials, paymentSpec } = props; // Create AgentCoreApplication with all agents this.application = new AgentCoreApplication(this, 'Application', { @@ -311,6 +356,79 @@ export class AgentCoreStack extends Stack { }); } + // Create payment infrastructure via CFN constructs + if (paymentSpec && paymentSpec.length > 0) { + for (const payment of paymentSpec) { + const mgrId = toCdkId(payment.name); + const manager = new AgentCorePaymentManager(this, \`Payment\${mgrId}\`, { + projectName: spec.name, + name: payment.name, + authorizerType: payment.authorizerType, + description: payment.description, + authorizerConfiguration: payment.authorizerConfiguration, + tags: spec.tags, + }); + + const prefix = \`AGENTCORE_PAYMENT_\${payment.name.toUpperCase().replace(/-/g, '_')}\`; + + // Wire env vars from construct output tokens into all agent environments + for (const env of this.application.environments.values()) { + env.runtime.addEnvironmentVariable(\`\${prefix}_MANAGER_ARN\`, manager.paymentManagerArn); + env.runtime.addEnvironmentVariable(\`\${prefix}_PROCESS_PAYMENT_ROLE_ARN\`, manager.processPaymentRoleArn); + + if (payment.autoPayment !== undefined) { + env.runtime.addEnvironmentVariable(\`\${prefix}_AUTO_PAYMENT\`, String(payment.autoPayment)); + } + if (payment.paymentToolAllowlist) { + env.runtime.addEnvironmentVariable(\`\${prefix}_TOOL_ALLOWLIST\`, payment.paymentToolAllowlist.join(',')); + } + if (payment.networkPreferences) { + env.runtime.addEnvironmentVariable(\`\${prefix}_NETWORK_PREFERENCES\`, payment.networkPreferences.join(',')); + } + if (payment.authorizerType === 'CUSTOM_JWT') { + env.runtime.addEnvironmentVariable(\`\${prefix}_AUTH_MODE\`, 'bearer'); + } + } + + // Create connectors for this manager + for (const connector of payment.connectors) { + const connId = toCdkId(connector.name); + const conn = new AgentCorePaymentConnector(this, \`Payment\${mgrId}\${connId}\`, { + projectName: spec.name, + paymentManager: manager, + connectorName: connector.name, + connectorType: connector.provider, + credentialProviderArn: connector.credentialProviderArn, + }); + + // Wire first connector's ID as env var + if (connector === payment.connectors[0]) { + for (const env of this.application.environments.values()) { + env.runtime.addEnvironmentVariable(\`\${prefix}_CONNECTOR_ID\`, conn.paymentConnectorId); + } + } + + new CfnOutput(this, \`Payment\${mgrId}\${connId}ConnectorId\`, { + value: conn.paymentConnectorId, + }); + } + + // CFN Outputs for post-deploy state parsing + new CfnOutput(this, \`Payment\${mgrId}ManagerArn\`, { + value: manager.paymentManagerArn, + }); + new CfnOutput(this, \`Payment\${mgrId}ManagerId\`, { + value: manager.paymentManagerId, + }); + new CfnOutput(this, \`Payment\${mgrId}ProcessPaymentRoleArn\`, { + value: manager.processPaymentRoleArn, + }); + new CfnOutput(this, \`Payment\${mgrId}ResourceRetrievalRoleArn\`, { + value: manager.resourceRetrievalRoleArn, + }); + } + } + // Stack-level output new CfnOutput(this, 'StackNameOutput', { description: 'Name of the CloudFormation Stack', @@ -383,9 +501,9 @@ test('AgentCoreStack synthesizes with empty spec', () => { evaluators: [], onlineEvalConfigs: [], policyEngines: [], + payments: [], + configBundles: [], agentCoreGateways: [], - mcpRuntimeTools: [], - unassignedTargets: [], }, }); const template = Template.fromStack(stack); @@ -539,6 +657,8 @@ exports[`Assets Directory Snapshots > File listing > should match the expected f "python/http/strands/base/pyproject.toml", "python/http/strands/capabilities/memory/__init__.py", "python/http/strands/capabilities/memory/session.py", + "python/http/strands/capabilities/payments/__init__.py", + "python/http/strands/capabilities/payments/payments.py", "python/mcp/standalone/base/README.md", "python/mcp/standalone/base/gitignore.template", "python/mcp/standalone/base/main.py", @@ -1180,7 +1300,7 @@ requires-python = ">=3.10" dependencies = [ "a2a-sdk >= 0.2.0, < 1.0.0", "aws-opentelemetry-distro", - "bedrock-agentcore[a2a] >= 1.0.3", + "bedrock-agentcore[a2a] >= 1.8.0", "google-adk >= 1.0.0", "google-genai >= 1.0.0", ] @@ -1546,7 +1666,7 @@ dependencies = [ {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", {{/if}}"aws-opentelemetry-distro", "opentelemetry-instrumentation-langchain >= 0.59.0", - "bedrock-agentcore[a2a] >= 1.0.3", + "bedrock-agentcore[a2a] >= 1.8.0", "botocore[crt] >= 1.35.0", "langgraph >= 0.2.0", ] @@ -2127,7 +2247,7 @@ requires-python = ">=3.10" dependencies = [ "ag-ui-adk >= 0.6.0", "ag-ui-protocol >= 0.1.10", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "fastapi >= 0.115.12", "google-adk >= 1.16.0", "google-genai >= 1.0.0", @@ -2442,7 +2562,7 @@ dependencies = [ {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", {{/if}}"aws-opentelemetry-distro", "opentelemetry-instrumentation-langchain >= 0.59.0", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", "langgraph >= 0.3.25", "langchain >= 0.3.0", @@ -3191,7 +3311,7 @@ dependencies = [ "autogen-ext[mcp] >= 0.7.5", "opentelemetry-distro", "opentelemetry-exporter-otlp", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", "tiktoken", {{#if (eq modelProvider "Bedrock")}} @@ -3614,7 +3734,7 @@ dependencies = [ "opentelemetry-distro", "opentelemetry-exporter-otlp", "google-adk >= 1.17.0", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0", {{/if}}{{/if}} @@ -4129,7 +4249,7 @@ dependencies = [ "mcp >= 1.19.0", "langchain-mcp-adapters >= 0.1.11", "langchain >= 1.0.3", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if (eq modelProvider "Bedrock")}} "langchain-aws >= 1.0.0", @@ -4556,7 +4676,7 @@ requires-python = ">=3.10" dependencies = [ "aws-opentelemetry-distro", "openai-agents >= 0.4.2", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0", {{/if}}{{/if}} @@ -4675,6 +4795,9 @@ from memory.session import get_memory_session_manager {{#if sessionStorageMountPath}} import os {{/if}} +{{#if hasPayment}} +from capabilities.payments.payments import create_payments_plugin, PAYMENT_SYSTEM_PROMPT +{{/if}} app = BedrockAgentCoreApp() log = app.logger @@ -4804,12 +4927,12 @@ class ConfigBundleHook(HookProvider): {{/if}} {{#if hasMemory}} +{{#unless hasPayment}} def agent_factory(): cache = {} def get_or_create_agent(session_id, user_id): key = f"{session_id}/{user_id}" if key not in cache: - # Create an agent for the given session_id and user_id cache[key] = Agent( model=load_model(), session_manager=get_memory_session_manager(session_id, user_id), @@ -4820,6 +4943,7 @@ def agent_factory(): return cache[key] return get_or_create_agent get_or_create_agent = agent_factory() +{{/unless}} {{else}} {{#if hasConfigBundle}} def create_agent(): @@ -4830,6 +4954,7 @@ def create_agent(): hooks=[ConfigBundleHook()], ) {{else}} +{{#unless hasPayment}} _agent = None def get_or_create_agent(): @@ -4838,9 +4963,10 @@ def get_or_create_agent(): _agent = Agent( model=load_model(), system_prompt=DEFAULT_SYSTEM_PROMPT, - tools=tools + tools=tools, ) return _agent +{{/unless}} {{/if}} {{/if}} @@ -4849,16 +4975,45 @@ def get_or_create_agent(): async def invoke(payload, context): log.info("Invoking Agent.....") +{{#if hasPayment}} + user_id = payload.get("user_id") or getattr(context, "user_id", "default-user") + instrument_id = payload.get("payment_instrument_id") + session_id = payload.get("payment_session_id") + payments_plugin = create_payments_plugin(user_id, instrument_id, session_id) + plugins = [payments_plugin] if payments_plugin else [] +{{/if}} + {{#if hasMemory}} +{{#if hasPayment}} + mem_session_id = getattr(context, 'session_id', 'default-session') + mem_user_id = getattr(context, 'user_id', 'default-user') + agent = Agent( + model=load_model(), + session_manager=get_memory_session_manager(mem_session_id, mem_user_id), + system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT, + tools=tools, + plugins=plugins, + ) +{{else}} session_id = getattr(context, 'session_id', 'default-session') user_id = getattr(context, 'user_id', 'default-user') agent = get_or_create_agent(session_id, user_id) +{{/if}} +{{else}} +{{#if hasPayment}} + agent = Agent( + model=load_model(), + system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT, + tools=tools, + plugins=plugins, + ) {{else}} {{#if hasConfigBundle}} agent = create_agent() {{else}} agent = get_or_create_agent() {{/if}} +{{/if}} {{/if}} # Execute and format response @@ -5171,6 +5326,150 @@ def get_memory_session_manager(session_id: Optional[str], actor_id: str) -> Opti " `; +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/payments/__init__.py should match snapshot 1`] = ` +""""Payment capabilities for Strands agents.""" +from .payments import create_payments_plugin + +__all__ = ["create_payments_plugin"] +" +`; + +exports[`Assets Directory Snapshots > Python framework assets > python/python/http/strands/capabilities/payments/payments.py should match snapshot 1`] = ` +""""Payment capability -- auto-generated by agentcore CLI. + +Configures AgentCorePaymentsPlugin for Strands agents. +Manager config is auto-discovered from AGENTCORE_PAYMENT_* +environment variables set at deploy time. + +Uses a per-invocation factory pattern so each request gets its own +plugin instance with the correct user_id, instrument_id, and session_id. +This prevents concurrency bugs where one user's payment context +could leak to another user's request. + +Uses the official SDK plugin which handles: +- x402 v1 (body-based) and v2 (header-based) payment detection +- Automatic 402 response interception and payment processing +- Retry limiting (max 3 payment retries per tool use) +- Error management and logging +""" +import os +import logging + +import boto3 +from bedrock_agentcore.payments.integrations.strands import AgentCorePaymentsPlugin +from bedrock_agentcore.payments.integrations.config import AgentCorePaymentsPluginConfig + +logger = logging.getLogger(__name__) + +PAYMENT_SYSTEM_PROMPT = """ +You have payment capabilities via the x402 protocol: +- Payments are processed automatically when you access paid endpoints (HTTP 402 responses) +- Use get_payment_session to check your remaining budget before expensive operations +- Use get_payment_instrument_balance to check wallet USDC balance +- Use list_payment_instruments to see available payment instruments +- If budget is low, inform the user before proceeding with paid requests +""" + +_manager_arn = None +_connector_id = None +_process_payment_role_arn = None +_name_segment = None +_region = None +_auth_mode = None +_manager_count = 0 +for key, value in os.environ.items(): + if key.startswith("AGENTCORE_PAYMENT_") and key.endswith("_MANAGER_ARN"): + if _manager_arn is None: + _manager_arn = value + _name_segment = key[len("AGENTCORE_PAYMENT_"):-len("_MANAGER_ARN")] + _manager_count += 1 +if _manager_count > 1: + logger.warning( + "Multiple payment managers detected in environment. Using the first one found. " + "Remove extra AGENTCORE_PAYMENT_*_MANAGER_ARN env vars to eliminate ambiguity." + ) +_region = os.getenv("AWS_REGION") + +_prefix = f"AGENTCORE_PAYMENT_{_name_segment}_" if _name_segment else "AGENTCORE_PAYMENT_" +_auth_mode = os.getenv(f"{_prefix}AUTH_MODE", "sigv4") +_connector_id = os.getenv(f"{_prefix}CONNECTOR_ID") +_process_payment_role_arn = os.getenv(f"{_prefix}PROCESS_PAYMENT_ROLE_ARN") +_auto_payment = os.getenv(f"{_prefix}AUTO_PAYMENT", "true").lower() == "true" +_allowlist_raw = os.getenv(f"{_prefix}TOOL_ALLOWLIST") +_allowlist = _allowlist_raw.split(",") if _allowlist_raw else None +_network_prefs_raw = os.getenv(f"{_prefix}NETWORK_PREFERENCES") +_network_prefs = _network_prefs_raw.split(",") if _network_prefs_raw else None + +if not _manager_arn: + logger.warning("No payment manager config found in environment") +if not _connector_id: + logger.warning("No payment connector config found in environment") + + +def _assume_role_session(role_arn): + """Assume an IAM role and return a boto3 session with temporary credentials.""" + sts = boto3.client("sts", region_name=_region) + creds = sts.assume_role( + RoleArn=role_arn, + RoleSessionName="agentcore-payment-plugin", + )["Credentials"] + return boto3.Session( + aws_access_key_id=creds["AccessKeyId"], + aws_secret_access_key=creds["SecretAccessKey"], + aws_session_token=creds["SessionToken"], + region_name=_region, + ) + + +def create_payments_plugin(user_id, instrument_id=None, session_id=None): + """Create a fresh plugin instance per invocation. + + Args: + user_id: From invocation context (required for SigV4, derived from JWT for bearer) + instrument_id: From invocation payload (created by app backend per user) + session_id: From invocation payload (created by app backend per conversation) + + Returns: + AgentCorePaymentsPlugin instance, or None if no manager is configured. + """ + if not _manager_arn: + return None + + config_kwargs = { + "payment_manager_arn": _manager_arn, + "region": _region, + "payment_instrument_id": instrument_id, + "payment_session_id": session_id, + "payment_connector_id": _connector_id, + } + + config_kwargs["auto_payment"] = _auto_payment + if _allowlist: + config_kwargs["payment_tool_allowlist"] = _allowlist + if _network_prefs: + config_kwargs["network_preferences_config"] = _network_prefs + + if _process_payment_role_arn: + config_kwargs["boto3_session"] = _assume_role_session(_process_payment_role_arn) + + if _auth_mode == "bearer": + bearer_token = os.getenv("AGENTCORE_BEARER_TOKEN") + if bearer_token: + config_kwargs["bearer_token"] = bearer_token + else: + logger.warning( + "Bearer auth mode configured but AGENTCORE_BEARER_TOKEN not set. " + "Falling back to SigV4. Set AGENTCORE_BEARER_TOKEN or pass bearer_token in invoke context." + ) + config_kwargs["user_id"] = user_id or "default-user" + else: + config_kwargs["user_id"] = user_id or "default-user" + + config = AgentCorePaymentsPluginConfig(**config_kwargs) + return AgentCorePaymentsPlugin(config=config) +" +`; + exports[`Assets Directory Snapshots > Python framework assets > python/python/mcp/standalone/base/README.md should match snapshot 1`] = ` "# {{ name }} diff --git a/src/assets/cdk/bin/cdk.ts b/src/assets/cdk/bin/cdk.ts index 7a78b71cd..3fdfc2749 100644 --- a/src/assets/cdk/bin/cdk.ts +++ b/src/assets/cdk/bin/cdk.ts @@ -30,15 +30,11 @@ async function main() { // Extract MCP configuration from project spec. // Gateway fields are stored in agentcore.json but may not yet be on the - // AgentCoreProjectSpec type from @aws/agentcore-cdk, so we read them - // dynamically and cast the resulting object. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const specAny = spec as any; - const mcpSpec = specAny.agentCoreGateways?.length + const mcpSpec = spec.agentCoreGateways?.length ? { - agentCoreGateways: specAny.agentCoreGateways, - mcpRuntimeTools: specAny.mcpRuntimeTools, - unassignedTargets: specAny.unassignedTargets, + agentCoreGateways: spec.agentCoreGateways, + mcpRuntimeTools: spec.mcpRuntimeTools, + unassignedTargets: spec.unassignedTargets, } : undefined; @@ -69,10 +65,31 @@ async function main() { | Record | undefined; + // Payment credential provider ARNs live in the same credentials map as identity credentials + const paymentCredentials = credentials; + + const paymentSpec = spec.payments?.length + ? spec.payments.map(p => ({ + name: p.name, + description: p.description, + authorizerType: p.authorizerType, + authorizerConfiguration: p.authorizerConfiguration, + autoPayment: p.autoPayment, + paymentToolAllowlist: p.paymentToolAllowlist, + networkPreferences: p.networkPreferences, + connectors: p.connectors.map(c => ({ + name: c.name, + provider: c.provider, + credentialProviderArn: paymentCredentials?.[c.credentialName]?.credentialProviderArn ?? '', + })), + })) + : undefined; + new AgentCoreStack(app, stackName, { spec, mcpSpec, credentials, + paymentSpec, env, description: `AgentCore stack for ${spec.name} deployed to ${target.name} (${target.region})`, tags: { diff --git a/src/assets/cdk/lib/cdk-stack.ts b/src/assets/cdk/lib/cdk-stack.ts index a4d277821..fbc002d94 100644 --- a/src/assets/cdk/lib/cdk-stack.ts +++ b/src/assets/cdk/lib/cdk-stack.ts @@ -1,12 +1,32 @@ import { AgentCoreApplication, AgentCoreMcp, + AgentCorePaymentManager, + AgentCorePaymentConnector, type AgentCoreProjectSpec, type AgentCoreMcpSpec, + type CustomJWTAuthorizerConfig, } from '@aws/agentcore-cdk'; import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib'; import { Construct } from 'constructs'; +export interface PaymentConnectorSpec { + name: string; + provider: 'CoinbaseCDP' | 'StripePrivy'; + credentialProviderArn: string; +} + +export interface PaymentSpec { + name: string; + description?: string; + authorizerType: 'AWS_IAM' | 'CUSTOM_JWT'; + authorizerConfiguration?: { customJWTAuthorizer: CustomJWTAuthorizerConfig }; + autoPayment?: boolean; + paymentToolAllowlist?: string[]; + networkPreferences?: string[]; + connectors: PaymentConnectorSpec[]; +} + export interface AgentCoreStackProps extends StackProps { /** * The AgentCore project specification containing agents, memories, and credentials. @@ -20,6 +40,14 @@ export interface AgentCoreStackProps extends StackProps { * Credential provider ARNs from deployed state, keyed by credential name. */ credentials?: Record; + /** + * Payment specifications with resolved credential provider ARNs. + */ + paymentSpec?: PaymentSpec[]; +} + +function toCdkId(name: string): string { + return name.replace(/_/g, ''); } /** @@ -35,7 +63,7 @@ export class AgentCoreStack extends Stack { constructor(scope: Construct, id: string, props: AgentCoreStackProps) { super(scope, id, props); - const { spec, mcpSpec, credentials } = props; + const { spec, mcpSpec, credentials, paymentSpec } = props; // Create AgentCoreApplication with all agents this.application = new AgentCoreApplication(this, 'Application', { @@ -53,6 +81,79 @@ export class AgentCoreStack extends Stack { }); } + // Create payment infrastructure via CFN constructs + if (paymentSpec && paymentSpec.length > 0) { + for (const payment of paymentSpec) { + const mgrId = toCdkId(payment.name); + const manager = new AgentCorePaymentManager(this, `Payment${mgrId}`, { + projectName: spec.name, + name: payment.name, + authorizerType: payment.authorizerType, + description: payment.description, + authorizerConfiguration: payment.authorizerConfiguration, + tags: spec.tags, + }); + + const prefix = `AGENTCORE_PAYMENT_${payment.name.toUpperCase().replace(/-/g, '_')}`; + + // Wire env vars from construct output tokens into all agent environments + for (const env of this.application.environments.values()) { + env.runtime.addEnvironmentVariable(`${prefix}_MANAGER_ARN`, manager.paymentManagerArn); + env.runtime.addEnvironmentVariable(`${prefix}_PROCESS_PAYMENT_ROLE_ARN`, manager.processPaymentRoleArn); + + if (payment.autoPayment !== undefined) { + env.runtime.addEnvironmentVariable(`${prefix}_AUTO_PAYMENT`, String(payment.autoPayment)); + } + if (payment.paymentToolAllowlist) { + env.runtime.addEnvironmentVariable(`${prefix}_TOOL_ALLOWLIST`, payment.paymentToolAllowlist.join(',')); + } + if (payment.networkPreferences) { + env.runtime.addEnvironmentVariable(`${prefix}_NETWORK_PREFERENCES`, payment.networkPreferences.join(',')); + } + if (payment.authorizerType === 'CUSTOM_JWT') { + env.runtime.addEnvironmentVariable(`${prefix}_AUTH_MODE`, 'bearer'); + } + } + + // Create connectors for this manager + for (const connector of payment.connectors) { + const connId = toCdkId(connector.name); + const conn = new AgentCorePaymentConnector(this, `Payment${mgrId}${connId}`, { + projectName: spec.name, + paymentManager: manager, + connectorName: connector.name, + connectorType: connector.provider, + credentialProviderArn: connector.credentialProviderArn, + }); + + // Wire first connector's ID as env var + if (connector === payment.connectors[0]) { + for (const env of this.application.environments.values()) { + env.runtime.addEnvironmentVariable(`${prefix}_CONNECTOR_ID`, conn.paymentConnectorId); + } + } + + new CfnOutput(this, `Payment${mgrId}${connId}ConnectorId`, { + value: conn.paymentConnectorId, + }); + } + + // CFN Outputs for post-deploy state parsing + new CfnOutput(this, `Payment${mgrId}ManagerArn`, { + value: manager.paymentManagerArn, + }); + new CfnOutput(this, `Payment${mgrId}ManagerId`, { + value: manager.paymentManagerId, + }); + new CfnOutput(this, `Payment${mgrId}ProcessPaymentRoleArn`, { + value: manager.processPaymentRoleArn, + }); + new CfnOutput(this, `Payment${mgrId}ResourceRetrievalRoleArn`, { + value: manager.resourceRetrievalRoleArn, + }); + } + } + // Stack-level output new CfnOutput(this, 'StackNameOutput', { description: 'Name of the CloudFormation Stack', diff --git a/src/assets/cdk/test/cdk.test.ts b/src/assets/cdk/test/cdk.test.ts index df5c767f9..fdef7572b 100644 --- a/src/assets/cdk/test/cdk.test.ts +++ b/src/assets/cdk/test/cdk.test.ts @@ -15,9 +15,9 @@ test('AgentCoreStack synthesizes with empty spec', () => { evaluators: [], onlineEvalConfigs: [], policyEngines: [], + payments: [], + configBundles: [], agentCoreGateways: [], - mcpRuntimeTools: [], - unassignedTargets: [], }, }); const template = Template.fromStack(stack); diff --git a/src/assets/python/a2a/googleadk/base/pyproject.toml b/src/assets/python/a2a/googleadk/base/pyproject.toml index 426150722..b2a024a51 100644 --- a/src/assets/python/a2a/googleadk/base/pyproject.toml +++ b/src/assets/python/a2a/googleadk/base/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10" dependencies = [ "a2a-sdk >= 0.2.0, < 1.0.0", "aws-opentelemetry-distro", - "bedrock-agentcore[a2a] >= 1.0.3", + "bedrock-agentcore[a2a] >= 1.8.0", "google-adk >= 1.0.0", "google-genai >= 1.0.0", ] diff --git a/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml b/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml index c906639ed..386d9a272 100644 --- a/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml +++ b/src/assets/python/a2a/langchain_langgraph/base/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", {{/if}}"aws-opentelemetry-distro", "opentelemetry-instrumentation-langchain >= 0.59.0", - "bedrock-agentcore[a2a] >= 1.0.3", + "bedrock-agentcore[a2a] >= 1.8.0", "botocore[crt] >= 1.35.0", "langgraph >= 0.2.0", ] diff --git a/src/assets/python/agui/googleadk/base/pyproject.toml b/src/assets/python/agui/googleadk/base/pyproject.toml index 0b3a3fed7..c431be1a3 100644 --- a/src/assets/python/agui/googleadk/base/pyproject.toml +++ b/src/assets/python/agui/googleadk/base/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10" dependencies = [ "ag-ui-adk >= 0.6.0", "ag-ui-protocol >= 0.1.10", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "fastapi >= 0.115.12", "google-adk >= 1.16.0", "google-genai >= 1.0.0", diff --git a/src/assets/python/agui/langchain_langgraph/base/pyproject.toml b/src/assets/python/agui/langchain_langgraph/base/pyproject.toml index 6e0e59de7..39e65cfaa 100644 --- a/src/assets/python/agui/langchain_langgraph/base/pyproject.toml +++ b/src/assets/python/agui/langchain_langgraph/base/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ {{/if}}{{#if (eq modelProvider "OpenAI")}}"langchain-openai >= 0.2.0", {{/if}}"aws-opentelemetry-distro", "opentelemetry-instrumentation-langchain >= 0.59.0", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", "langgraph >= 0.3.25", "langchain >= 0.3.0", diff --git a/src/assets/python/http/autogen/base/pyproject.toml b/src/assets/python/http/autogen/base/pyproject.toml index b6ba46d8c..743706144 100644 --- a/src/assets/python/http/autogen/base/pyproject.toml +++ b/src/assets/python/http/autogen/base/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "autogen-ext[mcp] >= 0.7.5", "opentelemetry-distro", "opentelemetry-exporter-otlp", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", "tiktoken", {{#if (eq modelProvider "Bedrock")}} diff --git a/src/assets/python/http/googleadk/base/pyproject.toml b/src/assets/python/http/googleadk/base/pyproject.toml index 98fd161ea..44eb74afb 100644 --- a/src/assets/python/http/googleadk/base/pyproject.toml +++ b/src/assets/python/http/googleadk/base/pyproject.toml @@ -12,7 +12,7 @@ dependencies = [ "opentelemetry-distro", "opentelemetry-exporter-otlp", "google-adk >= 1.17.0", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0", {{/if}}{{/if}} diff --git a/src/assets/python/http/langchain_langgraph/base/pyproject.toml b/src/assets/python/http/langchain_langgraph/base/pyproject.toml index ce261f6bf..6bf078a02 100644 --- a/src/assets/python/http/langchain_langgraph/base/pyproject.toml +++ b/src/assets/python/http/langchain_langgraph/base/pyproject.toml @@ -15,7 +15,7 @@ dependencies = [ "mcp >= 1.19.0", "langchain-mcp-adapters >= 0.1.11", "langchain >= 1.0.3", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if (eq modelProvider "Bedrock")}} "langchain-aws >= 1.0.0", diff --git a/src/assets/python/http/openaiagents/base/pyproject.toml b/src/assets/python/http/openaiagents/base/pyproject.toml index 61944b9a5..a344eccc7 100644 --- a/src/assets/python/http/openaiagents/base/pyproject.toml +++ b/src/assets/python/http/openaiagents/base/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10" dependencies = [ "aws-opentelemetry-distro", "openai-agents >= 0.4.2", - "bedrock-agentcore >= 1.0.3", + "bedrock-agentcore >= 1.8.0", "botocore[crt] >= 1.35.0", {{#if hasGateway}}{{#if (includes gatewayAuthTypes "AWS_IAM")}}"mcp-proxy-for-aws >= 1.1.0", {{/if}}{{/if}} diff --git a/src/assets/python/http/strands/base/main.py b/src/assets/python/http/strands/base/main.py index 0cc8771ad..623cb34e5 100644 --- a/src/assets/python/http/strands/base/main.py +++ b/src/assets/python/http/strands/base/main.py @@ -18,6 +18,9 @@ {{#if sessionStorageMountPath}} import os {{/if}} +{{#if hasPayment}} +from capabilities.payments.payments import create_payments_plugin, PAYMENT_SYSTEM_PROMPT +{{/if}} app = BedrockAgentCoreApp() log = app.logger @@ -147,12 +150,12 @@ def _override_tool_desc(self, event: BeforeToolCallEvent) -> None: {{/if}} {{#if hasMemory}} +{{#unless hasPayment}} def agent_factory(): cache = {} def get_or_create_agent(session_id, user_id): key = f"{session_id}/{user_id}" if key not in cache: - # Create an agent for the given session_id and user_id cache[key] = Agent( model=load_model(), session_manager=get_memory_session_manager(session_id, user_id), @@ -163,6 +166,7 @@ def get_or_create_agent(session_id, user_id): return cache[key] return get_or_create_agent get_or_create_agent = agent_factory() +{{/unless}} {{else}} {{#if hasConfigBundle}} def create_agent(): @@ -173,6 +177,7 @@ def create_agent(): hooks=[ConfigBundleHook()], ) {{else}} +{{#unless hasPayment}} _agent = None def get_or_create_agent(): @@ -181,9 +186,10 @@ def get_or_create_agent(): _agent = Agent( model=load_model(), system_prompt=DEFAULT_SYSTEM_PROMPT, - tools=tools + tools=tools, ) return _agent +{{/unless}} {{/if}} {{/if}} @@ -192,16 +198,45 @@ def get_or_create_agent(): async def invoke(payload, context): log.info("Invoking Agent.....") +{{#if hasPayment}} + user_id = payload.get("user_id") or getattr(context, "user_id", "default-user") + instrument_id = payload.get("payment_instrument_id") + session_id = payload.get("payment_session_id") + payments_plugin = create_payments_plugin(user_id, instrument_id, session_id) + plugins = [payments_plugin] if payments_plugin else [] +{{/if}} + {{#if hasMemory}} +{{#if hasPayment}} + mem_session_id = getattr(context, 'session_id', 'default-session') + mem_user_id = getattr(context, 'user_id', 'default-user') + agent = Agent( + model=load_model(), + session_manager=get_memory_session_manager(mem_session_id, mem_user_id), + system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT, + tools=tools, + plugins=plugins, + ) +{{else}} session_id = getattr(context, 'session_id', 'default-session') user_id = getattr(context, 'user_id', 'default-user') agent = get_or_create_agent(session_id, user_id) +{{/if}} +{{else}} +{{#if hasPayment}} + agent = Agent( + model=load_model(), + system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT, + tools=tools, + plugins=plugins, + ) {{else}} {{#if hasConfigBundle}} agent = create_agent() {{else}} agent = get_or_create_agent() {{/if}} +{{/if}} {{/if}} # Execute and format response diff --git a/src/assets/python/http/strands/capabilities/payments/__init__.py b/src/assets/python/http/strands/capabilities/payments/__init__.py new file mode 100644 index 000000000..74c5b37a2 --- /dev/null +++ b/src/assets/python/http/strands/capabilities/payments/__init__.py @@ -0,0 +1,4 @@ +"""Payment capabilities for Strands agents.""" +from .payments import create_payments_plugin + +__all__ = ["create_payments_plugin"] diff --git a/src/assets/python/http/strands/capabilities/payments/payments.py b/src/assets/python/http/strands/capabilities/payments/payments.py new file mode 100644 index 000000000..0245ae982 --- /dev/null +++ b/src/assets/python/http/strands/capabilities/payments/payments.py @@ -0,0 +1,132 @@ +"""Payment capability -- auto-generated by agentcore CLI. + +Configures AgentCorePaymentsPlugin for Strands agents. +Manager config is auto-discovered from AGENTCORE_PAYMENT_* +environment variables set at deploy time. + +Uses a per-invocation factory pattern so each request gets its own +plugin instance with the correct user_id, instrument_id, and session_id. +This prevents concurrency bugs where one user's payment context +could leak to another user's request. + +Uses the official SDK plugin which handles: +- x402 v1 (body-based) and v2 (header-based) payment detection +- Automatic 402 response interception and payment processing +- Retry limiting (max 3 payment retries per tool use) +- Error management and logging +""" +import os +import logging + +import boto3 +from bedrock_agentcore.payments.integrations.strands import AgentCorePaymentsPlugin +from bedrock_agentcore.payments.integrations.config import AgentCorePaymentsPluginConfig + +logger = logging.getLogger(__name__) + +PAYMENT_SYSTEM_PROMPT = """ +You have payment capabilities via the x402 protocol: +- Payments are processed automatically when you access paid endpoints (HTTP 402 responses) +- Use get_payment_session to check your remaining budget before expensive operations +- Use get_payment_instrument_balance to check wallet USDC balance +- Use list_payment_instruments to see available payment instruments +- If budget is low, inform the user before proceeding with paid requests +""" + +_manager_arn = None +_connector_id = None +_process_payment_role_arn = None +_name_segment = None +_region = None +_auth_mode = None +_manager_count = 0 +for key, value in os.environ.items(): + if key.startswith("AGENTCORE_PAYMENT_") and key.endswith("_MANAGER_ARN"): + if _manager_arn is None: + _manager_arn = value + _name_segment = key[len("AGENTCORE_PAYMENT_"):-len("_MANAGER_ARN")] + _manager_count += 1 +if _manager_count > 1: + logger.warning( + "Multiple payment managers detected in environment. Using the first one found. " + "Remove extra AGENTCORE_PAYMENT_*_MANAGER_ARN env vars to eliminate ambiguity." + ) +_region = os.getenv("AWS_REGION") + +_prefix = f"AGENTCORE_PAYMENT_{_name_segment}_" if _name_segment else "AGENTCORE_PAYMENT_" +_auth_mode = os.getenv(f"{_prefix}AUTH_MODE", "sigv4") +_connector_id = os.getenv(f"{_prefix}CONNECTOR_ID") +_process_payment_role_arn = os.getenv(f"{_prefix}PROCESS_PAYMENT_ROLE_ARN") +_auto_payment = os.getenv(f"{_prefix}AUTO_PAYMENT", "true").lower() == "true" +_allowlist_raw = os.getenv(f"{_prefix}TOOL_ALLOWLIST") +_allowlist = _allowlist_raw.split(",") if _allowlist_raw else None +_network_prefs_raw = os.getenv(f"{_prefix}NETWORK_PREFERENCES") +_network_prefs = _network_prefs_raw.split(",") if _network_prefs_raw else None + +if not _manager_arn: + logger.warning("No payment manager config found in environment") +if not _connector_id: + logger.warning("No payment connector config found in environment") + + +def _assume_role_session(role_arn): + """Assume an IAM role and return a boto3 session with temporary credentials.""" + sts = boto3.client("sts", region_name=_region) + creds = sts.assume_role( + RoleArn=role_arn, + RoleSessionName="agentcore-payment-plugin", + )["Credentials"] + return boto3.Session( + aws_access_key_id=creds["AccessKeyId"], + aws_secret_access_key=creds["SecretAccessKey"], + aws_session_token=creds["SessionToken"], + region_name=_region, + ) + + +def create_payments_plugin(user_id, instrument_id=None, session_id=None): + """Create a fresh plugin instance per invocation. + + Args: + user_id: From invocation context (required for SigV4, derived from JWT for bearer) + instrument_id: From invocation payload (created by app backend per user) + session_id: From invocation payload (created by app backend per conversation) + + Returns: + AgentCorePaymentsPlugin instance, or None if no manager is configured. + """ + if not _manager_arn: + return None + + config_kwargs = { + "payment_manager_arn": _manager_arn, + "region": _region, + "payment_instrument_id": instrument_id, + "payment_session_id": session_id, + "payment_connector_id": _connector_id, + } + + config_kwargs["auto_payment"] = _auto_payment + if _allowlist: + config_kwargs["payment_tool_allowlist"] = _allowlist + if _network_prefs: + config_kwargs["network_preferences_config"] = _network_prefs + + if _process_payment_role_arn: + config_kwargs["boto3_session"] = _assume_role_session(_process_payment_role_arn) + + if _auth_mode == "bearer": + bearer_token = os.getenv("AGENTCORE_BEARER_TOKEN") + if bearer_token: + config_kwargs["bearer_token"] = bearer_token + else: + logger.warning( + "Bearer auth mode configured but AGENTCORE_BEARER_TOKEN not set. " + "Falling back to SigV4. Set AGENTCORE_BEARER_TOKEN or pass bearer_token in invoke context." + ) + config_kwargs["user_id"] = user_id or "default-user" + else: + config_kwargs["user_id"] = user_id or "default-user" + + config = AgentCorePaymentsPluginConfig(**config_kwargs) + return AgentCorePaymentsPlugin(config=config) diff --git a/src/cli/aws/agentcore-payments.ts b/src/cli/aws/agentcore-payments.ts new file mode 100644 index 000000000..d166bcaea --- /dev/null +++ b/src/cli/aws/agentcore-payments.ts @@ -0,0 +1,485 @@ +/** + * AWS client wrappers for Payment control plane operations. + * + * Uses direct HTTP requests with SigV4 signing against the control plane + * because the Payment APIs are not yet in the SDK client. + */ +import { getCredentialProvider } from './account'; +import { serviceEndpoint } from './partition'; +import { Sha256 } from '@aws-crypto/sha256-js'; +import { defaultProvider } from '@aws-sdk/credential-provider-node'; +import { HttpRequest } from '@smithy/protocol-http'; +import { SignatureV4 } from '@smithy/signature-v4'; + +// ============================================================================ +// Types +// ============================================================================ + +// ── Create Payment Credential Provider ───────────────────────────────────── + +interface CreateCoinbaseCdpCredentialProviderOptions { + region: string; + name: string; + vendor: 'CoinbaseCDP'; + apiKeyId: string; + apiKeySecret: string; + walletSecret: string; +} + +interface CreateStripePrivyCredentialProviderOptions { + region: string; + name: string; + vendor: 'StripePrivy'; + appId: string; + appSecret: string; + authorizationPrivateKey: string; + authorizationId: string; +} + +type CreatePaymentCredentialProviderOptions = + | CreateCoinbaseCdpCredentialProviderOptions + | CreateStripePrivyCredentialProviderOptions; + +interface PaymentCredentialProviderApiResult { + credentialProviderArn: string; + status: string; +} + +// ── Update Payment Credential Provider ───────────────────────────────────── + +type UpdatePaymentCredentialProviderOptions = CreatePaymentCredentialProviderOptions; + +// ── Get Payment Credential Provider ──────────────────────────────────────── + +interface GetPaymentCredentialProviderOptions { + region: string; + name: string; +} + +interface PaymentCredentialProviderDetail { + credentialProviderArn: string; + name: string; + status: string; +} + +// ── Get Payment Manager ─────────────────────────────────────────────────── + +interface GetPaymentManagerOptions { + region: string; + paymentManagerId: string; +} + +interface PaymentManagerDetail { + paymentManagerId: string; + paymentManagerArn: string; + name: string; + status: string; + description?: string; + roleArn?: string; +} + +// ============================================================================ +// HTTP signing helper +// ============================================================================ + +function getControlPlaneEndpoint(region: string): string { + const stage = process.env.AGENTCORE_STAGE?.toLowerCase(); + if (stage === 'beta') return `https://beta.${region}.elcapcp.genesis-primitives.aws.dev`; + if (stage === 'gamma') return `https://gamma.${region}.elcapcp.genesis-primitives.aws.dev`; + return `https://${serviceEndpoint('bedrock-agentcore-control', region)}`; +} + +async function signedRequest(options: { + region: string; + method: string; + path: string; + body?: string; +}): Promise { + const { region, method, path, body } = options; + const endpoint = getControlPlaneEndpoint(region); + const url = new URL(path, endpoint); + + const query: Record = {}; + url.searchParams.forEach((value, key) => { + query[key] = value; + }); + + const request = new HttpRequest({ + method, + protocol: 'https:', + hostname: url.hostname, + path: url.pathname, + ...(Object.keys(query).length > 0 && { query }), + headers: { + 'Content-Type': 'application/json', + host: url.hostname, + }, + ...(body && { body }), + }); + + const credentials = getCredentialProvider() ?? defaultProvider(); + const service = 'bedrock-agentcore'; + const signer = new SignatureV4({ + service, + region, + credentials, + sha256: Sha256, + }); + + const signedReq = await signer.sign(request); + + let response: Response; + try { + response = await fetch(`${endpoint}${path}`, { + method, + headers: signedReq.headers as Record, + ...(body && { body }), + signal: AbortSignal.timeout(8000), + }); + } catch (err) { + if (err instanceof Error && err.name === 'TimeoutError') { + throw new Error( + `Payment API request timed out (>8s) for ${method} ${path}. Check network connectivity and region.` + ); + } + throw err; + } + + if (!response.ok) { + const errorBody = await response.text(); + // Sanitize error body -- API validation errors may echo request fields containing secrets + const sanitized = errorBody + .replace( + /("apiKeySecret"|"walletSecret"|"apiKeyId"|"appId"|"appSecret"|"authorizationPrivateKey"|"authorizationId")\s*:\s*"[^"]*"/g, + '$1:"[REDACTED]"' + ) + .slice(0, 500); + + const error = new Error(`Payment API error (${response.status}): ${sanitized}`) as Error & { code?: string }; + try { + const parsed = JSON.parse(errorBody) as Record; + const code = parsed.code ?? parsed.__type; + if (typeof code === 'string') error.code = code; + } catch (_err) { + /* ignore parse failures */ + } + throw error; + } + + if (response.status === 204) return {}; + return response.json(); +} + +// ============================================================================ +// Payment Credential Provider Operations +// ============================================================================ + +function buildProviderConfigPayload(options: CreatePaymentCredentialProviderOptions): { + credentialProviderVendor: string; + providerConfigurationInput: Record; +} { + if (options.vendor === 'StripePrivy') { + return { + credentialProviderVendor: 'StripePrivy', + providerConfigurationInput: { + stripePrivyConfiguration: { + appId: options.appId, + appSecret: options.appSecret, + authorizationPrivateKey: options.authorizationPrivateKey, + authorizationId: options.authorizationId, + }, + }, + }; + } + return { + credentialProviderVendor: 'CoinbaseCDP', + providerConfigurationInput: { + coinbaseCdpConfiguration: { + apiKeyId: options.apiKeyId, + apiKeySecret: options.apiKeySecret, + walletSecret: options.walletSecret, + }, + }, + }; +} + +export async function createPaymentCredentialProvider( + options: CreatePaymentCredentialProviderOptions +): Promise { + const { credentialProviderVendor, providerConfigurationInput } = buildProviderConfigPayload(options); + const body = JSON.stringify({ + name: options.name, + credentialProviderVendor, + providerConfigurationInput, + }); + + try { + const data = (await signedRequest({ + region: options.region, + method: 'POST', + path: '/identities/CreatePaymentCredentialProvider', + body, + })) as PaymentCredentialProviderApiResult; + + return { + credentialProviderArn: data.credentialProviderArn, + status: data.status, + }; + } catch (err) { + throw new Error( + `Failed to create payment credential provider "${options.name}": ${err instanceof Error ? err.message : String(err)}` + ); + } +} + +export async function updatePaymentCredentialProvider( + options: UpdatePaymentCredentialProviderOptions +): Promise { + const { credentialProviderVendor, providerConfigurationInput } = buildProviderConfigPayload(options); + const body = JSON.stringify({ + name: options.name, + credentialProviderVendor, + providerConfigurationInput, + }); + + try { + const data = (await signedRequest({ + region: options.region, + method: 'POST', + path: '/identities/UpdatePaymentCredentialProvider', + body, + })) as PaymentCredentialProviderApiResult; + + return { + credentialProviderArn: data.credentialProviderArn, + status: data.status, + }; + } catch (err) { + throw new Error( + `Failed to update payment credential provider "${options.name}": ${err instanceof Error ? err.message : String(err)}` + ); + } +} + +export async function getPaymentCredentialProvider( + options: GetPaymentCredentialProviderOptions +): Promise { + try { + const data = (await signedRequest({ + region: options.region, + method: 'POST', + path: '/identities/GetPaymentCredentialProvider', + body: JSON.stringify({ name: options.name }), + })) as PaymentCredentialProviderDetail; + + return data; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (msg.includes('(404)') || msg.includes('ResourceNotFoundException')) return null; + throw new Error(`Failed to get payment credential provider "${options.name}": ${msg}`); + } +} + +export async function deletePaymentCredentialProvider(options: { region: string; name: string }): Promise { + try { + await signedRequest({ + region: options.region, + method: 'POST', + path: '/identities/DeletePaymentCredentialProvider', + body: JSON.stringify({ name: options.name }), + }); + } catch (err) { + throw new Error( + `Failed to delete payment credential provider "${options.name}": ${err instanceof Error ? err.message : String(err)}` + ); + } +} + +// ============================================================================ +// Payment Manager Operations +// ============================================================================ + +export async function getPaymentManager(options: GetPaymentManagerOptions): Promise { + try { + return (await signedRequest({ + region: options.region, + method: 'GET', + path: `/payments/managers/${encodeURIComponent(options.paymentManagerId)}`, + })) as PaymentManagerDetail; + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + if (msg.includes('(404)') || msg.includes('ResourceNotFoundException')) return null; + throw new Error(`Failed to get payment manager "${options.paymentManagerId}": ${msg}`); + } +} + +// ============================================================================ +// Data Plane Operations (Payment Sessions) +// ============================================================================ + +function getDataPlaneEndpoint(region: string): string { + const stage = process.env.AGENTCORE_STAGE?.toLowerCase(); + if (stage === 'beta') return `https://beta.${region}.elcapdp.genesis-primitives.aws.dev`; + if (stage === 'gamma') return `https://gamma.${region}.elcapdp.genesis-primitives.aws.dev`; + return `https://${serviceEndpoint('bedrock-agentcore', region)}`; +} + +async function signedDataPlaneRequest(options: { + region: string; + method: string; + path: string; + body?: string; + extraHeaders?: Record; +}): Promise { + const { region, method, path, body, extraHeaders } = options; + const endpoint = getDataPlaneEndpoint(region); + const url = new URL(path, endpoint); + + const query: Record = {}; + url.searchParams.forEach((value, key) => { + query[key] = value; + }); + + const request = new HttpRequest({ + method, + protocol: 'https:', + hostname: url.hostname, + path: url.pathname, + ...(Object.keys(query).length > 0 && { query }), + headers: { + 'Content-Type': 'application/json', + host: url.hostname, + ...extraHeaders, + }, + ...(body && { body }), + }); + + const credentials = getCredentialProvider() ?? defaultProvider(); + const service = 'bedrock-agentcore'; + const signer = new SignatureV4({ + service, + region, + credentials, + sha256: Sha256, + }); + + const signedReq = await signer.sign(request); + + let response: Response; + try { + response = await fetch(`${endpoint}${path}`, { + method, + headers: signedReq.headers as Record, + ...(body && { body }), + signal: AbortSignal.timeout(8000), + }); + } catch (err) { + if (err instanceof Error && err.name === 'TimeoutError') { + throw new Error( + `Payment data plane API request timed out (>8s) for ${method} ${path}. Check network connectivity and region.` + ); + } + throw err; + } + + if (!response.ok) { + const errorBody = await response.text().catch(() => ''); + const sanitized = errorBody + .replace( + /("apiKeySecret"|"walletSecret"|"apiKeyId"|"appId"|"appSecret"|"authorizationPrivateKey"|"authorizationId")\s*:\s*"[^"]*"/g, + '$1:"[REDACTED]"' + ) + .slice(0, 500); + const error = new Error(`Payment data plane API error (${response.status}): ${sanitized}`) as Error & { + code?: string; + }; + try { + const parsed = JSON.parse(errorBody) as Record; + const code = parsed.code ?? parsed.__type; + if (typeof code === 'string') error.code = code; + } catch (_err) { + /* ignore parse failures */ + } + throw error; + } + + if (response.status === 204) return {}; + return response.json(); +} + +// ── Payment Session Types ───────────────────────────────────────────────── + +interface GetOrCreatePaymentSessionOptions { + region: string; + managerArn: string; + userId: string; + defaultSpendLimit?: string; + defaultExpiryMinutes?: number; +} + +interface PaymentSessionSummary { + paymentSessionId: string; + status: string; + expiryTime?: string; +} + +interface ListPaymentSessionsResult { + paymentSessions: PaymentSessionSummary[]; + nextToken?: string; +} + +interface CreatePaymentSessionResult { + paymentSessionId: string; + status: string; +} + +/** + * Get an existing active payment session or create a new one with default budget. + * Uses the developer's credentials (ManagementRole). + */ +export async function getOrCreatePaymentSession(options: GetOrCreatePaymentSessionOptions): Promise { + const { region, managerArn, userId, defaultSpendLimit = '10.00', defaultExpiryMinutes = 60 } = options; + const userIdHeader = { 'X-Amzn-Bedrock-AgentCore-Payments-User-Id': userId }; + + // Try to find an existing active session + try { + const listResult = (await signedDataPlaneRequest({ + region, + method: 'POST', + path: '/payments/listPaymentSessions', + body: JSON.stringify({ + userId, + paymentManagerArn: managerArn, + }), + extraHeaders: userIdHeader, + })) as ListPaymentSessionsResult; + + const activeSessions = (listResult.paymentSessions ?? []).filter(s => s.status === 'ACTIVE'); + if (activeSessions.length > 0) { + return activeSessions[0]!.paymentSessionId; + } + } catch (_err) { + // If list fails, fall through to create + } + + // No active session found — create one with configured budget + const createResult = (await signedDataPlaneRequest({ + region, + method: 'POST', + path: '/payments/createPaymentSession', + body: JSON.stringify({ + userId, + paymentManagerArn: managerArn, + expiryTimeInMinutes: defaultExpiryMinutes, + limits: { + maxSpendAmount: { + value: defaultSpendLimit, + currency: 'USD', + }, + }, + }), + extraHeaders: userIdHeader, + })) as CreatePaymentSessionResult; + + return createResult.paymentSessionId; +} diff --git a/src/cli/aws/agentcore.ts b/src/cli/aws/agentcore.ts index b99ea2f4e..5883f9584 100644 --- a/src/cli/aws/agentcore.ts +++ b/src/cli/aws/agentcore.ts @@ -68,6 +68,10 @@ export interface InvokeAgentRuntimeOptions { bearerToken?: string; /** W3C baggage header value (e.g. config bundle ref for runtime) */ baggage?: string; + /** Payment instrument ID for x402 payments */ + paymentInstrumentId?: string; + /** Payment session ID for budget tracking */ + paymentSessionId?: string; } export interface InvokeAgentRuntimeResult { @@ -147,6 +151,21 @@ export function extractResult(text: string): string { } } +/** + * Build the JSON payload body for an invoke request. + * Includes payment context fields only when provided. + */ +function buildInvokePayload(options: InvokeAgentRuntimeOptions): string { + const body: Record = { prompt: options.payload }; + if (options.paymentInstrumentId) { + body.payment_instrument_id = options.paymentInstrumentId; + } + if (options.paymentSessionId) { + body.payment_session_id = options.paymentSessionId; + } + return JSON.stringify(body); +} + // --------------------------------------------------------------------------- // Bearer token (CUSTOM_JWT) thin HTTP client // --------------------------------------------------------------------------- @@ -198,7 +217,7 @@ async function invokeWithBearerTokenStreaming(options: InvokeAgentRuntimeOptions const res = await fetch(url, { method: 'POST', headers, - body: JSON.stringify({ prompt: options.payload }), + body: buildInvokePayload(options), }); if (!res.ok) { @@ -284,7 +303,7 @@ async function invokeWithBearerToken(options: InvokeAgentRuntimeOptions): Promis const res = await fetch(url, { method: 'POST', headers, - body: JSON.stringify({ prompt: options.payload }), + body: buildInvokePayload(options), }); if (!res.ok) { @@ -316,7 +335,7 @@ export async function invokeAgentRuntimeStreaming(options: InvokeAgentRuntimeOpt const command = new InvokeAgentRuntimeCommand({ agentRuntimeArn: options.runtimeArn, - payload: new TextEncoder().encode(JSON.stringify({ prompt: options.payload })), + payload: new TextEncoder().encode(buildInvokePayload(options)), contentType: 'application/json', accept: 'application/json, text/event-stream', runtimeSessionId: options.sessionId, @@ -412,7 +431,7 @@ export async function invokeAgentRuntime(options: InvokeAgentRuntimeOptions): Pr const command = new InvokeAgentRuntimeCommand({ agentRuntimeArn: options.runtimeArn, - payload: new TextEncoder().encode(JSON.stringify({ prompt: options.payload })), + payload: new TextEncoder().encode(buildInvokePayload(options)), contentType: 'application/json', accept: 'application/json, text/event-stream', runtimeSessionId: options.sessionId, diff --git a/src/cli/aws/index.ts b/src/cli/aws/index.ts index 7c87fec34..a5ad2effb 100644 --- a/src/cli/aws/index.ts +++ b/src/cli/aws/index.ts @@ -26,6 +26,14 @@ export { type GetPolicyGenerationOptions, type GetPolicyGenerationResult, } from './policy-generation'; +export { + createPaymentCredentialProvider, + updatePaymentCredentialProvider, + getPaymentCredentialProvider, + deletePaymentCredentialProvider, + getPaymentManager, + getOrCreatePaymentSession, +} from './agentcore-payments'; export { DEFAULT_RUNTIME_USER_ID, executeBashCommand, diff --git a/src/cli/cdk/toolkit-lib/types.ts b/src/cli/cdk/toolkit-lib/types.ts index 61f2039b4..261e01712 100644 --- a/src/cli/cdk/toolkit-lib/types.ts +++ b/src/cli/cdk/toolkit-lib/types.ts @@ -172,6 +172,12 @@ export interface CdkToolkitWrapperOptions { * Optional AWS profile to use. */ profile?: string; + + /** + * Default AWS region for CDK operations. + * Without this, the toolkit falls back to AWS_REGION env var or us-east-1. + */ + region?: string; } export interface StackSelectionOptions { diff --git a/src/cli/cdk/toolkit-lib/wrapper.ts b/src/cli/cdk/toolkit-lib/wrapper.ts index 4444f2795..7db2eaea0 100644 --- a/src/cli/cdk/toolkit-lib/wrapper.ts +++ b/src/cli/cdk/toolkit-lib/wrapper.ts @@ -102,9 +102,13 @@ export class CdkToolkitWrapper { */ async initialize(): Promise { return withErrorContext(`initialize (project: ${this.projectDir})`, async () => { - // Use explicit profile, fall back to AWS_PROFILE env var per AWS SDK precedence + // Use explicit profile and region, fall back to env vars per AWS SDK precedence const profile = this.options.profile ?? process.env.AWS_PROFILE; - const sdkConfig = profile ? { baseCredentials: BaseCredentials.awsCliCompatible({ profile }) } : undefined; + const region = this.options.region ?? process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION; + const sdkConfig = + profile || region + ? { baseCredentials: BaseCredentials.awsCliCompatible({ profile, defaultRegion: region }) } + : undefined; this.toolkit = new Toolkit({ ioHost: this.options.ioHost, @@ -113,6 +117,7 @@ export class CdkToolkitWrapper { this.cloudAssemblySource = await this.toolkit.fromCdkApp(this.getCdkAppCommand(), { workingDirectory: this.projectDir, + ...(region && { env: { AWS_REGION: region, AWS_DEFAULT_REGION: region } }), }); }); } diff --git a/src/cli/cloudformation/__tests__/parse-payment-outputs.test.ts b/src/cli/cloudformation/__tests__/parse-payment-outputs.test.ts new file mode 100644 index 000000000..3a49ebe0d --- /dev/null +++ b/src/cli/cloudformation/__tests__/parse-payment-outputs.test.ts @@ -0,0 +1,350 @@ +import { parsePaymentOutputs } from '../outputs.js'; +import type { StackOutputs } from '../outputs.js'; +import { describe, expect, it } from 'vitest'; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makeOutputs(name: string, overrides: Record = {}): StackOutputs { + return { + [`Payment${name}ManagerArn`]: `arn:aws:bedrock:us-east-1:123456789012:payment-manager/${name}`, + [`Payment${name}ManagerId`]: `pm-${name.toLowerCase()}-001`, + [`Payment${name}ProcessPaymentRoleArn`]: `arn:aws:iam::123456789012:role/${name}ProcessPaymentRole`, + [`Payment${name}ResourceRetrievalRoleArn`]: `arn:aws:iam::123456789012:role/${name}ResourceRetrievalRole`, + ...overrides, + }; +} + +const COINBASE_CREDENTIAL_ARN = 'arn:aws:bedrock:us-east-1:123456789012:credential-provider/coinbase'; + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe('parsePaymentOutputs', () => { + describe('happy path', () => { + it('returns a complete PaymentDeployedState when all outputs are present', () => { + const outputs: StackOutputs = { + ...makeOutputs('MyManager'), + PaymentMyManagerCoinbaseConnectorId: 'conn-coinbase-001', + }; + + const specs = [ + { + name: 'MyManager', + connectors: [ + { + name: 'Coinbase', + credentialProviderArn: COINBASE_CREDENTIAL_ARN, + credentialProviderName: 'coinbase-cdp', + }, + ], + }, + ]; + + const result = parsePaymentOutputs(outputs, specs); + + expect(result.MyManager).toBeDefined(); + expect(result.MyManager!.managerId).toBe('pm-mymanager-001'); + expect(result.MyManager!.managerArn).toBe('arn:aws:bedrock:us-east-1:123456789012:payment-manager/MyManager'); + expect(result.MyManager!.processPaymentRoleArn).toBe( + 'arn:aws:iam::123456789012:role/MyManagerProcessPaymentRole' + ); + expect(result.MyManager!.resourceRetrievalRoleArn).toBe( + 'arn:aws:iam::123456789012:role/MyManagerResourceRetrievalRole' + ); + expect(result.MyManager!.connectors.Coinbase).toEqual({ + connectorId: 'conn-coinbase-001', + credentialProviderArn: COINBASE_CREDENTIAL_ARN, + credentialProviderName: 'coinbase-cdp', + }); + }); + }); + + describe('missing required manager fields', () => { + it('skips a payment when managerArn is absent', () => { + const outputs: StackOutputs = { + PaymentMyManagerManagerId: 'pm-001', + PaymentMyManagerProcessPaymentRoleArn: 'arn:aws:iam::123:role/ProcessPaymentRole', + PaymentMyManagerResourceRetrievalRoleArn: 'arn:aws:iam::123:role/ResourceRetrievalRole', + // managerArn intentionally omitted + }; + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager).toBeUndefined(); + expect(Object.keys(result)).toHaveLength(0); + }); + + it('skips a payment when managerId is absent', () => { + const outputs: StackOutputs = { + PaymentMyManagerManagerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/MyManager', + PaymentMyManagerProcessPaymentRoleArn: 'arn:aws:iam::123:role/ProcessPaymentRole', + PaymentMyManagerResourceRetrievalRoleArn: 'arn:aws:iam::123:role/ResourceRetrievalRole', + // managerId intentionally omitted + }; + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager).toBeUndefined(); + }); + + it('skips a payment when processPaymentRoleArn is absent', () => { + const outputs: StackOutputs = { + ...makeOutputs('MyManager'), + }; + delete outputs.PaymentMyManagerProcessPaymentRoleArn; + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager).toBeUndefined(); + }); + + it('skips a payment when resourceRetrievalRoleArn is absent', () => { + const outputs: StackOutputs = { + ...makeOutputs('MyManager'), + }; + delete outputs.PaymentMyManagerResourceRetrievalRoleArn; + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager).toBeUndefined(); + }); + }); + + describe('missing connector output', () => { + it('includes the manager with an empty connectors map when connector output is absent', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + // No connector output key present + + const specs = [ + { + name: 'MyManager', + connectors: [ + { + name: 'Coinbase', + credentialProviderArn: COINBASE_CREDENTIAL_ARN, + }, + ], + }, + ]; + + const result = parsePaymentOutputs(outputs, specs); + + expect(result.MyManager).toBeDefined(); + expect(result.MyManager!.connectors).toEqual({}); + }); + + it('includes a manager that has no connectors configured at all', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager).toBeDefined(); + expect(result.MyManager!.connectors).toEqual({}); + }); + }); + + describe('multiple managers', () => { + it('parses both managers independently', () => { + const outputs: StackOutputs = { + ...makeOutputs('Alpha'), + ...makeOutputs('Beta'), + PaymentAlphaCoinbaseConnectorId: 'conn-alpha-coinbase', + PaymentBetaStripeConnectorId: 'conn-beta-stripe', + }; + + const specs = [ + { + name: 'Alpha', + connectors: [{ name: 'Coinbase', credentialProviderArn: 'arn:cred:alpha' }], + }, + { + name: 'Beta', + connectors: [{ name: 'Stripe', credentialProviderArn: 'arn:cred:beta' }], + }, + ]; + + const result = parsePaymentOutputs(outputs, specs); + + expect(Object.keys(result)).toHaveLength(2); + + expect(result.Alpha!.managerId).toBe('pm-alpha-001'); + expect(result.Alpha!.connectors.Coinbase).toEqual({ + connectorId: 'conn-alpha-coinbase', + credentialProviderArn: 'arn:cred:alpha', + credentialProviderName: undefined, + }); + + expect(result.Beta!.managerId).toBe('pm-beta-001'); + expect(result.Beta!.connectors.Stripe).toEqual({ + connectorId: 'conn-beta-stripe', + credentialProviderArn: 'arn:cred:beta', + credentialProviderName: undefined, + }); + }); + + it('skips only the invalid manager when one of two is missing a required field', () => { + const outputs: StackOutputs = { + ...makeOutputs('Good'), + // Bad is missing resourceRetrievalRoleArn + PaymentBadManagerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/Bad', + PaymentBadManagerId: 'pm-bad-001', + PaymentBadProcessPaymentRoleArn: 'arn:aws:iam::123:role/BadProcessPaymentRole', + }; + + const result = parsePaymentOutputs(outputs, [ + { name: 'Good', connectors: [] }, + { name: 'Bad', connectors: [] }, + ]); + + expect(result.Good).toBeDefined(); + expect(result.Bad).toBeUndefined(); + }); + }); + + describe('authorizerType pass-through', () => { + it('includes authorizerType AWS_IAM when set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', authorizerType: 'AWS_IAM', connectors: [] }]); + + expect(result.MyManager!.authorizerType).toBe('AWS_IAM'); + }); + + it('includes authorizerType CUSTOM_JWT when set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [ + { name: 'MyManager', authorizerType: 'CUSTOM_JWT', connectors: [] }, + ]); + + expect(result.MyManager!.authorizerType).toBe('CUSTOM_JWT'); + }); + + it('omits authorizerType when not set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager!.authorizerType).toBeUndefined(); + }); + }); + + describe('autoPayment / toolAllowlist / networkPreferences pass-through', () => { + it('includes autoPayment: true when set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', autoPayment: true, connectors: [] }]); + + expect(result.MyManager!.autoPayment).toBe(true); + }); + + it('includes autoPayment: false when explicitly set to false', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', autoPayment: false, connectors: [] }]); + + expect(result.MyManager!.autoPayment).toBe(false); + }); + + it('omits autoPayment when not set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager!.autoPayment).toBeUndefined(); + }); + + it('includes paymentToolAllowlist when set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + const allowlist = ['x402_pay', 'x402_check_balance']; + + const result = parsePaymentOutputs(outputs, [ + { name: 'MyManager', paymentToolAllowlist: allowlist, connectors: [] }, + ]); + + expect(result.MyManager!.paymentToolAllowlist).toEqual(allowlist); + }); + + it('omits paymentToolAllowlist when not set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager!.paymentToolAllowlist).toBeUndefined(); + }); + + it('includes networkPreferences when set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + const networks = ['eip155:84532', 'eip155:8453']; + + const result = parsePaymentOutputs(outputs, [ + { name: 'MyManager', networkPreferences: networks, connectors: [] }, + ]); + + expect(result.MyManager!.networkPreferences).toEqual(networks); + }); + + it('omits networkPreferences when not set in spec', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(result.MyManager!.networkPreferences).toBeUndefined(); + }); + + it('passes all optional spec fields through together', () => { + const outputs: StackOutputs = { + ...makeOutputs('MyManager'), + PaymentMyManagerCoinbaseConnectorId: 'conn-001', + }; + + const result = parsePaymentOutputs(outputs, [ + { + name: 'MyManager', + authorizerType: 'AWS_IAM', + autoPayment: true, + paymentToolAllowlist: ['x402_pay'], + networkPreferences: ['eip155:84532'], + connectors: [{ name: 'Coinbase', credentialProviderArn: COINBASE_CREDENTIAL_ARN }], + }, + ]); + + expect(result.MyManager!.authorizerType).toBe('AWS_IAM'); + expect(result.MyManager!.autoPayment).toBe(true); + expect(result.MyManager!.paymentToolAllowlist).toEqual(['x402_pay']); + expect(result.MyManager!.networkPreferences).toEqual(['eip155:84532']); + }); + }); + + describe('edge cases', () => { + it('returns empty object when specs array is empty', () => { + const outputs: StackOutputs = makeOutputs('MyManager'); + + const result = parsePaymentOutputs(outputs, []); + + expect(result).toEqual({}); + }); + + it('returns empty object when outputs is empty', () => { + const result = parsePaymentOutputs({}, [{ name: 'MyManager', connectors: [] }]); + + expect(result).toEqual({}); + }); + + it('ignores unrelated stack outputs', () => { + const outputs: StackOutputs = { + ...makeOutputs('MyManager'), + SomeOtherOutputABC: 'unrelated-value', + ApplicationAgentSomethingRuntimeIdOutput: 'rt-999', + }; + + const result = parsePaymentOutputs(outputs, [{ name: 'MyManager', connectors: [] }]); + + expect(Object.keys(result)).toHaveLength(1); + expect(result.MyManager).toBeDefined(); + }); + }); +}); diff --git a/src/cli/cloudformation/outputs.ts b/src/cli/cloudformation/outputs.ts index 377cc3e9d..43482502f 100644 --- a/src/cli/cloudformation/outputs.ts +++ b/src/cli/cloudformation/outputs.ts @@ -4,6 +4,7 @@ import type { EvaluatorDeployedState, MemoryDeployedState, OnlineEvalDeployedState, + PaymentDeployedState, PolicyDeployedState, PolicyEngineDeployedState, RuntimeEndpointDeployedState, @@ -375,6 +376,73 @@ export function parseRuntimeEndpointOutputs( return endpoints; } +/** + * Strip underscores from a name to produce a valid CDK logical ID segment. + * Must match the toCdkId() function in the vended cdk-stack.ts. + */ +function toPaymentCdkId(name: string): string { + return name.replace(/_/g, ''); +} + +/** + * Parse payment-related CfnOutputs from a deployed stack. + * Output keys follow the pattern: Payment{name}ManagerArn, Payment{name}ManagerId, etc. + * Names have underscores stripped to produce valid CDK logical IDs. + */ +export function parsePaymentOutputs( + outputs: StackOutputs, + paymentSpecs: { + name: string; + authorizerType?: 'AWS_IAM' | 'CUSTOM_JWT'; + autoPayment?: boolean; + paymentToolAllowlist?: string[]; + networkPreferences?: string[]; + connectors: { name: string; credentialProviderArn: string; credentialProviderName?: string }[]; + }[] +): Record { + const payments: Record = {}; + + for (const spec of paymentSpecs) { + const mgrId = toPaymentCdkId(spec.name); + const managerArn = outputs[`Payment${mgrId}ManagerArn`]; + const managerId = outputs[`Payment${mgrId}ManagerId`]; + const processPaymentRoleArn = outputs[`Payment${mgrId}ProcessPaymentRoleArn`]; + const resourceRetrievalRoleArn = outputs[`Payment${mgrId}ResourceRetrievalRoleArn`]; + + if (!managerArn || !managerId || !processPaymentRoleArn || !resourceRetrievalRoleArn) continue; + + const connectors: Record< + string, + { connectorId: string; credentialProviderArn: string; credentialProviderName?: string } + > = {}; + for (const conn of spec.connectors) { + const connId = toPaymentCdkId(conn.name); + const connectorId = outputs[`Payment${mgrId}${connId}ConnectorId`]; + if (connectorId) { + connectors[conn.name] = { + connectorId, + credentialProviderArn: conn.credentialProviderArn, + credentialProviderName: conn.credentialProviderName, + }; + } + } + + payments[spec.name] = { + managerId, + managerArn, + connectors, + processPaymentRoleArn, + resourceRetrievalRoleArn, + ...(spec.authorizerType && { authorizerType: spec.authorizerType }), + ...(spec.autoPayment !== undefined && { autoPayment: spec.autoPayment }), + ...(spec.paymentToolAllowlist && { paymentToolAllowlist: spec.paymentToolAllowlist }), + ...(spec.networkPreferences && { networkPreferences: spec.networkPreferences }), + }; + } + + return payments; +} + export interface BuildDeployedStateOptions { targetName: string; stackName: string; @@ -389,6 +457,7 @@ export interface BuildDeployedStateOptions { policyEngines?: Record; policies?: Record; runtimeEndpoints?: Record; + payments?: Record; } /** @@ -409,6 +478,7 @@ export function buildDeployedState(opts: BuildDeployedStateOptions): DeployedSta policyEngines, policies, runtimeEndpoints, + payments, } = opts; const targetState: TargetDeployedState = { resources: { @@ -466,6 +536,11 @@ export function buildDeployedState(opts: BuildDeployedStateOptions): DeployedSta targetState.resources!.httpGateways = existingHttpGateways; } + // Add payment state from CFN outputs (or preserve credential provider state) + if (payments && Object.keys(payments).length > 0) { + targetState.resources!.payments = payments; + } + return { targets: { ...existingState?.targets, diff --git a/src/cli/commands/deploy/actions.ts b/src/cli/commands/deploy/actions.ts index eba2ab113..59f0dfa90 100644 --- a/src/cli/commands/deploy/actions.ts +++ b/src/cli/commands/deploy/actions.ts @@ -12,6 +12,7 @@ import { parseGatewayOutputs, parseMemoryOutputs, parseOnlineEvalOutputs, + parsePaymentOutputs, parsePolicyEngineOutputs, parsePolicyOutputs, parseRuntimeEndpointOutputs, @@ -41,6 +42,11 @@ import { } from '../../operations/deploy/post-deploy-config-bundles'; import { setupHttpGateways } from '../../operations/deploy/post-deploy-http-gateways'; import { enableOnlineEvalConfigs } from '../../operations/deploy/post-deploy-online-evals'; +import { + cleanupPaymentCredentialProviders, + hasPaymentCredentialProviders, + setupPaymentCredentialProviders, +} from '../../operations/deploy/pre-deploy-identity'; import { toStackName } from '../import/import-utils'; import type { DeployResult } from './types'; import { StackSelectionStrategy } from '@aws-cdk/toolkit-lib'; @@ -253,6 +259,40 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise 0) { const existingPreSynthState = await configIO.readDeployedState().catch(() => ({ targets: {} }) as DeployedState); @@ -269,10 +309,10 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise undefined); + const existingPayments = existingDeployedState?.targets?.[target.name]?.resources?.payments; + if (existingPayments && Object.keys(existingPayments).length > 0) { + startStep('Clean up payment credentials'); + try { + await cleanupPaymentCredentialProviders({ region: target.region, payments: existingPayments }); + endStep('success'); + } catch (cleanupErr) { + endStep('error', `Payment cleanup: ${getErrorMessage(cleanupErr)}`); + // Continue with teardown -- payment cleanup is best-effort + } + } + // After deploying the empty spec, destroy the stack entirely startStep('Tear down stack'); const teardown = await performStackTeardown(target.name); @@ -463,6 +517,21 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise ({ + name: p.name, + authorizerType: p.authorizerType, + autoPayment: p.autoPayment, + paymentToolAllowlist: p.paymentToolAllowlist, + networkPreferences: p.networkPreferences, + connectors: p.connectors.map(c => ({ + name: c.name, + credentialProviderArn: deployedCredentials[c.credentialName]?.credentialProviderArn ?? '', + credentialProviderName: c.credentialName, + })), + })); + const payments = paymentSpecs.length > 0 ? parsePaymentOutputs(outputs, paymentSpecs) : undefined; + const existingState = await configIO.readDeployedState().catch(() => undefined); let deployedState = buildDeployedState({ targetName: target.name, @@ -478,6 +547,7 @@ export async function handleDeploy(options: ValidatedDeployOptions): Promise p.name === Object.keys(payments!)[0]); + const sessionId = await getOrCreatePaymentSession({ + region: targetConfig.region, + managerArn: firstManager.managerArn, + userId: options.userId ?? DEFAULT_RUNTIME_USER_ID, + defaultSpendLimit: paymentSpec?.defaultSpendLimit, + }); + options = { ...options, paymentSessionId: sessionId }; + } catch (err) { + return { + success: false, + error: new Error( + `--auto-session failed to create payment session: ${err instanceof Error ? err.message : String(err)}` + ), + }; + } + } + // Exec mode: run shell command in runtime container if (options.exec) { const logger = new InvokeLogger({ @@ -485,6 +538,8 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption headers: options.headers, bearerToken: options.bearerToken, baggage, + paymentInstrumentId: options.paymentInstrumentId, + paymentSessionId: options.paymentSessionId, }); for await (const chunk of result.stream) { @@ -519,6 +574,8 @@ export async function handleInvoke(context: InvokeContext, options: InvokeOption headers: options.headers, bearerToken: options.bearerToken, baggage, + paymentInstrumentId: options.paymentInstrumentId, + paymentSessionId: options.paymentSessionId, }); logger.logResponse(response.content); diff --git a/src/cli/commands/invoke/command.tsx b/src/cli/commands/invoke/command.tsx index 0f2be6710..bb4d1fe2e 100644 --- a/src/cli/commands/invoke/command.tsx +++ b/src/cli/commands/invoke/command.tsx @@ -127,6 +127,9 @@ export const registerInvoke = (program: Command) => { [] as string[] ) .option('--bearer-token ', 'Bearer token for CUSTOM_JWT auth (bypasses SigV4) [non-interactive]') + .option('--payment-instrument-id ', 'Payment instrument ID for x402 payments [non-interactive]') + .option('--payment-session-id ', 'Payment session ID for budget tracking [non-interactive]') + .option('--auto-session', 'Auto-create/reuse a payment session for testing [non-interactive]') .action( async ( positionalPrompt: string | undefined, @@ -145,6 +148,9 @@ export const registerInvoke = (program: Command) => { timeout?: number; header?: string[]; bearerToken?: string; + paymentInstrumentId?: string; + paymentSessionId?: string; + autoSession?: boolean; } ) => { try { @@ -182,7 +188,10 @@ export const registerInvoke = (program: Command) => { cliOptions.runtime || cliOptions.tool || cliOptions.exec || - cliOptions.bearerToken + cliOptions.bearerToken || + cliOptions.paymentInstrumentId || + cliOptions.paymentSessionId || + cliOptions.autoSession ) { const result = await withCommandRunTelemetry( 'invoke', @@ -220,6 +229,9 @@ export const registerInvoke = (program: Command) => { timeout: cliOptions.timeout, headers, bearerToken: cliOptions.bearerToken, + paymentInstrumentId: cliOptions.paymentInstrumentId, + paymentSessionId: cliOptions.paymentSessionId, + autoSession: cliOptions.autoSession, }; return handleInvokeCLI(options, invokeContext); diff --git a/src/cli/commands/invoke/types.ts b/src/cli/commands/invoke/types.ts index 86411214c..d207c1ed2 100644 --- a/src/cli/commands/invoke/types.ts +++ b/src/cli/commands/invoke/types.ts @@ -22,6 +22,12 @@ export interface InvokeOptions { headers?: Record; /** Bearer token for CUSTOM_JWT auth (bypasses SigV4) */ bearerToken?: string; + /** Payment instrument ID for x402 payments */ + paymentInstrumentId?: string; + /** Payment session ID for budget tracking */ + paymentSessionId?: string; + /** Auto-create/reuse a payment session for testing (runs with developer ManagementRole credentials) */ + autoSession?: boolean; } export type InvokeResult = Result & { diff --git a/src/cli/commands/invoke/validate.ts b/src/cli/commands/invoke/validate.ts index dd97241b8..db1badc4e 100644 --- a/src/cli/commands/invoke/validate.ts +++ b/src/cli/commands/invoke/validate.ts @@ -21,5 +21,17 @@ export function validateInvokeOptions(options: InvokeOptions): ValidationResult if (options.stream && !options.prompt) { return { valid: false, error: 'Prompt is required for streaming' }; } + if (options.autoSession && options.paymentSessionId) { + return { + valid: false, + error: '--auto-session and --payment-session-id are mutually exclusive. Use one or the other.', + }; + } + if (options.paymentInstrumentId?.trim() === '') { + return { valid: false, error: '--payment-instrument-id cannot be empty' }; + } + if (options.paymentSessionId?.trim() === '') { + return { valid: false, error: '--payment-session-id cannot be empty' }; + } return { valid: true }; } diff --git a/src/cli/commands/logs/__tests__/action.test.ts b/src/cli/commands/logs/__tests__/action.test.ts index 1cd58c625..0aca8b124 100644 --- a/src/cli/commands/logs/__tests__/action.test.ts +++ b/src/cli/commands/logs/__tests__/action.test.ts @@ -63,6 +63,7 @@ describe('resolveAgentContext', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }, deployedState: { targets: { @@ -127,6 +128,7 @@ describe('resolveAgentContext', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }, }); const result = resolveAgentContext(context, {}); @@ -171,6 +173,7 @@ describe('resolveAgentContext', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }, deployedState: { targets: { @@ -225,6 +228,7 @@ describe('resolveAgentContext', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }, }); const result = resolveAgentContext(context, {}); diff --git a/src/cli/commands/remove/command.tsx b/src/cli/commands/remove/command.tsx index 369a323d7..3238c2307 100644 --- a/src/cli/commands/remove/command.tsx +++ b/src/cli/commands/remove/command.tsx @@ -1,5 +1,9 @@ -import { ConfigIO, serializeResult, toError } from '../../../lib'; +import { ConfigIO, removeEnvVars, serializeResult, toError } from '../../../lib'; import { getErrorMessage } from '../../errors'; +import { + computePaymentCredentialEnvVarNames, + computeStripePrivyCredentialEnvVarNames, +} from '../../primitives/credential-utils'; import { runCliCommand } from '../../telemetry/cli-command-run.js'; import { COMMAND_DESCRIPTIONS } from '../../tui/copy'; import { requireProject, requireTTY } from '../../tui/guards'; @@ -10,10 +14,26 @@ import type { Command } from '@commander-js/extra-typings'; import { Text, render } from 'ink'; import React from 'react'; -async function handleRemoveAll(_options: RemoveAllOptions): Promise { +async function handleRemoveAll(options: RemoveAllOptions): Promise { try { const configIO = new ConfigIO(); + if (options.dryRun) { + const current = await configIO.readProjectSpec(); + const items: string[] = []; + for (const r of current.runtimes ?? []) items.push(`runtime: ${r.name}`); + for (const m of current.memories ?? []) items.push(`memory: ${m.name}`); + for (const c of current.credentials ?? []) items.push(`credential: ${c.name}`); + for (const p of current.payments ?? []) items.push(`payment-manager: ${p.name}`); + for (const e of current.evaluators ?? []) items.push(`evaluator: ${e.name}`); + for (const g of current.agentCoreGateways ?? []) items.push(`gateway: ${g.name}`); + for (const pe of current.policyEngines ?? []) items.push(`policy-engine: ${pe.name}`); + return { + success: true, + message: items.length > 0 ? `Would remove: ${items.join(', ')}` : 'Nothing to remove', + }; + } + // Get current project name to preserve it let projectName = 'Project'; try { @@ -23,11 +43,35 @@ async function handleRemoveAll(_options: RemoveAllOptions): Promise { await runCliCommand('remove.all', !!options.json, async () => { const result = await handleRemoveAll(options); if (!result.success) throw result.error; - console.log(JSON.stringify(serializeResult(result))); + if (options.json) { + console.log(JSON.stringify(serializeResult(result))); + } else { + console.log(result.message ?? 'All schemas reset to empty state'); + if (result.note) console.log(result.note); + } return {}; }); } diff --git a/src/cli/commands/remove/types.ts b/src/cli/commands/remove/types.ts index b45c3ba4a..752802cad 100644 --- a/src/cli/commands/remove/types.ts +++ b/src/cli/commands/remove/types.ts @@ -12,7 +12,9 @@ export type ResourceType = | 'policy-engine' | 'policy' | 'config-bundle' - | 'ab-test'; + | 'ab-test' + | 'payment-manager' + | 'payment-connector'; export interface RemoveOptions { resourceType: ResourceType; diff --git a/src/cli/commands/status/action.ts b/src/cli/commands/status/action.ts index e821b1f32..465955c5b 100644 --- a/src/cli/commands/status/action.ts +++ b/src/cli/commands/status/action.ts @@ -2,6 +2,7 @@ import { ConfigIO, ResourceNotFoundError, toError } from '../../../lib'; import type { Result } from '../../../lib/result'; import type { AgentCoreProjectSpec, AwsDeploymentTargets, DeployedResourceState, DeployedState } from '../../../schema'; import { getAgentRuntimeStatus } from '../../aws'; +import { getPaymentManager } from '../../aws/agentcore-payments'; import { getEvaluator, getOnlineEvaluationConfig } from '../../aws/agentcore-control'; import { dnsSuffix } from '../../aws/partition'; import { getErrorMessage } from '../../errors'; @@ -23,7 +24,8 @@ export interface ResourceStatusEntry { | 'policy' | 'config-bundle' | 'ab-test' - | 'runtime-endpoint'; + | 'runtime-endpoint' + | 'payment'; name: string; deploymentState: ResourceDeploymentState; identifier?: string; @@ -286,6 +288,14 @@ export function computeResourceStatuses( getParentName: item => item.agentName, }); + const payments = diffResourceSet({ + resourceType: 'payment', + localItems: project.payments ?? [], + deployedRecord: resources?.payments ?? {}, + getIdentifier: deployed => deployed.managerArn, + getLocalDetail: item => `${item.authorizerType} — ${item.pattern} (${item.connectors.length} connector(s))`, + }); + return [ ...agents, ...runtimeEndpoints, @@ -298,6 +308,7 @@ export function computeResourceStatuses( ...policies, ...configBundles, ...abTests, + ...payments, ]; } @@ -471,6 +482,46 @@ export async function handleProjectStatus( const hasOnlineEvalErrors = resources.some(r => r.resourceType === 'online-eval' && r.error); logger.endStep(hasOnlineEvalErrors ? 'error' : 'success'); } + + // Enrich deployed payment managers with live status + const paymentStates = targetResources?.payments ?? {}; + const deployedPayments = resources.filter( + e => e.resourceType === 'payment' && e.deploymentState === 'deployed' && paymentStates[e.name] + ); + + if (deployedPayments.length > 0) { + logger.startStep( + `Fetch payment status (${deployedPayments.length} manager${deployedPayments.length !== 1 ? 's' : ''})` + ); + + await Promise.all( + resources.map(async (entry, i) => { + if (entry.resourceType !== 'payment' || entry.deploymentState !== 'deployed') return; + + const paymentState = paymentStates[entry.name]; + if (!paymentState) return; + + const connectorCount = Object.keys(paymentState.connectors ?? {}).length; + + try { + const managerDetail = await getPaymentManager({ + region: targetConfig.region, + paymentManagerId: paymentState.managerId, + }); + const status = managerDetail?.status ?? 'unknown'; + resources[i] = { ...entry, detail: `${status} — ${connectorCount} connector(s)` }; + logger.log(` ${entry.name}: ${status} (${paymentState.managerId})`); + } catch (error) { + const errorMsg = getErrorMessage(error); + resources[i] = { ...entry, detail: `unknown — ${connectorCount} connector(s)`, error: errorMsg }; + logger.log(` ${entry.name}: unknown (fetch failed) - ${errorMsg}`, 'error'); + } + }) + ); + + const hasPaymentErrors = resources.some(r => r.resourceType === 'payment' && r.error); + logger.endStep(hasPaymentErrors ? 'error' : 'success'); + } } logger.finalize(true); diff --git a/src/cli/commands/status/command.tsx b/src/cli/commands/status/command.tsx index a155d71f0..715b7928e 100644 --- a/src/cli/commands/status/command.tsx +++ b/src/cli/commands/status/command.tsx @@ -16,6 +16,7 @@ const VALID_RESOURCE_TYPES = [ 'gateway', 'evaluator', 'online-eval', + 'payment', 'policy-engine', 'policy', 'config-bundle', @@ -62,7 +63,7 @@ export const registerStatus = (program: Command) => { .option('--target ', 'Select deployment target') .option( '--type ', - 'Filter by resource type (agent, runtime-endpoint, memory, credential, gateway, evaluator, online-eval, policy-engine, policy, config-bundle, ab-test)' + 'Filter by resource type (agent, runtime-endpoint, memory, credential, gateway, evaluator, online-eval, policy-engine, policy, config-bundle, ab-test, payment)' ) .option('--state ', 'Filter by deployment state (deployed, local-only, pending-removal)') .option('--runtime ', 'Filter to a specific runtime') @@ -77,7 +78,7 @@ export const registerStatus = (program: Command) => { Invalid resource type '{cliOptions.type}'. Valid types: {VALID_RESOURCE_TYPES.join(', ')} ); - return; + process.exit(1); } // Validate --state @@ -87,7 +88,7 @@ export const registerStatus = (program: Command) => { Invalid state '{cliOptions.state}'. Valid states: {VALID_STATES.join(', ')} ); - return; + process.exit(1); } try { @@ -153,7 +154,7 @@ export const registerStatus = (program: Command) => { const policies = filtered.filter(r => r.resourceType === 'policy'); const configBundles = filtered.filter(r => r.resourceType === 'config-bundle'); const abTests = filtered.filter(r => r.resourceType === 'ab-test'); - // TODO: Add http-gateway resource type when diffResourceSet for HTTP gateways is added to action.ts + const payments = filtered.filter(r => r.resourceType === 'payment'); render( @@ -292,7 +293,14 @@ export const registerStatus = (program: Command) => { )} - {/* TODO: Add HTTP Gateways render section when diffResourceSet is added to action.ts */} + {payments.length > 0 && ( + + Payments + {payments.map(entry => ( + + ))} + + )} {filtered.length === 0 && No resources match the given filters.} diff --git a/src/cli/commands/validate/__tests__/action.test.ts b/src/cli/commands/validate/__tests__/action.test.ts index 4e8714014..08e967cdb 100644 --- a/src/cli/commands/validate/__tests__/action.test.ts +++ b/src/cli/commands/validate/__tests__/action.test.ts @@ -8,12 +8,22 @@ const { mockReadDeployedState, mockConfigExists, mockFindConfigRoot, + mockExistsSync, + mockReadEnvFile, + mockSecureCredentialsGet, } = vi.hoisted(() => ({ mockReadProjectSpec: vi.fn(), mockReadAWSDeploymentTargets: vi.fn(), mockReadDeployedState: vi.fn(), mockConfigExists: vi.fn(), mockFindConfigRoot: vi.fn(), + mockExistsSync: vi.fn(), + mockReadEnvFile: vi.fn(), + mockSecureCredentialsGet: vi.fn(), +})); + +vi.mock('fs', () => ({ + existsSync: mockExistsSync, })); vi.mock('../../../../lib/index.js', () => { @@ -50,6 +60,15 @@ vi.mock('../../../../lib/index.js', () => { } } + class SecureCredentials { + static fromEnvVars(_vars: Record) { + return new SecureCredentials(); + } + get(key: string) { + return mockSecureCredentialsGet(key); + } + } + return { ConfigIO: class { readProjectSpec = mockReadProjectSpec; @@ -63,6 +82,8 @@ vi.mock('../../../../lib/index.js', () => { ConfigNotFoundError, NoProjectError, findConfigRoot: mockFindConfigRoot, + readEnvFile: mockReadEnvFile, + SecureCredentials, }; }); @@ -215,3 +236,233 @@ describe('handleValidate', () => { expect(result.error.message).toBe('string error'); }); }); + +describe('payment validation', () => { + const CONFIG_ROOT = '/project/agentcore'; + + const baseSpec = { + name: 'Test', + version: 1, + managedBy: 'CDK' as const, + runtimes: [], + }; + + const coinbaseCredential = { + name: 'my-cred', + authorizerType: 'PaymentCredentialProvider', + provider: 'CoinbaseCDP', + }; + + const validPaymentSpec = { + ...baseSpec, + credentials: [coinbaseCredential], + payments: [ + { + name: 'my-manager', + connectors: [{ name: 'my-connector', credentialName: 'my-cred', provider: 'CoinbaseCDP' }], + }, + ], + }; + + afterEach(() => vi.clearAllMocks()); + + it('passes with valid config and .env.local present', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue(validPaymentSpec); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({}); + // All three CoinbaseCDP vars present with real values + mockSecureCredentialsGet.mockImplementation((key: string) => { + const map: Record = { + AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_ID: 'key-id', + AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_SECRET: 'key-secret', + AGENTCORE_CREDENTIAL_MY_CRED_WALLET_SECRET: 'wallet-secret', + }; + return map[key]; + }); + + const result = await handleValidate({}); + + expect(result.success).toBe(true); + }); + + it('fails when payment manager has zero connectors', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue({ + ...baseSpec, + payments: [{ name: 'empty-manager', connectors: [] }], + }); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('"empty-manager" has no connectors'); + expect(result.error.message).toContain('--manager empty-manager'); + }); + + it('fails when connector references a credential that does not exist', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue({ + ...baseSpec, + credentials: [], + payments: [ + { + name: 'my-manager', + connectors: [{ name: 'my-connector', credentialName: 'ghost-cred' }], + }, + ], + }); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('"ghost-cred" which does not exist'); + expect(result.error.message).toContain('"my-connector"'); + }); + + it('fails when referenced credential has wrong authorizerType', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue({ + ...baseSpec, + credentials: [{ name: 'bad-cred', authorizerType: 'OAuth2' }], + payments: [ + { + name: 'my-manager', + connectors: [{ name: 'my-connector', credentialName: 'bad-cred' }], + }, + ], + }); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('"OAuth2"'); + expect(result.error.message).toContain('"PaymentCredentialProvider"'); + expect(result.error.message).toContain('"my-connector"'); + }); + + it('fails when connector provider does not match credential provider', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue({ + ...baseSpec, + credentials: [{ name: 'my-cred', authorizerType: 'PaymentCredentialProvider', provider: 'StripePrivy' }], + payments: [ + { + name: 'my-manager', + connectors: [{ name: 'my-connector', credentialName: 'my-cred', provider: 'CoinbaseCDP' }], + }, + ], + }); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('"CoinbaseCDP"'); + expect(result.error.message).toContain('"StripePrivy"'); + expect(result.error.message).toContain('"my-connector"'); + }); + + it('fails with variable list when .env.local is missing and connectors exist', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue(validPaymentSpec); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + mockExistsSync.mockReturnValue(false); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('.env.local not found'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_ID'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_SECRET'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_MY_CRED_WALLET_SECRET'); + }); + + it('fails naming missing CoinbaseCDP vars when .env.local exists but vars are absent', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue(validPaymentSpec); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({}); + // Only api key id is set; secret and wallet secret are missing + mockSecureCredentialsGet.mockImplementation((key: string) => { + if (key === 'AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_ID') return 'key-id'; + return undefined; + }); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('Missing CoinbaseCDP credentials'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_SECRET'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_MY_CRED_WALLET_SECRET'); + expect(result.error.message).not.toContain('AGENTCORE_CREDENTIAL_MY_CRED_API_KEY_ID'); + }); + + it('fails naming missing StripePrivy vars when .env.local exists but vars are absent', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue({ + ...baseSpec, + credentials: [{ name: 'stripe-cred', authorizerType: 'PaymentCredentialProvider', provider: 'StripePrivy' }], + payments: [ + { + name: 'stripe-manager', + connectors: [{ name: 'stripe-connector', credentialName: 'stripe-cred', provider: 'StripePrivy' }], + }, + ], + }); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({}); + // Only app id is present; the other three are missing + mockSecureCredentialsGet.mockImplementation((key: string) => { + if (key === 'AGENTCORE_CREDENTIAL_STRIPE_CRED_APP_ID') return 'app-id'; + return undefined; + }); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('Missing StripePrivy credentials'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_STRIPE_CRED_APP_SECRET'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_STRIPE_CRED_AUTHORIZATION_PRIVATE_KEY'); + expect(result.error.message).toContain('AGENTCORE_CREDENTIAL_STRIPE_CRED_AUTHORIZATION_ID'); + expect(result.error.message).not.toContain('AGENTCORE_CREDENTIAL_STRIPE_CRED_APP_ID'); + }); + + it('fails when credential values in .env.local are whitespace-only', async () => { + mockFindConfigRoot.mockReturnValue(CONFIG_ROOT); + mockReadProjectSpec.mockResolvedValue(validPaymentSpec); + mockReadAWSDeploymentTargets.mockResolvedValue([]); + mockConfigExists.mockReturnValue(false); + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({}); + // All three vars exist but contain only whitespace + mockSecureCredentialsGet.mockReturnValue(' '); + + const result = await handleValidate({}); + + expect(result.success).toBe(false); + assert(!result.success); + expect(result.error.message).toContain('Missing CoinbaseCDP credentials'); + }); +}); diff --git a/src/cli/commands/validate/action.ts b/src/cli/commands/validate/action.ts index b6d12566b..723fa6548 100644 --- a/src/cli/commands/validate/action.ts +++ b/src/cli/commands/validate/action.ts @@ -1,3 +1,5 @@ +import { existsSync } from 'fs'; +import { join } from 'path'; import { ConfigIO, ConfigNotFoundError, @@ -5,9 +7,15 @@ import { ConfigReadError, ConfigValidationError, NoProjectError, + SecureCredentials, findConfigRoot, + readEnvFile, } from '../../../lib'; import type { Result } from '../../../lib/result'; +import { + computePaymentCredentialEnvVarNames, + computeStripePrivyCredentialEnvVarNames, +} from '../../primitives/credential-utils'; export interface ValidateOptions { directory?: string; @@ -32,12 +40,115 @@ export async function handleValidate(options: ValidateOptions): Promise const configIO = new ConfigIO({ baseDir: configRoot }); // Validate project spec (agentcore.json) + let projectSpec; try { - await configIO.readProjectSpec(); + projectSpec = await configIO.readProjectSpec(); } catch (err) { return { success: false, error: new Error(formatError(err, 'agentcore.json'), { cause: err }) }; } + // Validate payment credential completeness (local only, no network calls) + if (projectSpec.payments && projectSpec.payments.length > 0) { + for (const payment of projectSpec.payments) { + if (payment.connectors.length === 0) { + return { + success: false, + error: new Error(`Payment manager "${payment.name}" has no connectors. Add a connector with \`agentcore add payment-connector --manager ${payment.name}\``), + }; + } + for (const connector of payment.connectors) { + const credential = projectSpec.credentials?.find(c => c.name === connector.credentialName); + if (!credential) { + return { + success: false, + error: new Error(`Payment connector "${connector.name}" (manager "${payment.name}") references credential "${connector.credentialName}" which does not exist.`), + }; + } + if (credential.authorizerType !== 'PaymentCredentialProvider') { + return { + success: false, + error: new Error(`Payment connector "${connector.name}" references credential "${connector.credentialName}" with type "${credential.authorizerType}" — expected "PaymentCredentialProvider".`), + }; + } + const connectorProvider = connector.provider ?? 'CoinbaseCDP'; + const credentialProvider = 'provider' in credential ? (credential as { provider: string }).provider : undefined; + if (credentialProvider && credentialProvider !== connectorProvider) { + return { + success: false, + error: new Error(`Payment connector "${connector.name}" uses provider "${connectorProvider}" but credential "${connector.credentialName}" is configured for "${credentialProvider}".`), + }; + } + } + } + + // Check .env.local has required variables + const hasConnectors = projectSpec.payments.some(p => p.connectors.length > 0); + const envFilePath = join(configRoot, '.env.local'); + if (hasConnectors && !existsSync(envFilePath)) { + const expectedVars: string[] = []; + for (const payment of projectSpec.payments) { + for (const connector of payment.connectors) { + const provider = connector.provider ?? 'CoinbaseCDP'; + if (provider === 'StripePrivy') { + const vars = computeStripePrivyCredentialEnvVarNames(connector.credentialName); + expectedVars.push(vars.appId, vars.appSecret, vars.authorizationPrivateKey, vars.authorizationId); + } else { + const vars = computePaymentCredentialEnvVarNames(connector.credentialName); + expectedVars.push(vars.apiKeyId, vars.apiKeySecret, vars.walletSecret); + } + } + } + return { + success: false, + error: new Error(`agentcore/.env.local not found. Payment credentials required:\n${expectedVars.map(v => ` ${v}`).join('\n')}\n\nRun 'agentcore add payment-connector --manager ' to set credentials interactively.`), + }; + } + if (existsSync(envFilePath)) { + try { + const envVars = await readEnvFile(configRoot); + const credentials = SecureCredentials.fromEnvVars(envVars); + for (const payment of projectSpec.payments) { + for (const connector of payment.connectors) { + const provider = connector.provider ?? 'CoinbaseCDP'; + if (provider === 'StripePrivy') { + const vars = computeStripePrivyCredentialEnvVarNames(connector.credentialName); + const missing = [ + !credentials.get(vars.appId)?.trim() && vars.appId, + !credentials.get(vars.appSecret)?.trim() && vars.appSecret, + !credentials.get(vars.authorizationPrivateKey)?.trim() && vars.authorizationPrivateKey, + !credentials.get(vars.authorizationId)?.trim() && vars.authorizationId, + ].filter(Boolean); + if (missing.length > 0) { + return { + success: false, + error: new Error(`Missing StripePrivy credentials for connector "${connector.name}" in .env.local: ${missing.join(', ')}`), + }; + } + } else { + const vars = computePaymentCredentialEnvVarNames(connector.credentialName); + const missing = [ + !credentials.get(vars.apiKeyId)?.trim() && vars.apiKeyId, + !credentials.get(vars.apiKeySecret)?.trim() && vars.apiKeySecret, + !credentials.get(vars.walletSecret)?.trim() && vars.walletSecret, + ].filter(Boolean); + if (missing.length > 0) { + return { + success: false, + error: new Error(`Missing CoinbaseCDP credentials for connector "${connector.name}" in .env.local: ${missing.join(', ')}`), + }; + } + } + } + } + } catch (error) { + return { + success: false, + error: new Error(`Failed to read .env.local: ${error instanceof Error ? error.message : String(error)}. Fix the file or re-run 'agentcore add payment-connector' to set credentials.`), + }; + } + } + } + // Validate AWS targets (aws-targets.json) try { await configIO.readAWSDeploymentTargets(); diff --git a/src/cli/commands/validate/command.tsx b/src/cli/commands/validate/command.tsx index 7f2fb2bff..ab5c59b91 100644 --- a/src/cli/commands/validate/command.tsx +++ b/src/cli/commands/validate/command.tsx @@ -7,11 +7,19 @@ export const registerValidate = (program: Command) => { program .command('validate') .option('-d, --directory ', 'Project directory containing agentcore config') + .option('--json', 'Output as JSON [non-interactive]') .description(COMMAND_DESCRIPTIONS.validate) .action(async options => { const result = await handleValidate(options); - if (result.success) { + if (options.json) { + if (result.success) { + console.log(JSON.stringify({ success: true })); + } else { + console.log(JSON.stringify({ success: false, error: result.error.message })); + } + process.exit(result.success ? 0 : 1); + } else if (result.success) { render(Valid); process.exit(0); } else { diff --git a/src/cli/errors.ts b/src/cli/errors.ts index 99c59c051..ccca6fa16 100644 --- a/src/cli/errors.ts +++ b/src/cli/errors.ts @@ -107,6 +107,34 @@ export function isExpiredTokenError(err: unknown): boolean { return false; } +/** + * Checks if an error indicates a service quota or resource limit has been exceeded. + */ +export function isQuotaExceededError(err: unknown): boolean { + if (!err || typeof err !== 'object') { + return false; + } + + const error = err as Record; + + if ( + error.code === 'ServiceQuotaExceededException' || + error.code === 'LimitExceededException' || + error.code === 'TooManyRequestsException' + ) { + return true; + } + + const message = getErrorMessage(err).toLowerCase(); + return ( + message.includes('quota exceeded') || + message.includes('limit exceeded') || + message.includes('too many') || + message.includes('maximum number') || + message.includes('maxmanagers') + ); +} + /** * Checks if an error indicates the CloudFormation stack is in a transitional state. * These errors occur when trying to deploy to a stack that is currently being updated. diff --git a/src/cli/external-requirements/__tests__/checks-extended.test.ts b/src/cli/external-requirements/__tests__/checks-extended.test.ts index 462d9be14..58d52dcae 100644 --- a/src/cli/external-requirements/__tests__/checks-extended.test.ts +++ b/src/cli/external-requirements/__tests__/checks-extended.test.ts @@ -56,6 +56,7 @@ describe('requiresUv', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresUv(project)).toBe(true); }); @@ -84,6 +85,7 @@ describe('requiresUv', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresUv(project)).toBe(false); }); @@ -103,6 +105,7 @@ describe('requiresUv', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresUv(project)).toBe(false); }); @@ -133,6 +136,7 @@ describe('requiresContainerRuntime', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresContainerRuntime(project)).toBe(true); }); @@ -161,6 +165,7 @@ describe('requiresContainerRuntime', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresContainerRuntime(project)).toBe(false); }); @@ -180,6 +185,7 @@ describe('requiresContainerRuntime', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresContainerRuntime(project)).toBe(false); }); @@ -216,6 +222,7 @@ describe('requiresContainerRuntime', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(requiresContainerRuntime(project)).toBe(true); }); @@ -286,6 +293,7 @@ describe('checkDependencyVersions', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const result = await checkDependencyVersions(project); @@ -309,6 +317,7 @@ describe('checkDependencyVersions', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const result = await checkDependencyVersions(project); @@ -340,6 +349,7 @@ describe('checkDependencyVersions', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const result = await checkDependencyVersions(project); diff --git a/src/cli/logging/remove-logger.ts b/src/cli/logging/remove-logger.ts index 54f8aa0ba..4d0f42b50 100644 --- a/src/cli/logging/remove-logger.ts +++ b/src/cli/logging/remove-logger.ts @@ -19,7 +19,9 @@ export interface RemoveLoggerOptions { | 'policy-engine' | 'policy' | 'config-bundle' - | 'ab-test'; + | 'ab-test' + | 'payment-manager' + | 'payment-connector'; /** Name of the resource being removed */ resourceName: string; } diff --git a/src/cli/operations/agent/generate/schema-mapper.ts b/src/cli/operations/agent/generate/schema-mapper.ts index 523c89a61..d82111454 100644 --- a/src/cli/operations/agent/generate/schema-mapper.ts +++ b/src/cli/operations/agent/generate/schema-mapper.ts @@ -280,6 +280,14 @@ export async function mapGenerateConfigToRenderConfig( hasMemory: isMcp || config.language === 'TypeScript' ? false : config.memory !== 'none', hasIdentity: isMcp ? false : identityProviders.length > 0, hasGateway: gatewayProviders.length > 0, + hasPayment: await (async () => { + try { + const spec = await new ConfigIO().readProjectSpec(); + return spec.payments.length > 0; + } catch { + return false; + } + })(), isVpc: config.networkMode === 'VPC', buildType: config.buildType, memoryProviders: diff --git a/src/cli/operations/agent/generate/write-agent-to-project.ts b/src/cli/operations/agent/generate/write-agent-to-project.ts index 38c89fd85..f40c208bf 100644 --- a/src/cli/operations/agent/generate/write-agent-to-project.ts +++ b/src/cli/operations/agent/generate/write-agent-to-project.ts @@ -74,6 +74,7 @@ export async function writeAgentToProject(config: GenerateConfig, options?: Writ configBundles: [], abTests: [], httpGateways: [], + payments: [], }; await configIO.writeProjectSpec(project); diff --git a/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts b/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts index 75f36ebcc..2d9d3cceb 100644 --- a/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts +++ b/src/cli/operations/deploy/__tests__/post-deploy-ab-tests.test.ts @@ -69,6 +69,7 @@ function makeProjectSpec(abTests: AgentCoreProjectSpec['abTests'] = []): AgentCo configBundles: [], httpGateways: [], abTests, + payments: [], }; } diff --git a/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts b/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts index ecfc285cd..e3c701b9c 100644 --- a/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts +++ b/src/cli/operations/deploy/__tests__/post-deploy-config-bundles.test.ts @@ -507,6 +507,7 @@ describe('resolveConfigBundleComponentKeys', () => { configBundles, httpGateways: [], abTests: [], + payments: [], }; } diff --git a/src/cli/operations/deploy/__tests__/post-deploy-http-gateways.test.ts b/src/cli/operations/deploy/__tests__/post-deploy-http-gateways.test.ts index 32c7e6252..0450b135a 100644 --- a/src/cli/operations/deploy/__tests__/post-deploy-http-gateways.test.ts +++ b/src/cli/operations/deploy/__tests__/post-deploy-http-gateways.test.ts @@ -81,6 +81,7 @@ function makeProjectSpec(httpGateways: AgentCoreProjectSpec['httpGateways'] = [] configBundles: [], abTests: [], httpGateways, + payments: [], }; } diff --git a/src/cli/operations/deploy/__tests__/pre-deploy-payments.test.ts b/src/cli/operations/deploy/__tests__/pre-deploy-payments.test.ts new file mode 100644 index 000000000..1eedee2b1 --- /dev/null +++ b/src/cli/operations/deploy/__tests__/pre-deploy-payments.test.ts @@ -0,0 +1,475 @@ +import { cleanupPaymentCredentialProviders, setupPaymentCredentialProviders } from '../pre-deploy-identity.js'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +// ============================================================================ +// Hoisted mocks +// ============================================================================ + +const { + mockCreatePaymentCredentialProvider, + mockUpdatePaymentCredentialProvider, + mockGetPaymentCredentialProvider, + mockDeletePaymentCredentialProvider, + mockReadEnvFile, + mockExistsSync, +} = vi.hoisted(() => ({ + mockCreatePaymentCredentialProvider: vi.fn(), + mockUpdatePaymentCredentialProvider: vi.fn(), + mockGetPaymentCredentialProvider: vi.fn(), + mockDeletePaymentCredentialProvider: vi.fn(), + mockReadEnvFile: vi.fn(), + mockExistsSync: vi.fn(), +})); + +vi.mock('../../../aws/agentcore-payments', () => ({ + createPaymentCredentialProvider: mockCreatePaymentCredentialProvider, + updatePaymentCredentialProvider: mockUpdatePaymentCredentialProvider, + getPaymentCredentialProvider: mockGetPaymentCredentialProvider, + deletePaymentCredentialProvider: mockDeletePaymentCredentialProvider, +})); + +vi.mock('../../../../lib', () => ({ + SecureCredentials: class { + constructor(private envVars: Record) {} + static fromEnvVars(envVars: Record) { + return new this(envVars); + } + merge(_other: unknown) { + return this; + } + get(key: string) { + return this.envVars[key]; + } + }, + readEnvFile: mockReadEnvFile, +})); + +vi.mock('fs', () => ({ + existsSync: mockExistsSync, +})); + +vi.mock('../../../errors', () => ({ + isNoCredentialsError: () => false, + isQuotaExceededError: () => false, +})); + +vi.mock('../../../external-requirements/checks', () => ({ + getAwsLoginGuidance: vi.fn().mockResolvedValue('Run: aws sso login'), +})); + +// ============================================================================ +// Shared fixtures +// ============================================================================ + +const BASE_DIR = '/project/agentcore'; +const REGION = 'us-east-1'; + +function makeCoinbaseSpec(credentialName = 'my-cdp-cred') { + return { + name: 'test-project', + payments: [ + { + name: 'my-payment-manager', + connectors: [ + { + name: 'my-connector', + provider: 'CoinbaseCDP' as const, + credentialName, + }, + ], + }, + ], + credentials: [ + { + name: credentialName, + authorizerType: 'PaymentCredentialProvider' as const, + }, + ], + runtimes: [], + }; +} + +function makeStripePrivySpec(credentialName = 'my-stripe-cred') { + return { + name: 'test-project', + payments: [ + { + name: 'my-payment-manager', + connectors: [ + { + name: 'my-connector', + provider: 'StripePrivy' as const, + credentialName, + }, + ], + }, + ], + credentials: [ + { + name: credentialName, + authorizerType: 'PaymentCredentialProvider' as const, + }, + ], + runtimes: [], + }; +} + +// ============================================================================ +// setupPaymentCredentialProviders +// ============================================================================ + +describe('setupPaymentCredentialProviders', () => { + afterEach(() => vi.clearAllMocks()); + + it('returns empty credentialProviders when payments array is empty', async () => { + const projectSpec = { + name: 'test-project', + payments: [], + credentials: [], + runtimes: [], + }; + + const result = await setupPaymentCredentialProviders({ + projectSpec: projectSpec as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(false); + expect(result.errors).toHaveLength(0); + expect(result.credentialProviders).toEqual({}); + expect(mockGetPaymentCredentialProvider).not.toHaveBeenCalled(); + expect(mockCreatePaymentCredentialProvider).not.toHaveBeenCalled(); + }); + + it('returns error when .env.local does not exist', async () => { + mockExistsSync.mockReturnValue(false); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeCoinbaseSpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(true); + expect(result.errors).toHaveLength(1); + expect(result.errors[0]).toContain('agentcore/.env.local not found'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_ID'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_SECRET'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_CDP_CRED_WALLET_SECRET'); + expect(result.credentialProviders).toEqual({}); + expect(mockCreatePaymentCredentialProvider).not.toHaveBeenCalled(); + }); + + it('lists all required StripePrivy vars in the missing .env.local error', async () => { + mockExistsSync.mockReturnValue(false); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeStripePrivySpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(true); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_ID'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_SECRET'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_PRIVATE_KEY'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_ID'); + }); + + it('creates a new credential provider when none exists', async () => { + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_ID: 'key-id-123', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_SECRET: 'key-secret-abc', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_WALLET_SECRET: 'wallet-secret-xyz', + }); + mockGetPaymentCredentialProvider.mockResolvedValue(null); + mockCreatePaymentCredentialProvider.mockResolvedValue({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + status: 'ACTIVE', + }); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeCoinbaseSpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(false); + expect(result.errors).toHaveLength(0); + expect(mockCreatePaymentCredentialProvider).toHaveBeenCalledOnce(); + expect(mockUpdatePaymentCredentialProvider).not.toHaveBeenCalled(); + expect(result.credentialProviders['my-cdp-cred']).toEqual({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + credentialProviderName: 'my-cdp-cred', + }); + }); + + it('updates an existing credential provider when one already exists', async () => { + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_ID: 'key-id-123', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_SECRET: 'key-secret-abc', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_WALLET_SECRET: 'wallet-secret-xyz', + }); + mockGetPaymentCredentialProvider.mockResolvedValue({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + name: 'my-cdp-cred', + status: 'ACTIVE', + }); + mockUpdatePaymentCredentialProvider.mockResolvedValue({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + status: 'ACTIVE', + }); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeCoinbaseSpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(false); + expect(mockUpdatePaymentCredentialProvider).toHaveBeenCalledOnce(); + expect(mockCreatePaymentCredentialProvider).not.toHaveBeenCalled(); + expect(result.credentialProviders['my-cdp-cred']?.credentialProviderArn).toBe( + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred' + ); + }); + + it('returns error when specific CoinbaseCDP env vars are missing from .env.local', async () => { + mockExistsSync.mockReturnValue(true); + // Only provide apiKeyId — leave secret and walletSecret absent + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_ID: 'key-id-123', + }); + mockGetPaymentCredentialProvider.mockResolvedValue(null); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeCoinbaseSpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(true); + expect(result.errors).toHaveLength(1); + expect(result.errors[0]).toContain('Missing CDP credentials'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_SECRET'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_CDP_CRED_WALLET_SECRET'); + expect(mockCreatePaymentCredentialProvider).not.toHaveBeenCalled(); + }); + + it('returns error when specific StripePrivy env vars are missing from .env.local', async () => { + mockExistsSync.mockReturnValue(true); + // Provide only appId — leave others absent + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_ID: 'app-id-123', + }); + mockGetPaymentCredentialProvider.mockResolvedValue(null); + + const result = await setupPaymentCredentialProviders({ + projectSpec: makeStripePrivySpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(result.hasErrors).toBe(true); + expect(result.errors).toHaveLength(1); + expect(result.errors[0]).toContain('Missing StripePrivy credentials'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_SECRET'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_PRIVATE_KEY'); + expect(result.errors[0]).toContain('AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_ID'); + expect(mockCreatePaymentCredentialProvider).not.toHaveBeenCalled(); + }); + + it('resolves all 3 CoinbaseCDP env vars and passes them to create', async () => { + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_ID: 'key-id-123', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_API_KEY_SECRET: 'key-secret-abc', + AGENTCORE_CREDENTIAL_MY_CDP_CRED_WALLET_SECRET: 'wallet-secret-xyz', + }); + mockGetPaymentCredentialProvider.mockResolvedValue(null); + mockCreatePaymentCredentialProvider.mockResolvedValue({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + status: 'ACTIVE', + }); + + await setupPaymentCredentialProviders({ + projectSpec: makeCoinbaseSpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(mockCreatePaymentCredentialProvider).toHaveBeenCalledWith( + expect.objectContaining({ + vendor: 'CoinbaseCDP', + name: 'my-cdp-cred', + apiKeyId: 'key-id-123', + apiKeySecret: 'key-secret-abc', + walletSecret: 'wallet-secret-xyz', + region: REGION, + }) + ); + }); + + it('resolves all 4 StripePrivy env vars and passes them to create', async () => { + mockExistsSync.mockReturnValue(true); + mockReadEnvFile.mockResolvedValue({ + AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_ID: 'app-id-123', + AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_APP_SECRET: 'app-secret-abc', + AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_PRIVATE_KEY: 'priv-key-xyz', + AGENTCORE_CREDENTIAL_MY_STRIPE_CRED_AUTHORIZATION_ID: 'auth-id-456', + }); + mockGetPaymentCredentialProvider.mockResolvedValue(null); + mockCreatePaymentCredentialProvider.mockResolvedValue({ + credentialProviderArn: 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-stripe-cred', + status: 'ACTIVE', + }); + + await setupPaymentCredentialProviders({ + projectSpec: makeStripePrivySpec() as any, + configBaseDir: BASE_DIR, + region: REGION, + }); + + expect(mockCreatePaymentCredentialProvider).toHaveBeenCalledWith( + expect.objectContaining({ + vendor: 'StripePrivy', + name: 'my-stripe-cred', + appId: 'app-id-123', + appSecret: 'app-secret-abc', + authorizationPrivateKey: 'priv-key-xyz', + authorizationId: 'auth-id-456', + region: REGION, + }) + ); + }); +}); + +// ============================================================================ +// cleanupPaymentCredentialProviders +// ============================================================================ + +describe('cleanupPaymentCredentialProviders', () => { + afterEach(() => vi.clearAllMocks()); + + it('deletes credential providers by name extracted from ARN', async () => { + mockDeletePaymentCredentialProvider.mockResolvedValue(undefined); + + await cleanupPaymentCredentialProviders({ + region: REGION, + payments: { + 'my-payment-manager': { + connectors: { + 'my-connector': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + }, + }, + }, + }, + }); + + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledOnce(); + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledWith({ + region: REGION, + name: 'my-cdp-cred', + }); + }); + + it('deletes multiple credential providers across managers and connectors', async () => { + mockDeletePaymentCredentialProvider.mockResolvedValue(undefined); + + await cleanupPaymentCredentialProviders({ + region: REGION, + payments: { + 'manager-a': { + connectors: { + 'connector-1': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/cred-one', + }, + 'connector-2': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/cred-two', + }, + }, + }, + 'manager-b': { + connectors: { + 'connector-3': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/cred-three', + }, + }, + }, + }, + }); + + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledTimes(3); + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledWith({ region: REGION, name: 'cred-one' }); + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledWith({ region: REGION, name: 'cred-two' }); + expect(mockDeletePaymentCredentialProvider).toHaveBeenCalledWith({ region: REGION, name: 'cred-three' }); + }); + + it('ignores 404 errors gracefully without throwing', async () => { + mockDeletePaymentCredentialProvider.mockRejectedValue(new Error('Payment API error (404): resource not found')); + + await expect( + cleanupPaymentCredentialProviders({ + region: REGION, + payments: { + 'my-payment-manager': { + connectors: { + 'my-connector': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + }, + }, + }, + }, + }) + ).resolves.toBeUndefined(); + }); + + it('ignores NotFound errors gracefully without throwing', async () => { + mockDeletePaymentCredentialProvider.mockRejectedValue(new Error('ResourceNotFoundException: not found')); + + await expect( + cleanupPaymentCredentialProviders({ + region: REGION, + payments: { + 'my-payment-manager': { + connectors: { + 'my-connector': { + credentialProviderArn: + 'arn:aws:bedrock-agentcore:us-east-1:123456789:payment-credential-provider/my-cdp-cred', + }, + }, + }, + }, + }) + ).resolves.toBeUndefined(); + }); + + it('makes no API calls when payments object is empty', async () => { + await cleanupPaymentCredentialProviders({ + region: REGION, + payments: {}, + }); + + expect(mockDeletePaymentCredentialProvider).not.toHaveBeenCalled(); + }); + + it('makes no API calls when a manager has no connectors', async () => { + await cleanupPaymentCredentialProviders({ + region: REGION, + payments: { + 'my-payment-manager': {}, + }, + }); + + expect(mockDeletePaymentCredentialProvider).not.toHaveBeenCalled(); + }); +}); diff --git a/src/cli/operations/deploy/index.ts b/src/cli/operations/deploy/index.ts index 93cdb6353..d3ad758c5 100644 --- a/src/cli/operations/deploy/index.ts +++ b/src/cli/operations/deploy/index.ts @@ -41,6 +41,16 @@ export { type DestroyTargetOptions, } from './teardown'; +// Pre-deploy payment credential setup +export { + setupPaymentCredentialProviders, + hasPaymentCredentialProviders, + cleanupPaymentCredentialProviders, + type SetupPaymentCredentialProvidersOptions, + type PaymentCredentialProvidersResult, + type PaymentCredentialProviderResult, +} from './pre-deploy-identity'; + // Post-deploy observability setup export { setupTransactionSearch } from './post-deploy-observability'; diff --git a/src/cli/operations/deploy/pre-deploy-identity.ts b/src/cli/operations/deploy/pre-deploy-identity.ts index 8484f16aa..d91254c14 100644 --- a/src/cli/operations/deploy/pre-deploy-identity.ts +++ b/src/cli/operations/deploy/pre-deploy-identity.ts @@ -1,9 +1,19 @@ import { SecureCredentials, readEnvFile } from '../../../lib'; import type { AgentCoreProjectSpec, Credential } from '../../../schema'; import { getCredentialProvider } from '../../aws'; -import { isNoCredentialsError } from '../../errors'; +import { + createPaymentCredentialProvider, + deletePaymentCredentialProvider, + getPaymentCredentialProvider, + updatePaymentCredentialProvider, +} from '../../aws/agentcore-payments'; +import { isNoCredentialsError, isQuotaExceededError } from '../../errors'; import { getAwsLoginGuidance } from '../../external-requirements/checks'; -import { computeDefaultCredentialEnvVarName } from '../../primitives/credential-utils'; +import { + computeDefaultCredentialEnvVarName, + computePaymentCredentialEnvVarNames, + computeStripePrivyCredentialEnvVarNames, +} from '../../primitives/credential-utils'; import { apiKeyProviderExists, createApiKeyProvider, @@ -15,6 +25,8 @@ import { } from '../identity'; import { BedrockAgentCoreControlClient, GetTokenVaultCommand } from '@aws-sdk/client-bedrock-agentcore-control'; import { CreateKeyCommand, KMSClient } from '@aws-sdk/client-kms'; +import { existsSync } from 'fs'; +import { join } from 'path'; // ───────────────────────────────────────────────────────────────────────────── // Types @@ -85,6 +97,9 @@ export async function setupApiKeyProviders(options: SetupApiKeyProvidersOptions) // Set up each credential in the project for (const credential of projectSpec.credentials) { + // Skip payment credentials — handled by setupPaymentCredentialProviders below + if (credential.authorizerType === 'PaymentCredentialProvider') continue; + if (credential.authorizerType === 'ApiKeyCredentialProvider') { const result = await setupApiKeyCredentialProvider(client, credential, allCredentials); results.push(result); @@ -393,3 +408,223 @@ async function setupSingleOAuth2Provider( return { providerName: credential.name, status: 'error', error: errorMessage }; } } + +// ───────────────────────────────────────────────────────────────────────────── +// Payment Credential Providers +// ───────────────────────────────────────────────────────────────────────────── + +export interface PaymentCredentialProviderResult { + credentialProviderArn: string; + credentialProviderName: string; +} + +export interface PaymentCredentialProvidersResult { + credentialProviders: Record; + hasErrors: boolean; + errors: string[]; +} + +export interface SetupPaymentCredentialProvidersOptions { + projectSpec: AgentCoreProjectSpec; + configBaseDir: string; + region: string; + runtimeCredentials?: SecureCredentials; +} + +export function hasPaymentCredentialProviders(projectSpec: AgentCoreProjectSpec): boolean { + return projectSpec.payments.length > 0; +} + +export async function setupPaymentCredentialProviders( + options: SetupPaymentCredentialProvidersOptions +): Promise { + const { projectSpec, configBaseDir, region, runtimeCredentials } = options; + + const result: PaymentCredentialProvidersResult = { + credentialProviders: {}, + hasErrors: false, + errors: [], + }; + + if (projectSpec.payments.length === 0) { + return result; + } + + const envFilePath = join(configBaseDir, '.env.local'); + if (!existsSync(envFilePath)) { + const expectedVars: string[] = []; + for (const payment of projectSpec.payments) { + for (const connector of payment.connectors) { + if (connector.provider === 'StripePrivy') { + const vars = computeStripePrivyCredentialEnvVarNames(connector.credentialName); + expectedVars.push(vars.appId, vars.appSecret, vars.authorizationPrivateKey, vars.authorizationId); + } else { + const vars = computePaymentCredentialEnvVarNames(connector.credentialName); + expectedVars.push(vars.apiKeyId, vars.apiKeySecret, vars.walletSecret); + } + } + } + const varList = + expectedVars.length > 0 ? `\n\nRequired variables:\n${expectedVars.map(v => ` ${v}`).join('\n')}` : ''; + return { + hasErrors: true, + errors: [ + `agentcore/.env.local not found. Payment connectors require credential environment variables.${varList}\n\nTo fix: create agentcore/.env.local with the variables above, or re-run 'agentcore add payment-connector --manager ' to enter credentials interactively.`, + ], + credentialProviders: {}, + }; + } + + const envVars = await readEnvFile(configBaseDir); + const envCredentials = SecureCredentials.fromEnvVars(envVars); + const allCredentials = runtimeCredentials ? envCredentials.merge(runtimeCredentials) : envCredentials; + + for (const payment of projectSpec.payments) { + for (const connector of payment.connectors) { + try { + const credentialName = connector.credentialName; + const credential = projectSpec.credentials.find( + c => c.name === credentialName && c.authorizerType === 'PaymentCredentialProvider' + ); + if (!credential) { + result.hasErrors = true; + result.errors.push( + `Payment manager "${payment.name}" connector "${connector.name}" references credential "${credentialName}" which is not a PaymentCredentialProvider` + ); + continue; + } + + const credentialProviderArn = await createOrUpdatePaymentCredentialProvider({ + connector, + credential, + region, + credentials: allCredentials, + }); + + result.credentialProviders[credentialName] = { + credentialProviderArn, + credentialProviderName: credentialName, + }; + } catch (error) { + let errorMessage: string; + if (isNoCredentialsError(error)) { + errorMessage = `AWS credentials not found. ${await getAwsLoginGuidance()}`; + } else if (isQuotaExceededError(error)) { + errorMessage = `Service quota exceeded. Delete unused credential providers, or request a limit increase via the AWS Service Quotas console.`; + } else { + errorMessage = error instanceof Error ? error.message : String(error); + } + result.hasErrors = true; + result.errors.push(`Credential provider for "${connector.name}": ${errorMessage}`); + } + } + } + + return result; +} + +export async function cleanupPaymentCredentialProviders(options: { + region: string; + payments: Record }>; +}): Promise { + const { region, payments } = options; + + for (const [name, state] of Object.entries(payments)) { + for (const [connName, conn] of Object.entries(state.connectors ?? {})) { + const credName = conn.credentialProviderArn.split('/').pop() ?? ''; + if (credName) { + try { + await deletePaymentCredentialProvider({ region, name: credName }); + } catch (credErr) { + const msg = credErr instanceof Error ? credErr.message : String(credErr); + if (!msg.includes('404') && !msg.includes('NotFound')) { + console.warn( + `Failed to delete credential provider for connector '${connName}' (payment '${name}'): ${msg}` + ); + } + } + } + } + } +} + +// ── Payment Credential Provider Helper ──────────────────────────────────── + +interface CreateOrUpdatePaymentCredentialProviderOptions { + connector: AgentCoreProjectSpec['payments'][number]['connectors'][number]; + credential: AgentCoreProjectSpec['credentials'][number]; + region: string; + credentials: SecureCredentials; +} + +async function createOrUpdatePaymentCredentialProvider( + options: CreateOrUpdatePaymentCredentialProviderOptions +): Promise { + const { connector, credential, region, credentials } = options; + const vendor = connector.provider ?? 'CoinbaseCDP'; + + let credProviderOptions: Parameters[0]; + + if (vendor === 'StripePrivy') { + const envVarNames = computeStripePrivyCredentialEnvVarNames(credential.name); + const appId = credentials.get(envVarNames.appId); + const appSecret = credentials.get(envVarNames.appSecret); + const authorizationPrivateKey = credentials.get(envVarNames.authorizationPrivateKey); + const authorizationId = credentials.get(envVarNames.authorizationId); + + if (!appId || !appSecret || !authorizationPrivateKey || !authorizationId) { + const missing = [ + !appId && envVarNames.appId, + !appSecret && envVarNames.appSecret, + !authorizationPrivateKey && envVarNames.authorizationPrivateKey, + !authorizationId && envVarNames.authorizationId, + ].filter(Boolean); + throw new Error( + `Missing StripePrivy credentials for connector "${connector.name}" in agentcore/.env.local: ${missing.join(', ')}` + ); + } + + credProviderOptions = { + region, + name: credential.name, + vendor: 'StripePrivy', + appId, + appSecret, + authorizationPrivateKey, + authorizationId, + }; + } else { + const envVarNames = computePaymentCredentialEnvVarNames(credential.name); + const apiKeyId = credentials.get(envVarNames.apiKeyId); + const apiKeySecret = credentials.get(envVarNames.apiKeySecret); + const walletSecret = credentials.get(envVarNames.walletSecret); + + if (!apiKeyId || !apiKeySecret || !walletSecret) { + const missing = [ + !apiKeyId && envVarNames.apiKeyId, + !apiKeySecret && envVarNames.apiKeySecret, + !walletSecret && envVarNames.walletSecret, + ].filter(Boolean); + throw new Error( + `Missing CDP credentials for connector "${connector.name}" in agentcore/.env.local: ${missing.join(', ')}` + ); + } + + credProviderOptions = { + region, + name: credential.name, + vendor: 'CoinbaseCDP', + apiKeyId, + apiKeySecret, + walletSecret, + }; + } + + const existingProvider = await getPaymentCredentialProvider({ region, name: credential.name }); + if (existingProvider) { + const updateResult = await updatePaymentCredentialProvider(credProviderOptions); + return updateResult.credentialProviderArn; + } + const createResult = await createPaymentCredentialProvider(credProviderOptions); + return createResult.credentialProviderArn; +} diff --git a/src/cli/operations/deploy/preflight.ts b/src/cli/operations/deploy/preflight.ts index ba423a088..bf6f79af7 100644 --- a/src/cli/operations/deploy/preflight.ts +++ b/src/cli/operations/deploy/preflight.ts @@ -89,8 +89,9 @@ export async function validateProject(): Promise { // Check for gateways in agentcore.json const hasGateways = projectSpec.agentCoreGateways && projectSpec.agentCoreGateways.length > 0; + const hasPayments = projectSpec.payments && projectSpec.payments.length > 0; - if (!hasAgents && !hasGateways && !hasMemories && !hasEvaluators && !hasPolicyEngines) { + if (!hasAgents && !hasGateways && !hasMemories && !hasEvaluators && !hasPolicyEngines && !hasPayments) { let hasExistingStack = false; try { const deployedState = await configIO.readDeployedState(); @@ -208,6 +209,8 @@ export interface SynthOptions { ioHost?: IIoHost; /** Previous toolkit wrapper to dispose before synthesis. */ previousWrapper?: CdkToolkitWrapper | null; + /** Target region for CDK operations. Without this, toolkit may default to us-east-1. */ + region?: string; } /** @@ -228,6 +231,7 @@ export async function synthesizeCdk(cdkProject: LocalCdkProject, options?: Synth const toolkitWrapper = await createCdkToolkitWrapper({ projectDir: cdkProject.projectDir, ioHost: options?.ioHost ?? silentIoHost, + region: options?.region, }); // synth() produces the assembly internally and stores the directory for later use diff --git a/src/cli/operations/deploy/teardown.ts b/src/cli/operations/deploy/teardown.ts index b7c39c49b..73b4777a6 100644 --- a/src/cli/operations/deploy/teardown.ts +++ b/src/cli/operations/deploy/teardown.ts @@ -63,6 +63,7 @@ export async function destroyTarget(options: DestroyTargetOptions): Promise { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project); @@ -55,6 +56,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project); @@ -85,6 +87,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -121,6 +124,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(() => getDevConfig(workingDir, project, undefined, 'NonExistentAgent')).toThrow( @@ -152,6 +156,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, undefined, 'TsAgent'); @@ -184,6 +189,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -216,6 +222,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; // No configRoot provided @@ -248,6 +255,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -280,6 +288,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -311,6 +320,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -342,6 +352,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -373,6 +384,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -404,6 +416,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -436,6 +449,7 @@ describe('getDevConfig', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const config = getDevConfig(workingDir, project, '/test/project/agentcore'); @@ -481,6 +495,7 @@ describe('getAgentPort', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(getAgentPort(project, 'Agent1', 8080)).toBe(8080); @@ -502,6 +517,7 @@ describe('getAgentPort', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(getAgentPort(project, 'NonExistent', 9000)).toBe(9000); @@ -528,6 +544,7 @@ describe('getDevSupportedAgents', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; expect(getDevSupportedAgents(project)).toEqual([]); @@ -557,6 +574,7 @@ describe('getDevSupportedAgents', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const supported = getDevSupportedAgents(project); @@ -596,6 +614,7 @@ describe('getDevSupportedAgents', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const supported = getDevSupportedAgents(project); @@ -626,6 +645,7 @@ describe('getDevSupportedAgents', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const supported = getDevSupportedAgents(project); @@ -665,6 +685,7 @@ describe('getDevSupportedAgents', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const supported = getDevSupportedAgents(project); diff --git a/src/cli/operations/dev/__tests__/payment-env.test.ts b/src/cli/operations/dev/__tests__/payment-env.test.ts new file mode 100644 index 000000000..fdc0d8f14 --- /dev/null +++ b/src/cli/operations/dev/__tests__/payment-env.test.ts @@ -0,0 +1,210 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +const { mockReadDeployedState, mockReadProjectSpec } = vi.hoisted(() => ({ + mockReadDeployedState: vi.fn(), + mockReadProjectSpec: vi.fn(), +})); + +vi.mock('../../../../lib/index.js', () => ({ + ConfigIO: class { + readDeployedState = mockReadDeployedState; + readProjectSpec = mockReadProjectSpec; + }, +})); + +const { getPaymentEnvVars } = await import('../payment-env.js'); + +describe('getPaymentEnvVars', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('returns empty object when readDeployedState throws', async () => { + mockReadDeployedState.mockRejectedValue(new Error('not found')); + const result = await getPaymentEnvVars(); + expect(result).toEqual({}); + }); + + it('generates MANAGER_ARN, PROCESS_PAYMENT_ROLE_ARN, and CONNECTOR_ID for a single manager', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'my-payment': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/my-payment', + processPaymentRoleArn: 'arn:aws:iam::123:role/ProcessPaymentRole', + connectors: { + 'coinbase-connector': { + connectorId: 'conn-abc123', + credentialProviderName: 'my-cdp-cred', + }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ payments: [] }); + + const result = await getPaymentEnvVars(); + + expect(result).toEqual({ + AGENTCORE_PAYMENT_MY_PAYMENT_MANAGER_ARN: 'arn:aws:bedrock:us-east-1:123:payment-manager/my-payment', + AGENTCORE_PAYMENT_MY_PAYMENT_PROCESS_PAYMENT_ROLE_ARN: 'arn:aws:iam::123:role/ProcessPaymentRole', + AGENTCORE_PAYMENT_MY_PAYMENT_COINBASE_CONNECTOR_CONNECTOR_ID: 'conn-abc123', + AGENTCORE_PAYMENT_MY_PAYMENT_COINBASE_CONNECTOR_CREDENTIAL_PROVIDER_NAME: 'my-cdp-cred', + // Convenience alias (first connector) + AGENTCORE_PAYMENT_MY_PAYMENT_CONNECTOR_ID: 'conn-abc123', + AGENTCORE_PAYMENT_MY_PAYMENT_CREDENTIAL_PROVIDER_NAME: 'my-cdp-cred', + }); + }); + + it('injects AUTH_MODE=bearer when authorizerType is CUSTOM_JWT', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'jwt-payment': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/jwt-payment', + connectors: { + 'my-conn': { connectorId: 'conn-jwt' }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ + payments: [{ name: 'jwt-payment', authorizerType: 'CUSTOM_JWT' }], + }); + + const result = await getPaymentEnvVars(); + + expect(result.AGENTCORE_PAYMENT_JWT_PAYMENT_AUTH_MODE).toBe('bearer'); + }); + + it('does NOT inject AUTH_MODE when authorizerType is AWS_IAM', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'iam-payment': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/iam-payment', + connectors: { + 'my-conn': { connectorId: 'conn-iam' }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ + payments: [{ name: 'iam-payment', authorizerType: 'AWS_IAM' }], + }); + + const result = await getPaymentEnvVars(); + + expect(result).not.toHaveProperty('AGENTCORE_PAYMENT_IAM_PAYMENT_AUTH_MODE'); + }); + + it('generates per-connector vars and convenience first-connector alias for multiple connectors', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'multi-pay': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/multi-pay', + connectors: { + 'connector-one': { + connectorId: 'conn-001', + credentialProviderName: 'cred-one', + }, + 'connector-two': { + connectorId: 'conn-002', + credentialProviderName: 'cred-two', + }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ payments: [] }); + + const result = await getPaymentEnvVars(); + + // Per-connector vars for both + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CONNECTOR_ONE_CONNECTOR_ID).toBe('conn-001'); + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CONNECTOR_ONE_CREDENTIAL_PROVIDER_NAME).toBe('cred-one'); + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CONNECTOR_TWO_CONNECTOR_ID).toBe('conn-002'); + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CONNECTOR_TWO_CREDENTIAL_PROVIDER_NAME).toBe('cred-two'); + // Convenience alias points to first connector + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CONNECTOR_ID).toBe('conn-001'); + expect(result.AGENTCORE_PAYMENT_MULTI_PAY_CREDENTIAL_PROVIDER_NAME).toBe('cred-one'); + }); + + it('does not inject PROCESS_PAYMENT_ROLE_ARN when it is missing', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'no-role-pay': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/no-role-pay', + connectors: { + 'my-conn': { connectorId: 'conn-norole' }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ payments: [] }); + + const result = await getPaymentEnvVars(); + + expect(result).not.toHaveProperty('AGENTCORE_PAYMENT_NO_ROLE_PAY_PROCESS_PAYMENT_ROLE_ARN'); + // Ensure no "undefined" string values leaked in + for (const value of Object.values(result)) { + expect(value).not.toBe('undefined'); + } + }); + + it('injects autoPayment, paymentToolAllowlist, and networkPreferences when set', async () => { + mockReadDeployedState.mockResolvedValue({ + targets: { + default: { + resources: { + payments: { + 'config-pay': { + managerArn: 'arn:aws:bedrock:us-east-1:123:payment-manager/config-pay', + autoPayment: true, + paymentToolAllowlist: ['pay_tool_a', 'pay_tool_b'], + networkPreferences: ['eip155:84532', 'eip155:1'], + connectors: { + 'my-conn': { connectorId: 'conn-cfg' }, + }, + }, + }, + }, + }, + }, + }); + mockReadProjectSpec.mockResolvedValue({ payments: [] }); + + const result = await getPaymentEnvVars(); + + expect(result.AGENTCORE_PAYMENT_CONFIG_PAY_AUTO_PAYMENT).toBe('true'); + expect(result.AGENTCORE_PAYMENT_CONFIG_PAY_TOOL_ALLOWLIST).toBe('pay_tool_a,pay_tool_b'); + expect(result.AGENTCORE_PAYMENT_CONFIG_PAY_NETWORK_PREFERENCES).toBe('eip155:84532,eip155:1'); + }); +}); diff --git a/src/cli/operations/dev/load-dev-env.ts b/src/cli/operations/dev/load-dev-env.ts index 3139c4a99..f41849da0 100644 --- a/src/cli/operations/dev/load-dev-env.ts +++ b/src/cli/operations/dev/load-dev-env.ts @@ -1,16 +1,17 @@ import { findConfigRoot, readEnvFile } from '../../../lib'; import { getGatewayEnvVars } from './gateway-env.js'; import { getMemoryEnvVars } from './memory-env.js'; +import { getPaymentEnvVars } from './payment-env.js'; export interface DevEnv { - /** Merged env vars: deployed-state (gateway + memory) first, then .env overrides */ + /** Merged env vars: deployed-state (gateway + memory + payment) first, then .env overrides */ envVars: Record; /** Number of deployed memories (based on env vars resolved from deployed state) */ deployedMemoryCount: number; } /** - * Load all dev-mode environment variables: deployed-state gateway/memory env vars + * Load all dev-mode environment variables: deployed-state gateway/memory/payment env vars * merged with the user's .env file. Deployed-state vars go first so .env can override. */ export async function loadDevEnv(workingDir: string): Promise { @@ -18,9 +19,10 @@ export async function loadDevEnv(workingDir: string): Promise { const dotEnvVars = configRoot ? await readEnvFile(configRoot) : {}; const gatewayEnvVars = await getGatewayEnvVars(); const memoryEnvVars = await getMemoryEnvVars(); + const paymentEnvVars = await getPaymentEnvVars(); return { - envVars: { ...gatewayEnvVars, ...memoryEnvVars, ...dotEnvVars }, + envVars: { ...gatewayEnvVars, ...memoryEnvVars, ...paymentEnvVars, ...dotEnvVars }, deployedMemoryCount: Object.keys(memoryEnvVars).length, }; } diff --git a/src/cli/operations/dev/payment-env.ts b/src/cli/operations/dev/payment-env.ts new file mode 100644 index 000000000..8b9d5f445 --- /dev/null +++ b/src/cli/operations/dev/payment-env.ts @@ -0,0 +1,69 @@ +import { ConfigIO } from '../../../lib/index.js'; + +export async function getPaymentEnvVars(): Promise> { + const configIO = new ConfigIO(); + const envVars: Record = {}; + + try { + const deployedState = await configIO.readDeployedState(); + const projectSpec = await configIO.readProjectSpec().catch(() => null); + + // Iterate all targets (not just 'default') + for (const target of Object.values(deployedState?.targets ?? {})) { + const payments = target?.resources?.payments ?? {}; + + for (const [name, payment] of Object.entries(payments)) { + if (!payment.managerArn) continue; + const sanitized = name.toUpperCase().replace(/-/g, '_'); + envVars[`AGENTCORE_PAYMENT_${sanitized}_MANAGER_ARN`] = payment.managerArn; + if (payment.processPaymentRoleArn) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_PROCESS_PAYMENT_ROLE_ARN`] = payment.processPaymentRoleArn; + } + + const connectorEntries = Object.entries(payment.connectors ?? {}); + + // Per-connector env vars + for (const [connName, conn] of connectorEntries) { + const connSanitized = connName.toUpperCase().replace(/-/g, '_'); + envVars[`AGENTCORE_PAYMENT_${sanitized}_${connSanitized}_CONNECTOR_ID`] = conn.connectorId; + if (conn.credentialProviderName) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_${connSanitized}_CREDENTIAL_PROVIDER_NAME`] = + conn.credentialProviderName; + } + } + + // Convenience: also expose first connector at manager level for single-connector setups + const firstConnector = connectorEntries[0]?.[1]; + if (firstConnector) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_CONNECTOR_ID`] = firstConnector.connectorId; + if (firstConnector.credentialProviderName) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_CREDENTIAL_PROVIDER_NAME`] = firstConnector.credentialProviderName; + } + } + + // Payment config env vars (parity with CDK stack injection) + if (payment.autoPayment !== undefined) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_AUTO_PAYMENT`] = String(payment.autoPayment); + } + if (payment.paymentToolAllowlist && payment.paymentToolAllowlist.length > 0) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_TOOL_ALLOWLIST`] = payment.paymentToolAllowlist.join(','); + } + if (payment.networkPreferences && payment.networkPreferences.length > 0) { + envVars[`AGENTCORE_PAYMENT_${sanitized}_NETWORK_PREFERENCES`] = payment.networkPreferences.join(','); + } + + // Auth mode from project spec (mirrors CDK injection) + const paymentSpec = projectSpec?.payments?.find((p: { name: string }) => p.name === name) as + | { authorizerType?: string } + | undefined; + if (paymentSpec?.authorizerType === 'CUSTOM_JWT') { + envVars[`AGENTCORE_PAYMENT_${sanitized}_AUTH_MODE`] = 'bearer'; + } + } + } + } catch { + // No deployed state or project spec issue — skip payment env vars + } + + return envVars; +} diff --git a/src/cli/primitives/PaymentConnectorPrimitive.ts b/src/cli/primitives/PaymentConnectorPrimitive.ts new file mode 100644 index 000000000..f34f8409e --- /dev/null +++ b/src/cli/primitives/PaymentConnectorPrimitive.ts @@ -0,0 +1,592 @@ +import { findConfigRoot, removeEnvVars, setEnvVar, toError } from '../../lib'; +import type { AgentCoreProjectSpec, PaymentProvider } from '../../schema'; +import { PaymentConnectorNameSchema, PaymentConnectorSchema, PaymentProviderSchema } from '../../schema'; +import type { RemoveResult } from '../commands/remove/types'; +import { getErrorMessage } from '../errors'; +import type { RemovalPreview, SchemaChange } from '../operations/remove/types'; +import { requireTTY } from '../tui/guards/tty'; +import { BasePrimitive } from './BasePrimitive'; +import { SOURCE_CODE_NOTE } from './constants'; +import { computePaymentCredentialEnvVarNames, computeStripePrivyCredentialEnvVarNames } from './credential-utils'; +import type { AddResult, AddScreenComponent, RemovableResource } from './types'; +import type { Command } from '@commander-js/extra-typings'; + +/** + * Options for adding a CoinbaseCDP payment connector. + */ +export interface AddCoinbaseCdpConnectorOptions { + manager: string; + name: string; + provider: 'CoinbaseCDP'; + apiKeyId: string; + apiKeySecret: string; + walletSecret: string; +} + +/** + * Options for adding a StripePrivy payment connector. + */ +export interface AddStripePrivyConnectorOptions { + manager: string; + name: string; + provider: 'StripePrivy'; + appId: string; + appSecret: string; + authorizationPrivateKey: string; + authorizationId: string; +} + +export type AddPaymentConnectorOptions = AddCoinbaseCdpConnectorOptions | AddStripePrivyConnectorOptions; + +/** + * Removable connector resource with parent manager context. + */ +export interface RemovableConnectorResource extends RemovableResource { + managerName: string; +} + +/** + * PaymentConnectorPrimitive handles payment connector add/remove operations. + * Connectors are child resources of a PaymentManager, using composite keys + * (managerName/connectorName) for removal — following the PolicyPrimitive pattern. + */ +export class PaymentConnectorPrimitive extends BasePrimitive { + readonly kind = 'payment-connector' as const; + readonly label = 'Payment Connector'; + readonly primitiveSchema = PaymentConnectorSchema; + + async add( + options: AddPaymentConnectorOptions + ): Promise> { + try { + const project = await this.readProjectSpec(); + + const manager = project.payments.find(m => m.name === options.manager); + if (!manager) { + return { success: false, error: new Error(`Payment manager "${options.manager}" not found.`) }; + } + + // Check for duplicate connector name within the manager + if (manager.connectors.some(c => c.name === options.name)) { + return { + success: false, + error: new Error(`Payment connector "${options.name}" already exists in manager "${options.manager}".`), + }; + } + + // Build a credential name from the connector name (suffix indicates provider) + const credentialSuffix = options.provider === 'StripePrivy' ? 'stripe-privy' : 'cdp'; + const credentialName = `${options.manager}-${options.name}-${credentialSuffix}`; + + // Check for duplicate credential name + this.checkDuplicate(project.credentials, credentialName, 'Credential'); + + // Create a PaymentCredentialProvider credential entry + project.credentials.push({ + authorizerType: 'PaymentCredentialProvider', + name: credentialName, + provider: options.provider, + }); + + // Write secrets to .env.local BEFORE spec (if this fails, spec is untouched) + if (options.provider === 'StripePrivy') { + const envVarNames = computeStripePrivyCredentialEnvVarNames(credentialName); + await setEnvVar(envVarNames.appId, options.appId); + await setEnvVar(envVarNames.appSecret, options.appSecret); + await setEnvVar(envVarNames.authorizationPrivateKey, options.authorizationPrivateKey); + await setEnvVar(envVarNames.authorizationId, options.authorizationId); + } else { + const envVarNames = computePaymentCredentialEnvVarNames(credentialName); + await setEnvVar(envVarNames.apiKeyId, options.apiKeyId); + await setEnvVar(envVarNames.apiKeySecret, options.apiKeySecret); + await setEnvVar(envVarNames.walletSecret, options.walletSecret); + } + + // Push connector into the manager's connectors array + manager.connectors.push({ + name: options.name, + provider: options.provider, + credentialName, + }); + + await this.writeProjectSpec(project); + + return { + success: true, + connectorName: options.name, + managerName: options.manager, + credentialName, + }; + } catch (err) { + return { success: false, error: toError(err) }; + } + } + + /** + * Remove a connector by composite key "managerName/connectorName" or by separate arguments. + * The composite key format is used by getRemovable() and the generic TUI remove flow. + */ + async remove(nameOrCompositeKey: string, managerName?: string): Promise { + try { + const project = await this.readProjectSpec(); + + let resolvedManager: string | undefined = managerName; + let resolvedConnector: string = nameOrCompositeKey; + + if (!resolvedManager && nameOrCompositeKey.includes('/')) { + const slashIndex = nameOrCompositeKey.indexOf('/'); + resolvedManager = nameOrCompositeKey.slice(0, slashIndex); + resolvedConnector = nameOrCompositeKey.slice(slashIndex + 1); + } + + if (!resolvedManager) { + // Find which manager contains this connector + const matchingManagers = project.payments.filter(m => m.connectors.some(c => c.name === resolvedConnector)); + if (matchingManagers.length > 1) { + return { + success: false, + error: new Error( + `Connector "${resolvedConnector}" exists in multiple managers: ${matchingManagers.map(m => m.name).join(', ')}. Use --manager to specify which one.` + ), + }; + } + if (matchingManagers.length === 1) { + resolvedManager = matchingManagers[0]!.name; + } + } + + for (const manager of project.payments) { + if (resolvedManager && manager.name !== resolvedManager) continue; + + const connIndex = manager.connectors.findIndex(c => c.name === resolvedConnector); + if (connIndex !== -1) { + const connector = manager.connectors[connIndex]!; + const credentialName = connector.credentialName; + + // Remove connector + manager.connectors.splice(connIndex, 1); + + // Remove associated credential if no longer referenced + const stillReferenced = project.payments.some(m => + m.connectors.some(c => c.credentialName === credentialName) + ); + if (!stillReferenced) { + const credIndex = project.credentials.findIndex(c => c.name === credentialName); + if (credIndex !== -1) { + project.credentials.splice(credIndex, 1); + } + } + + await this.writeProjectSpec(project); + + // Clean up .env.local secrets (provider-specific) + if (!stillReferenced) { + try { + if (connector.provider === 'StripePrivy') { + const envVarNames = computeStripePrivyCredentialEnvVarNames(credentialName); + await removeEnvVars([ + envVarNames.appId, + envVarNames.appSecret, + envVarNames.authorizationPrivateKey, + envVarNames.authorizationId, + ]); + } else { + const envVarNames = computePaymentCredentialEnvVarNames(credentialName); + await removeEnvVars([envVarNames.apiKeyId, envVarNames.apiKeySecret, envVarNames.walletSecret]); + } + } catch { + // Best-effort cleanup + } + } + + return { success: true }; + } + } + + return { + success: false, + error: new Error( + `Payment connector "${resolvedConnector}" not found${resolvedManager ? ` in manager "${resolvedManager}"` : ''}.` + ), + }; + } catch (err) { + return { success: false, error: toError(err) }; + } + } + + async previewRemove(nameOrCompositeKey: string): Promise { + const project = await this.readProjectSpec(); + + let targetManager: string | undefined; + let targetConnector: string = nameOrCompositeKey; + + if (nameOrCompositeKey.includes('/')) { + const slashIndex = nameOrCompositeKey.indexOf('/'); + targetManager = nameOrCompositeKey.slice(0, slashIndex); + targetConnector = nameOrCompositeKey.slice(slashIndex + 1); + } + + if (!targetManager) { + const matchingManagers = project.payments.filter(m => m.connectors.some(c => c.name === targetConnector)); + if (matchingManagers.length > 1) { + throw new Error( + `Connector "${targetConnector}" exists in multiple managers: ${matchingManagers.map(m => m.name).join(', ')}. Use --manager to specify which one.` + ); + } + if (matchingManagers.length === 1) { + targetManager = matchingManagers[0]!.name; + } + } + + for (const manager of project.payments) { + if (targetManager && manager.name !== targetManager) continue; + + const connector = manager.connectors.find(c => c.name === targetConnector); + if (connector) { + const summary = [`Removing payment connector: ${targetConnector} (from manager ${manager.name})`]; + + const stillReferenced = project.payments.some(m => + m.connectors + .filter(c => !(m.name === manager.name && c.name === targetConnector)) + .some(c => c.credentialName === connector.credentialName) + ); + if (!stillReferenced) { + summary.push(`Associated credential "${connector.credentialName}" will also be removed`); + } else { + summary.push(`Credential "${connector.credentialName}" is shared and will be kept`); + } + + const schemaChanges: SchemaChange[] = []; + const afterSpec: AgentCoreProjectSpec = { + ...project, + payments: project.payments.map(m => { + if (m.name !== manager.name) return m; + return { + ...m, + connectors: m.connectors.filter(c => c.name !== targetConnector), + }; + }), + }; + schemaChanges.push({ + file: 'agentcore/agentcore.json', + before: project, + after: afterSpec, + }); + + return { summary, directoriesToDelete: [], schemaChanges }; + } + } + + throw new Error( + `Payment connector "${targetConnector}" not found${targetManager ? ` in manager "${targetManager}"` : ''}.` + ); + } + + /** + * Get all removable connectors across all managers. + * Returns composite keys "managerName/connectorName" following PolicyPrimitive pattern. + */ + async getRemovable(): Promise { + try { + const project = await this.readProjectSpec(); + const resources: RemovableConnectorResource[] = []; + + for (const manager of project.payments) { + for (const connector of manager.connectors) { + resources.push({ + name: `${manager.name}/${connector.name}`, + managerName: manager.name, + }); + } + } + + return resources; + } catch { + return []; + } + } + + registerCommands(addCmd: Command, removeCmd: Command): void { + addCmd + .command('payment-connector') + .description('Add a payment connector to a payment manager') + .option('--manager ', 'Payment manager name [non-interactive]') + .option('--name ', 'Payment connector name [non-interactive]') + .option('--provider ', 'Payment provider: CoinbaseCDP, StripePrivy [non-interactive]') + .option('--api-key-id ', 'CDP API Key ID (CoinbaseCDP) [non-interactive]') + .option('--api-key-secret ', 'CDP API Key Secret (CoinbaseCDP) [non-interactive]') + .option('--wallet-secret ', 'CDP Wallet Secret (CoinbaseCDP) [non-interactive]') + .option('--app-id ', 'Privy App ID (StripePrivy) [non-interactive]') + .option('--app-secret ', 'Privy App Secret (StripePrivy) [non-interactive]') + .option('--authorization-private-key ', 'ECDSA P-256 private key (StripePrivy) [non-interactive]') + .option('--authorization-id ', 'Authorization key identifier (StripePrivy) [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') + .action( + async (cliOptions: { + manager?: string; + name?: string; + provider?: string; + apiKeyId?: string; + apiKeySecret?: string; + walletSecret?: string; + appId?: string; + appSecret?: string; + authorizationPrivateKey?: string; + authorizationId?: string; + json?: boolean; + }) => { + try { + if (!findConfigRoot()) { + console.error('No agentcore project found. Run `agentcore create` first.'); + process.exit(1); + } + + const hasAnyOption = + cliOptions.manager ?? + cliOptions.name ?? + cliOptions.provider ?? + cliOptions.apiKeyId ?? + cliOptions.apiKeySecret ?? + cliOptions.walletSecret ?? + cliOptions.appId ?? + cliOptions.appSecret ?? + cliOptions.authorizationPrivateKey ?? + cliOptions.authorizationId ?? + cliOptions.json; + + if (hasAnyOption) { + if (!cliOptions.provider) { + const error = '--provider is required. Valid: CoinbaseCDP, StripePrivy'; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + let provider: PaymentProvider; + try { + provider = PaymentProviderSchema.parse(cliOptions.provider); + } catch { + const error = `Invalid provider "${cliOptions.provider}". Valid: CoinbaseCDP, StripePrivy`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + const missing: string[] = []; + if (!cliOptions.manager) missing.push('--manager'); + if (!cliOptions.name) missing.push('--name'); + + if (provider === 'StripePrivy') { + if (!cliOptions.appId?.trim()) missing.push('--app-id'); + if (!cliOptions.appSecret?.trim()) missing.push('--app-secret'); + if (!cliOptions.authorizationPrivateKey?.trim()) missing.push('--authorization-private-key'); + if (!cliOptions.authorizationId?.trim()) missing.push('--authorization-id'); + } else { + if (!cliOptions.apiKeyId?.trim()) missing.push('--api-key-id'); + if (!cliOptions.apiKeySecret?.trim()) missing.push('--api-key-secret'); + if (!cliOptions.walletSecret?.trim()) missing.push('--wallet-secret'); + } + + if (missing.length > 0) { + const error = `Missing required options for ${provider}: ${missing.join(', ')}`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + const nameResult = PaymentConnectorNameSchema.safeParse(cliOptions.name); + if (!nameResult.success) { + const error = `Invalid connector name: ${nameResult.error.issues[0]?.message}`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + // Validate StripePrivy authorizationPrivateKey format (base64-encoded EC P-256 key) + if (provider === 'StripePrivy') { + const trimmedKey = cliOptions.authorizationPrivateKey!.trim(); + const BASE64_REGEX = /^[A-Za-z0-9+/]+=*$/; + if (!BASE64_REGEX.test(trimmedKey)) { + const error = 'authorizationPrivateKey must be base64-encoded'; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + const decoded = Buffer.from(trimmedKey, 'base64'); + if (decoded.length < 100 || decoded.length > 200) { + const error = + 'authorizationPrivateKey must be a base64-encoded EC P-256 private key (unexpected length)'; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + } + + let result: Awaited>; + if (provider === 'StripePrivy') { + result = await this.add({ + manager: cliOptions.manager!, + name: cliOptions.name!, + provider, + appId: cliOptions.appId!.trim(), + appSecret: cliOptions.appSecret!.trim(), + authorizationPrivateKey: cliOptions.authorizationPrivateKey!.trim(), + authorizationId: cliOptions.authorizationId!.trim(), + }); + } else { + result = await this.add({ + manager: cliOptions.manager!, + name: cliOptions.name!, + provider, + apiKeyId: cliOptions.apiKeyId!.trim(), + apiKeySecret: cliOptions.apiKeySecret!.trim(), + walletSecret: cliOptions.walletSecret!.trim(), + }); + } + + if (cliOptions.json) { + console.log( + JSON.stringify( + result.success + ? result + : { + success: false, + error: result.error instanceof Error ? result.error.message : String(result.error), + } + ) + ); + } else if (result.success) { + console.log(`Added payment connector '${result.connectorName}' to manager '${result.managerName}'`); + console.log(`Credential '${result.credentialName}' created and secrets stored in .env.local`); + console.log(`Run \`agentcore deploy\` to create payment infrastructure on AWS.`); + } else { + console.error(result.error.message); + } + process.exit(result.success ? 0 : 1); + } else { + requireTTY(); + const [{ render }, { default: React }, { AddFlow }] = await Promise.all([ + import('ink'), + import('react'), + import('../tui/screens/add/AddFlow'), + ]); + const { clear, unmount } = render( + React.createElement(AddFlow, { + isInteractive: false, + onExit: () => { + clear(); + unmount(); + process.exit(0); + }, + }) + ); + } + } catch (error) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: getErrorMessage(error) })); + } else { + console.error(`Error: ${getErrorMessage(error)}`); + } + process.exit(1); + } + } + ); + + removeCmd + .command('payment-connector') + .description('Remove a payment connector from a payment manager') + .option('--name ', 'Name of connector to remove [non-interactive]') + .option('--manager ', 'Payment manager name [non-interactive]') + .option('-y, --yes', 'Skip confirmation prompt [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') + .action(async (cliOptions: { name?: string; manager?: string; yes?: boolean; json?: boolean }) => { + try { + if (!findConfigRoot()) { + console.error('No agentcore project found. Run `agentcore create` first.'); + process.exit(1); + } + + if (cliOptions.name || cliOptions.yes || cliOptions.json) { + if (!cliOptions.name) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: '--name is required' })); + } else { + console.error('--name is required'); + } + process.exit(1); + } + + // Build composite key when --manager is provided + const removeKey = cliOptions.manager ? `${cliOptions.manager}/${cliOptions.name}` : cliOptions.name; + const result = await this.remove(removeKey); + + if (cliOptions.json) { + console.log( + JSON.stringify({ + success: result.success, + resourceType: this.kind, + resourceName: cliOptions.name, + message: result.success ? `Removed payment connector '${cliOptions.name}'` : undefined, + note: result.success ? SOURCE_CODE_NOTE : undefined, + error: !result.success ? result.error.message : undefined, + }) + ); + } else if (result.success) { + console.log(`Removed payment connector '${cliOptions.name}'`); + } else { + console.error(result.error.message); + } + process.exit(result.success ? 0 : 1); + } else { + requireTTY(); + const [{ render }, { default: React }, { RemoveFlow }] = await Promise.all([ + import('ink'), + import('react'), + import('../tui/screens/remove'), + ]); + const { clear, unmount } = render( + React.createElement(RemoveFlow, { + isInteractive: false, + force: cliOptions.yes, + initialResourceType: this.kind, + initialResourceName: cliOptions.name, + onExit: () => { + clear(); + unmount(); + process.exit(0); + }, + }) + ); + } + } catch (error) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: getErrorMessage(error) })); + } else { + console.error(`Error: ${getErrorMessage(error)}`); + } + process.exit(1); + } + }); + } + + addScreen(): AddScreenComponent { + return null; + } +} diff --git a/src/cli/primitives/PaymentManagerPrimitive.ts b/src/cli/primitives/PaymentManagerPrimitive.ts new file mode 100644 index 000000000..3dd18ca20 --- /dev/null +++ b/src/cli/primitives/PaymentManagerPrimitive.ts @@ -0,0 +1,572 @@ +import { findConfigRoot, removeEnvVars, serializeResult, toError } from '../../lib'; +import type { AgentCoreProjectSpec, PaymentAuthorizerType, PaymentPattern } from '../../schema'; +import { + PaymentAuthorizerTypeSchema, + PaymentManagerNameSchema, + PaymentManagerSchema, + PaymentPatternSchema, +} from '../../schema'; +import type { RemoveResult } from '../commands/remove/types'; +import { getErrorMessage } from '../errors'; +import type { RemovalPreview, SchemaChange } from '../operations/remove/types'; +import { getTemplatePath } from '../templates/templateRoot'; +import { requireTTY } from '../tui/guards/tty'; +import { BasePrimitive } from './BasePrimitive'; +import { SOURCE_CODE_NOTE } from './constants'; +import { computePaymentCredentialEnvVarNames, computeStripePrivyCredentialEnvVarNames } from './credential-utils'; +import type { AddResult, AddScreenComponent, RemovableResource } from './types'; +import type { Command } from '@commander-js/extra-typings'; +import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; + +/** + * Options for adding a payment manager resource. + */ +export interface AddPaymentManagerOptions { + name: string; + authorizerType: PaymentAuthorizerType; + discoveryUrl?: string; + allowedClients?: string[]; + allowedAudience?: string[]; + allowedScopes?: string[]; + pattern: PaymentPattern; + description?: string; + autoPayment?: boolean; + defaultSpendLimit?: string; + paymentToolAllowlist?: string[]; + networkPreferences?: string[]; +} + +/** + * PaymentManagerPrimitive handles payment manager add/remove operations. + * Manages the top-level payment manager entry in agentcore.json. + * Connectors (child resources) are managed by PaymentConnectorPrimitive. + */ +export class PaymentManagerPrimitive extends BasePrimitive { + readonly kind = 'payment-manager' as const; + readonly label = 'Payment Manager'; + readonly primitiveSchema = PaymentManagerSchema; + + async add(options: AddPaymentManagerOptions): Promise> { + try { + const project = await this.readProjectSpec(); + + this.checkDuplicate(project.payments, options.name, 'Payment manager'); + + if (options.authorizerType === 'CUSTOM_JWT' && !options.discoveryUrl) { + return { success: false, error: new Error('--discovery-url is required when --authorizer-type is CUSTOM_JWT') }; + } + + const authorizerConfiguration = + options.authorizerType === 'CUSTOM_JWT' + ? { + customJWTAuthorizer: { + discoveryUrl: options.discoveryUrl!, + ...(options.allowedClients && { allowedClients: options.allowedClients }), + ...(options.allowedAudience && { allowedAudience: options.allowedAudience }), + ...(options.allowedScopes && { allowedScopes: options.allowedScopes }), + }, + } + : undefined; + + project.payments.push({ + name: options.name, + authorizerType: options.authorizerType, + ...(authorizerConfiguration && { authorizerConfiguration }), + pattern: options.pattern, + connectors: [], + ...(options.description && { description: options.description }), + ...(options.autoPayment !== undefined && { autoPayment: options.autoPayment }), + ...(options.defaultSpendLimit && { defaultSpendLimit: options.defaultSpendLimit }), + ...(options.paymentToolAllowlist?.length && { paymentToolAllowlist: options.paymentToolAllowlist }), + ...(options.networkPreferences?.length && { networkPreferences: options.networkPreferences }), + }); + + await this.writeProjectSpec(project); + + // Wire payment capability into all agents + const configRoot = findConfigRoot(); + if (configRoot) { + for (const runtime of project.runtimes) { + this.wirePaymentCapability(configRoot, runtime.codeLocation); + } + } + + return { success: true, managerName: options.name }; + } catch (err) { + return { success: false, error: toError(err) }; + } + } + + async remove(name: string): Promise { + try { + const project = await this.readProjectSpec(); + + const index = project.payments.findIndex(p => p.name === name); + if (index === -1) { + return { success: false, error: new Error(`Payment manager "${name}" not found.`) }; + } + + const manager = project.payments[index]!; + + // Collect connector info before removal for cleanup + const connectorInfo = manager.connectors.map(c => ({ + credentialName: c.credentialName, + provider: c.provider, + })); + + // Remove the manager (which removes all its nested connectors) + project.payments.splice(index, 1); + + // Remove associated credentials that are no longer referenced by any connector + for (const { credentialName } of connectorInfo) { + const stillReferenced = project.payments.some(m => m.connectors.some(c => c.credentialName === credentialName)); + if (!stillReferenced) { + const credIndex = project.credentials.findIndex(c => c.name === credentialName); + if (credIndex !== -1) { + project.credentials.splice(credIndex, 1); + } + } + } + + await this.writeProjectSpec(project); + + // Clean up .env.local secrets for removed credentials (provider-specific) + for (const { credentialName, provider } of connectorInfo) { + const stillReferenced = project.payments.some(m => m.connectors.some(c => c.credentialName === credentialName)); + if (!stillReferenced) { + try { + if (provider === 'StripePrivy') { + const envVarNames = computeStripePrivyCredentialEnvVarNames(credentialName); + await removeEnvVars([ + envVarNames.appId, + envVarNames.appSecret, + envVarNames.authorizationPrivateKey, + envVarNames.authorizationId, + ]); + } else { + const envVarNames = computePaymentCredentialEnvVarNames(credentialName); + await removeEnvVars([envVarNames.apiKeyId, envVarNames.apiKeySecret, envVarNames.walletSecret]); + } + } catch { + // Best-effort cleanup + } + } + } + + return { success: true }; + } catch (err) { + return { success: false, error: toError(err) }; + } + } + + async previewRemove(name: string): Promise { + const project = await this.readProjectSpec(); + + const manager = project.payments.find(p => p.name === name); + if (!manager) { + throw new Error(`Payment manager "${name}" not found.`); + } + + const summary: string[] = [`Removing payment manager: ${name}`]; + if (manager.connectors.length > 0) { + summary.push(`Note: ${manager.connectors.length} connector(s) within this manager will also be removed`); + for (const conn of manager.connectors) { + summary.push(` - Connector: ${conn.name} (credential: ${conn.credentialName})`); + } + } + + const credentialNames = manager.connectors.map(c => c.credentialName); + for (const credName of credentialNames) { + const otherReferences = project.payments.some( + m => m.name !== name && m.connectors.some(c => c.credentialName === credName) + ); + if (!otherReferences) { + summary.push(`Associated credential "${credName}" will also be removed`); + } else { + summary.push(`Credential "${credName}" is shared by other managers and will be kept`); + } + } + + const schemaChanges: SchemaChange[] = []; + const afterSpec: AgentCoreProjectSpec = { + ...project, + payments: project.payments.filter(p => p.name !== name), + }; + schemaChanges.push({ + file: 'agentcore/agentcore.json', + before: project, + after: afterSpec, + }); + + return { summary, directoriesToDelete: [], schemaChanges }; + } + + async getRemovable(): Promise { + try { + const project = await this.readProjectSpec(); + return project.payments.map(p => ({ name: p.name })); + } catch { + return []; + } + } + + async getExistingManagers(): Promise { + try { + const project = await this.readProjectSpec(); + return project.payments.map(p => p.name); + } catch { + return []; + } + } + + registerCommands(addCmd: Command, removeCmd: Command): void { + addCmd + .command('payment-manager') + .description('Add a payment manager to the project') + .option('--name ', 'Payment manager name [non-interactive]') + .option('--authorizer-type ', 'Authorizer type: AWS_IAM or CUSTOM_JWT (default: AWS_IAM) [non-interactive]') + .option('--discovery-url ', 'OIDC discovery URL (required for CUSTOM_JWT) [non-interactive]') + .option('--allowed-clients ', 'Comma-separated allowed client IDs (for CUSTOM_JWT) [non-interactive]') + .option('--allowed-audience ', 'Comma-separated allowed audiences (for CUSTOM_JWT) [non-interactive]') + .option('--allowed-scopes ', 'Comma-separated allowed scopes (for CUSTOM_JWT) [non-interactive]') + .option('--pattern ', 'Payment pattern: interceptor or tool-based [non-interactive]') + .option('--auto-payment [value]', 'Enable auto payment: true or false (default: true) [non-interactive]') + .option('--default-spend-limit ', 'Default spend limit in USD (default: 10.00) [non-interactive]') + .option('--tool-allowlist ', 'Comma-separated tool names eligible for payment [non-interactive]') + .option( + '--network-preferences ', + 'Comma-separated network identifiers e.g. eip155:84532 [non-interactive]' + ) + .option('--description ', 'Payment manager description [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') + .action( + async (cliOptions: { + name?: string; + authorizerType?: string; + discoveryUrl?: string; + allowedClients?: string; + allowedAudience?: string; + allowedScopes?: string; + pattern?: string; + autoPayment?: string | boolean; + defaultSpendLimit?: string; + toolAllowlist?: string; + networkPreferences?: string; + description?: string; + json?: boolean; + }) => { + try { + if (!findConfigRoot()) { + console.error('No agentcore project found. Run `agentcore create` first.'); + process.exit(1); + } + + if (cliOptions.name !== undefined || cliOptions.authorizerType || cliOptions.pattern || cliOptions.json) { + if (!cliOptions.name) { + const error = '--name is required'; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + const nameResult = PaymentManagerNameSchema.safeParse(cliOptions.name); + if (!nameResult.success) { + const error = `Invalid name: ${nameResult.error.issues[0]?.message}`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + let authorizerType: PaymentAuthorizerType; + try { + authorizerType = PaymentAuthorizerTypeSchema.parse(cliOptions.authorizerType ?? 'AWS_IAM'); + } catch { + const error = `Invalid authorizer type "${cliOptions.authorizerType}". Valid: AWS_IAM, CUSTOM_JWT`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + let pattern: PaymentPattern; + try { + pattern = PaymentPatternSchema.parse(cliOptions.pattern ?? 'interceptor'); + } catch { + const error = `Invalid pattern "${cliOptions.pattern}". Valid: interceptor, tool-based`; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + + if (cliOptions.defaultSpendLimit !== undefined) { + const num = Number(cliOptions.defaultSpendLimit); + if (Number.isNaN(num) || num < 0) { + const error = 'Invalid --default-spend-limit: must be a valid non-negative number (e.g., "10.00")'; + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error })); + } else { + console.error(error); + } + process.exit(1); + } + } + + const parseList = (val?: string): string[] | undefined => + val + ? val + .split(',') + .map(s => s.trim()) + .filter(Boolean) + : undefined; + + const result = await this.add({ + name: cliOptions.name, + authorizerType, + discoveryUrl: cliOptions.discoveryUrl, + allowedClients: parseList(cliOptions.allowedClients), + allowedAudience: parseList(cliOptions.allowedAudience), + allowedScopes: parseList(cliOptions.allowedScopes), + pattern, + autoPayment: + cliOptions.autoPayment !== undefined + ? (() => { + const val = String(cliOptions.autoPayment).toLowerCase(); + if (['true', 'false', 'yes', 'no', '1', '0', 'on', 'off'].includes(val)) { + return !['false', 'no', '0', 'off'].includes(val); + } + throw new Error(`Invalid --auto-payment value "${cliOptions.autoPayment}". Use true or false.`); + })() + : undefined, + defaultSpendLimit: cliOptions.defaultSpendLimit, + paymentToolAllowlist: parseList(cliOptions.toolAllowlist), + networkPreferences: parseList(cliOptions.networkPreferences), + description: cliOptions.description, + }); + + if (cliOptions.json) { + console.log(JSON.stringify(serializeResult(result))); + } else if (result.success) { + console.log(`Added payment manager '${result.managerName}'`); + console.log(`\nPayment capability code has been added to your agent(s).`); + console.log( + `Add a payment connector with \`agentcore add payment-connector --manager ${result.managerName}\`` + ); + } else { + console.error(result.error.message); + } + process.exit(result.success ? 0 : 1); + } else { + requireTTY(); + const [{ render }, { default: React }, { AddFlow }] = await Promise.all([ + import('ink'), + import('react'), + import('../tui/screens/add/AddFlow'), + ]); + const { clear, unmount } = render( + React.createElement(AddFlow, { + isInteractive: false, + onExit: () => { + clear(); + unmount(); + process.exit(0); + }, + }) + ); + } + } catch (error) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: getErrorMessage(error) })); + } else { + console.error(`Error: ${getErrorMessage(error)}`); + } + process.exit(1); + } + } + ); + + removeCmd + .command('payment-manager') + .description('Remove a payment manager from the project') + .option('--name ', 'Name of resource to remove [non-interactive]') + .option('-y, --yes', 'Skip confirmation prompt [non-interactive]') + .option('--json', 'Output as JSON [non-interactive]') + .action(async (cliOptions: { name?: string; yes?: boolean; json?: boolean }) => { + try { + if (!findConfigRoot()) { + console.error('No agentcore project found. Run `agentcore create` first.'); + process.exit(1); + } + + if (cliOptions.name || cliOptions.yes || cliOptions.json) { + if (!cliOptions.name) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: '--name is required' })); + } else { + console.error('--name is required'); + } + process.exit(1); + } + + const result = await this.remove(cliOptions.name); + if (cliOptions.json) { + console.log( + JSON.stringify({ + success: result.success, + resourceType: this.kind, + resourceName: cliOptions.name, + message: result.success ? `Removed payment manager '${cliOptions.name}'` : undefined, + note: result.success ? SOURCE_CODE_NOTE : undefined, + error: !result.success ? result.error.message : undefined, + }) + ); + } else if (result.success) { + console.log(`Removed payment manager '${cliOptions.name}'`); + } else { + console.error(result.error.message); + } + process.exit(result.success ? 0 : 1); + } else { + requireTTY(); + const [{ render }, { default: React }, { RemoveFlow }] = await Promise.all([ + import('ink'), + import('react'), + import('../tui/screens/remove'), + ]); + const { clear, unmount } = render( + React.createElement(RemoveFlow, { + isInteractive: false, + force: cliOptions.yes, + initialResourceType: this.kind, + initialResourceName: cliOptions.name, + onExit: () => { + clear(); + unmount(); + process.exit(0); + }, + }) + ); + } + } catch (error) { + if (cliOptions.json) { + console.log(JSON.stringify({ success: false, error: getErrorMessage(error) })); + } else { + console.error(`Error: ${getErrorMessage(error)}`); + } + process.exit(1); + } + }); + } + + addScreen(): AddScreenComponent { + return null; + } + + /** + * Wire payment capability template into an agent's code directory. + * Copies payments.py and patches main.py to add the import line. + * + * Note: The per-invocation plugin setup (extracting user_id, instrument_id, + * session_id from payload and creating the plugin inside the entrypoint) is + * handled by the Handlebars template for new agents. For existing agents, + * the user must manually update their entrypoint to use the factory pattern. + */ + private wirePaymentCapability(configRoot: string, codeLocation: string): void { + const projectRoot = dirname(configRoot); + const agentDir = resolve(projectRoot, codeLocation); + const capDir = join(agentDir, 'capabilities', 'payments'); + + if (existsSync(join(capDir, 'payments.py'))) return; + + const templateDir = getTemplatePath('python', 'http', 'strands', 'capabilities', 'payments'); + if (!existsSync(templateDir)) return; + + mkdirSync(capDir, { recursive: true }); + copyFileSync(join(templateDir, 'payments.py'), join(capDir, 'payments.py')); + const initPath = join(capDir, '__init__.py'); + if (!existsSync(initPath)) writeFileSync(initPath, ''); + const parentInit = join(agentDir, 'capabilities', '__init__.py'); + if (!existsSync(parentInit)) writeFileSync(parentInit, ''); + + const mainPath = join(agentDir, 'main.py'); + if (!existsSync(mainPath)) return; + + const main = readFileSync(mainPath, 'utf-8'); + if (main.includes('create_payments_plugin')) return; + + const importLine = 'from capabilities.payments.payments import create_payments_plugin, PAYMENT_SYSTEM_PROMPT'; + + let patched = main; + + // 1. Add import after last import line + const lastImportMatch = [...main.matchAll(/^(?:from|import) .+$/gm)].pop(); + if (lastImportMatch?.index !== undefined) { + const insertPos = lastImportMatch.index + lastImportMatch[0].length; + patched = patched.slice(0, insertPos) + '\n' + importLine + patched.slice(insertPos); + } else { + patched = importLine + '\n' + patched; + } + + // 2. Replace "agent = get_or_create_agent()" with per-invocation agent + plugin creation + // The cached agent pattern can't work with per-invocation plugins because + // plugins are scoped to a request (different user_id/instrument_id/session_id). + const agentCallPattern = /^([^\S\n]*)agent = get_or_create_agent\(\)\s*$/m; + const agentCallMatch = agentCallPattern.exec(patched); + if (agentCallMatch) { + const indent = agentCallMatch[1]; + const replacement = [ + `${indent}# Payment plugin (per-invocation — different user/instrument/session per request)`, + `${indent}user_id = payload.get("user_id") or getattr(context, "user_id", "default-user")`, + `${indent}instrument_id = payload.get("payment_instrument_id")`, + `${indent}session_id = payload.get("payment_session_id")`, + `${indent}payments_plugin = create_payments_plugin(user_id, instrument_id, session_id)`, + `${indent}plugins = [payments_plugin] if payments_plugin else []`, + ``, + `${indent}agent = Agent(`, + `${indent} model=load_model(),`, + `${indent} system_prompt=DEFAULT_SYSTEM_PROMPT + PAYMENT_SYSTEM_PROMPT,`, + `${indent} tools=tools,`, + `${indent} plugins=plugins,`, + `${indent})`, + ].join('\n'); + patched = + patched.slice(0, agentCallMatch.index) + + replacement + + patched.slice(agentCallMatch.index + agentCallMatch[0].length); + + // Remove the now-dead cached agent singleton (replaced by per-invocation Agent above) + patched = patched.replace(/^_agent = None\n\ndef get_or_create_agent\(\):[\s\S]*?(?=\n\n@|\n\n\n|$)/m, ''); + } else { + const byoAgentPattern = /^(\s*)(agent = Agent\()/m; + const byoMatch = byoAgentPattern.exec(patched); + if (byoMatch) { + const indent = byoMatch[1]; + const pluginSetup = [ + `${indent}# Payment plugin (per-invocation — different user/instrument/session per request)`, + `${indent}user_id = payload.get("user_id") or getattr(context, "user_id", "default-user")`, + `${indent}instrument_id = payload.get("payment_instrument_id")`, + `${indent}session_id = payload.get("payment_session_id")`, + `${indent}payments_plugin = create_payments_plugin(user_id, instrument_id, session_id)`, + `${indent}plugins = [payments_plugin] if payments_plugin else []`, + ``, + `${indent}# TODO: Add plugins=plugins to your Agent() constructor below`, + `${indent}${byoMatch[2]}`, + ].join('\n'); + patched = patched.slice(0, byoMatch.index) + pluginSetup + patched.slice(byoMatch.index + byoMatch[0].length); + } + } + + writeFileSync(mainPath, patched); + } +} diff --git a/src/cli/primitives/__tests__/GatewayPrimitive.test.ts b/src/cli/primitives/__tests__/GatewayPrimitive.test.ts index fb53e095d..c9c1f351c 100644 --- a/src/cli/primitives/__tests__/GatewayPrimitive.test.ts +++ b/src/cli/primitives/__tests__/GatewayPrimitive.test.ts @@ -16,6 +16,7 @@ const defaultProject: AgentCoreProjectSpec = { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const { mockConfigExists, mockReadProjectSpec, mockWriteProjectSpec } = vi.hoisted(() => ({ diff --git a/src/cli/primitives/__tests__/PaymentConnectorPrimitive.test.ts b/src/cli/primitives/__tests__/PaymentConnectorPrimitive.test.ts new file mode 100644 index 000000000..d024e66fc --- /dev/null +++ b/src/cli/primitives/__tests__/PaymentConnectorPrimitive.test.ts @@ -0,0 +1,479 @@ +import type { AgentCoreProjectSpec } from '../../../schema'; +import { PaymentConnectorPrimitive } from '../PaymentConnectorPrimitive'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +// ── Hoisted mocks ──────────────────────────────────────────────────────────── + +const { mockSetEnvVar, mockRemoveEnvVars, mockReadProjectSpec, mockWriteProjectSpec } = vi.hoisted(() => ({ + mockSetEnvVar: vi.fn().mockResolvedValue(undefined), + mockRemoveEnvVars: vi.fn().mockResolvedValue(undefined), + mockReadProjectSpec: vi.fn(), + mockWriteProjectSpec: vi.fn().mockResolvedValue(undefined), +})); + +vi.mock('../../../lib', () => { + const MockConfigIO = vi.fn(function (this: Record) { + this.readProjectSpec = mockReadProjectSpec; + this.writeProjectSpec = mockWriteProjectSpec; + }); + return { + ConfigIO: MockConfigIO, + findConfigRoot: vi.fn().mockReturnValue('/fake/root'), + setEnvVar: mockSetEnvVar, + removeEnvVars: mockRemoveEnvVars, + toError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))), + serializeResult: (r: unknown) => r, + ResourceNotFoundError: class extends Error { + constructor(m: string) { + super(m); + this.name = 'ResourceNotFoundError'; + } + }, + }; +}); + +// ── Fixtures ───────────────────────────────────────────────────────────────── + +function makeProject(overrides: Partial = {}): AgentCoreProjectSpec { + return { + name: 'test-project', + version: 1, + managedBy: 'CDK' as const, + runtimes: [], + memories: [], + credentials: [], + evaluators: [], + onlineEvalConfigs: [], + agentCoreGateways: [], + policyEngines: [], + configBundles: [], + abTests: [], + httpGateways: [], + payments: [], + ...overrides, + }; +} + +function makeManager( + name: string, + connectors: { name: string; provider: 'CoinbaseCDP' | 'StripePrivy'; credentialName: string }[] = [] +) { + return { + name, + authorizerType: 'AWS_IAM' as const, + pattern: 'interceptor' as const, + connectors, + }; +} + +// ── Tests ───────────────────────────────────────────────────────────────────── + +describe('PaymentConnectorPrimitive', () => { + let primitive: PaymentConnectorPrimitive; + + beforeEach(() => { + vi.clearAllMocks(); + primitive = new PaymentConnectorPrimitive(); + }); + + // ── add() ────────────────────────────────────────────────────────────────── + + describe('add()', () => { + describe('CoinbaseCDP happy path', () => { + it('returns success with correct names', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + const result = await primitive.add({ + manager: 'mgr1', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'key-id', + apiKeySecret: 'key-secret', + walletSecret: 'wallet-secret', + }); + + expect(result.success).toBe(true); + if (!result.success) throw new Error('expected success'); + expect(result.connectorName).toBe('conn1'); + expect(result.managerName).toBe('mgr1'); + expect(result.credentialName).toBe('mgr1-conn1-cdp'); + }); + + it('writes all 3 CoinbaseCDP env vars', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + await primitive.add({ + manager: 'mgr1', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'key-id', + apiKeySecret: 'key-secret', + walletSecret: 'wallet-secret', + }); + + expect(mockSetEnvVar).toHaveBeenCalledTimes(3); + expect(mockSetEnvVar).toHaveBeenCalledWith('AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_API_KEY_ID', 'key-id'); + expect(mockSetEnvVar).toHaveBeenCalledWith('AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_API_KEY_SECRET', 'key-secret'); + expect(mockSetEnvVar).toHaveBeenCalledWith( + 'AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_WALLET_SECRET', + 'wallet-secret' + ); + }); + + it('writes env vars BEFORE writeProjectSpec', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + const callOrder: string[] = []; + mockSetEnvVar.mockImplementation(() => { + callOrder.push('setEnvVar'); + return Promise.resolve(); + }); + mockWriteProjectSpec.mockImplementation(() => { + callOrder.push('writeProjectSpec'); + return Promise.resolve(); + }); + + await primitive.add({ + manager: 'mgr1', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'key-id', + apiKeySecret: 'key-secret', + walletSecret: 'wallet-secret', + }); + + const firstWrite = callOrder.indexOf('writeProjectSpec'); + const lastEnvVar = callOrder.lastIndexOf('setEnvVar'); + expect(lastEnvVar).toBeLessThan(firstWrite); + }); + + it('writes connector into manager and credential into spec', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + await primitive.add({ + manager: 'mgr1', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'key-id', + apiKeySecret: 'key-secret', + walletSecret: 'wallet-secret', + }); + + expect(mockWriteProjectSpec).toHaveBeenCalledTimes(1); + const writtenSpec = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + const manager = writtenSpec.payments.find(m => m.name === 'mgr1'); + expect(manager?.connectors).toHaveLength(1); + expect(manager?.connectors[0]!.name).toBe('conn1'); + expect(manager?.connectors[0]!.provider).toBe('CoinbaseCDP'); + expect(manager?.connectors[0]!.credentialName).toBe('mgr1-conn1-cdp'); + expect(writtenSpec.credentials).toHaveLength(1); + expect(writtenSpec.credentials[0]!.name).toBe('mgr1-conn1-cdp'); + }); + }); + + describe('StripePrivy happy path', () => { + it('writes 4 env vars for StripePrivy', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + const result = await primitive.add({ + manager: 'mgr1', + name: 'sp-conn', + provider: 'StripePrivy', + appId: 'app-123', + appSecret: 'app-secret-456', + authorizationPrivateKey: 'priv-key-789', + authorizationId: 'auth-id-abc', + }); + + expect(result.success).toBe(true); + expect(mockSetEnvVar).toHaveBeenCalledTimes(4); + expect(mockSetEnvVar).toHaveBeenCalledWith('AGENTCORE_CREDENTIAL_MGR1_SP_CONN_STRIPE_PRIVY_APP_ID', 'app-123'); + expect(mockSetEnvVar).toHaveBeenCalledWith( + 'AGENTCORE_CREDENTIAL_MGR1_SP_CONN_STRIPE_PRIVY_APP_SECRET', + 'app-secret-456' + ); + expect(mockSetEnvVar).toHaveBeenCalledWith( + 'AGENTCORE_CREDENTIAL_MGR1_SP_CONN_STRIPE_PRIVY_AUTHORIZATION_PRIVATE_KEY', + 'priv-key-789' + ); + expect(mockSetEnvVar).toHaveBeenCalledWith( + 'AGENTCORE_CREDENTIAL_MGR1_SP_CONN_STRIPE_PRIVY_AUTHORIZATION_ID', + 'auth-id-abc' + ); + }); + + it('uses "stripe-privy" suffix for credentialName', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + const result = await primitive.add({ + manager: 'mgr1', + name: 'sp-conn', + provider: 'StripePrivy', + appId: 'app-123', + appSecret: 'app-secret-456', + authorizationPrivateKey: 'priv-key-789', + authorizationId: 'auth-id-abc', + }); + + if (!result.success) throw new Error('expected success'); + expect(result.credentialName).toBe('mgr1-sp-conn-stripe-privy'); + }); + }); + + describe('error cases', () => { + it('returns error when manager does not exist', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [] })); + + const result = await primitive.add({ + manager: 'non-existent', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'k', + apiKeySecret: 's', + walletSecret: 'w', + }); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('"non-existent"'); + expect(result.error.message).toContain('not found'); + } + expect(mockSetEnvVar).not.toHaveBeenCalled(); + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + + it('returns error for duplicate connector name within same manager', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + }) + ); + + const result = await primitive.add({ + manager: 'mgr1', + name: 'conn1', + provider: 'CoinbaseCDP', + apiKeyId: 'k', + apiKeySecret: 's', + walletSecret: 'w', + }); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('"conn1"'); + expect(result.error.message).toContain('already exists'); + expect(result.error.message).toContain('"mgr1"'); + } + expect(mockSetEnvVar).not.toHaveBeenCalled(); + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + }); + }); + + // ── remove() ────────────────────────────────────────────────────────────── + + describe('remove()', () => { + it('auto-resolves manager when connector exists in exactly one manager', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const result = await primitive.remove('conn1'); + + expect(result.success).toBe(true); + expect(mockWriteProjectSpec).toHaveBeenCalledTimes(1); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments[0]!.connectors).toHaveLength(0); + }); + + it('returns error when connector exists in multiple managers (ambiguous)', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + makeManager('mgr2', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr2-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + { authorizerType: 'PaymentCredentialProvider', name: 'mgr2-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const result = await primitive.remove('conn1'); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('exists in multiple managers'); + expect(result.error.message).toContain('mgr1'); + expect(result.error.message).toContain('mgr2'); + expect(result.error.message).toContain('--manager'); + } + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + + it('removes orphaned credential from spec and cleans up env vars', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const result = await primitive.remove('conn1'); + + expect(result.success).toBe(true); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + // Credential removed from spec + expect(written.credentials).toHaveLength(0); + // Env vars cleaned up + expect(mockRemoveEnvVars).toHaveBeenCalledTimes(1); + expect(mockRemoveEnvVars).toHaveBeenCalledWith( + expect.arrayContaining([ + 'AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_API_KEY_ID', + 'AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_API_KEY_SECRET', + 'AGENTCORE_CREDENTIAL_MGR1_CONN1_CDP_WALLET_SECRET', + ]) + ); + }); + + it('keeps shared credential in spec when still referenced by another connector', async () => { + // Both connectors in different managers share the same credentialName + const sharedCred = 'shared-cred'; + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: sharedCred }]), + makeManager('mgr2', [{ name: 'conn2', provider: 'CoinbaseCDP', credentialName: sharedCred }]), + ], + credentials: [{ authorizerType: 'PaymentCredentialProvider', name: sharedCred, provider: 'CoinbaseCDP' }], + }) + ); + + // Remove conn1 from mgr1 using composite key + const result = await primitive.remove('mgr1/conn1'); + + expect(result.success).toBe(true); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + // Credential kept because mgr2/conn2 still references it + expect(written.credentials).toHaveLength(1); + expect(written.credentials[0]!.name).toBe(sharedCred); + // No env var cleanup + expect(mockRemoveEnvVars).not.toHaveBeenCalled(); + }); + }); + + // ── previewRemove() ──────────────────────────────────────────────────────── + + describe('previewRemove()', () => { + it('correctly excludes the target connector when computing stillReferenced', async () => { + // Only one connector references this credential — previewRemove should + // report it as orphaned (not shared), even though the connector is still + // in the spec during the preview pass. + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const preview = await primitive.previewRemove('mgr1/conn1'); + + const credRemovalMsg = preview.summary.find(s => s.includes('will also be removed')); + expect(credRemovalMsg).toBeDefined(); + expect(credRemovalMsg).toContain('mgr1-conn1-cdp'); + }); + + it('reports credential as shared when another connector still references it', async () => { + const sharedCred = 'shared-cred'; + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: sharedCred }]), + makeManager('mgr2', [{ name: 'conn2', provider: 'CoinbaseCDP', credentialName: sharedCred }]), + ], + credentials: [{ authorizerType: 'PaymentCredentialProvider', name: sharedCred, provider: 'CoinbaseCDP' }], + }) + ); + + const preview = await primitive.previewRemove('mgr1/conn1'); + + const sharedMsg = preview.summary.find(s => s.includes('shared') && s.includes('kept')); + expect(sharedMsg).toBeDefined(); + }); + + it('includes the target connector in the summary', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const preview = await primitive.previewRemove('conn1'); + + expect(preview.summary[0]).toContain('conn1'); + expect(preview.summary[0]).toContain('mgr1'); + }); + + it('includes a schema change entry for agentcore.json', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + ], + credentials: [ + { authorizerType: 'PaymentCredentialProvider', name: 'mgr1-conn1-cdp', provider: 'CoinbaseCDP' }, + ], + }) + ); + + const preview = await primitive.previewRemove('conn1'); + + expect(preview.schemaChanges).toHaveLength(1); + expect(preview.schemaChanges[0]!.file).toBe('agentcore/agentcore.json'); + const after = preview.schemaChanges[0]!.after as AgentCoreProjectSpec; + expect(after.payments[0]!.connectors).toHaveLength(0); + }); + + it('throws when connector is not found', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makeManager('mgr1')] })); + + await expect(primitive.previewRemove('does-not-exist')).rejects.toThrow('not found'); + }); + + it('throws when connector exists in multiple managers without a composite key', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [ + makeManager('mgr1', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr1-conn1-cdp' }]), + makeManager('mgr2', [{ name: 'conn1', provider: 'CoinbaseCDP', credentialName: 'mgr2-conn1-cdp' }]), + ], + }) + ); + + await expect(primitive.previewRemove('conn1')).rejects.toThrow('exists in multiple managers'); + }); + }); +}); diff --git a/src/cli/primitives/__tests__/PaymentManagerPrimitive.test.ts b/src/cli/primitives/__tests__/PaymentManagerPrimitive.test.ts new file mode 100644 index 000000000..c351ea50d --- /dev/null +++ b/src/cli/primitives/__tests__/PaymentManagerPrimitive.test.ts @@ -0,0 +1,391 @@ +import type { AgentCoreProjectSpec } from '../../../schema'; +import { PaymentManagerPrimitive } from '../PaymentManagerPrimitive'; +import { afterEach, describe, expect, it, vi } from 'vitest'; + +const mockReadProjectSpec = vi.fn(); +const mockWriteProjectSpec = vi.fn(); + +vi.mock('../../../lib', () => ({ + ConfigIO: class { + readProjectSpec = mockReadProjectSpec; + writeProjectSpec = mockWriteProjectSpec; + }, + findConfigRoot: vi.fn().mockReturnValue(null), + removeEnvVars: vi.fn().mockResolvedValue(undefined), + toError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))), + serializeResult: (r: unknown) => r, +})); + +vi.mock('../templates/templateRoot', () => ({ + getTemplatePath: vi.fn().mockReturnValue('/nonexistent/template/path'), +})); + +function makeProject(overrides: Partial = {}): AgentCoreProjectSpec { + return { + name: 'TestProject', + version: 1, + managedBy: 'CDK' as const, + runtimes: [], + memories: [], + credentials: [], + evaluators: [], + onlineEvalConfigs: [], + agentCoreGateways: [], + policyEngines: [], + configBundles: [], + abTests: [], + httpGateways: [], + payments: [], + ...overrides, + }; +} + +function makePaymentManager( + name: string, + connectors: { name: string; credentialName: string; provider?: 'CoinbaseCDP' | 'StripePrivy' }[] = [] +) { + return { + name, + authorizerType: 'AWS_IAM' as const, + pattern: 'interceptor' as const, + connectors: connectors.map(c => ({ + name: c.name, + credentialName: c.credentialName, + provider: c.provider ?? ('CoinbaseCDP' as const), + })), + }; +} + +function makePaymentCredential(name: string) { + return { + authorizerType: 'PaymentCredentialProvider' as const, + name, + provider: 'CoinbaseCDP' as const, + }; +} + +const primitive = new PaymentManagerPrimitive(); + +describe('PaymentManagerPrimitive', () => { + afterEach(() => vi.clearAllMocks()); + + describe('add()', () => { + it('happy path with AWS_IAM — adds manager to spec and returns success', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.add({ + name: 'myManager', + authorizerType: 'AWS_IAM', + pattern: 'interceptor', + }); + + expect(result.success).toBe(true); + expect(result).toHaveProperty('managerName', 'myManager'); + + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments).toHaveLength(1); + const manager = written.payments[0]!; + expect(manager.name).toBe('myManager'); + expect(manager.authorizerType).toBe('AWS_IAM'); + expect(manager.pattern).toBe('interceptor'); + expect(manager.connectors).toEqual([]); + expect(manager.authorizerConfiguration).toBeUndefined(); + }); + + it('happy path writes optional fields when provided', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + mockWriteProjectSpec.mockResolvedValue(undefined); + + await primitive.add({ + name: 'richManager', + authorizerType: 'AWS_IAM', + pattern: 'tool-based', + description: 'My payment manager', + autoPayment: true, + defaultSpendLimit: '50.00', + paymentToolAllowlist: ['buy_item', 'refund'], + networkPreferences: ['eip155:84532'], + }); + + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + const manager = written.payments[0]!; + expect(manager.description).toBe('My payment manager'); + expect(manager.autoPayment).toBe(true); + expect(manager.defaultSpendLimit).toBe('50.00'); + expect(manager.paymentToolAllowlist).toEqual(['buy_item', 'refund']); + expect(manager.networkPreferences).toEqual(['eip155:84532']); + }); + + it('happy path with CUSTOM_JWT and discovery URL — builds authorizerConfiguration', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.add({ + name: 'jwtManager', + authorizerType: 'CUSTOM_JWT', + discoveryUrl: 'https://example.com/.well-known/openid-configuration', + allowedClients: ['client1', 'client2'], + allowedAudience: ['aud1'], + allowedScopes: ['scope1'], + pattern: 'interceptor', + }); + + expect(result.success).toBe(true); + + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + const manager = written.payments[0]!; + expect(manager.authorizerType).toBe('CUSTOM_JWT'); + expect(manager.authorizerConfiguration?.customJWTAuthorizer?.discoveryUrl).toBe( + 'https://example.com/.well-known/openid-configuration' + ); + expect(manager.authorizerConfiguration?.customJWTAuthorizer?.allowedClients).toEqual(['client1', 'client2']); + expect(manager.authorizerConfiguration?.customJWTAuthorizer?.allowedAudience).toEqual(['aud1']); + expect(manager.authorizerConfiguration?.customJWTAuthorizer?.allowedScopes).toEqual(['scope1']); + }); + + it('duplicate name — returns error without writing', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject({ payments: [makePaymentManager('existingManager')] })); + + const result = await primitive.add({ + name: 'existingManager', + authorizerType: 'AWS_IAM', + pattern: 'interceptor', + }); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('existingManager'); + expect(result.error.message).toContain('already exists'); + } + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + + it('CUSTOM_JWT without discovery URL — returns error without writing', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + + const result = await primitive.add({ + name: 'jwtManager', + authorizerType: 'CUSTOM_JWT', + pattern: 'interceptor', + // no discoveryUrl + }); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('--discovery-url'); + expect(result.error.message).toContain('CUSTOM_JWT'); + } + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + + it('readProjectSpec failure — returns error', async () => { + mockReadProjectSpec.mockRejectedValue(new Error('disk read failure')); + + const result = await primitive.add({ + name: 'anyManager', + authorizerType: 'AWS_IAM', + pattern: 'interceptor', + }); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toBe('disk read failure'); + } + }); + }); + + describe('remove()', () => { + it('cascading delete — removes manager and its connectors from spec', async () => { + const project = makeProject({ + payments: [ + makePaymentManager('managerA', [{ name: 'connA', credentialName: 'cred1' }]), + makePaymentManager('managerB'), + ], + credentials: [makePaymentCredential('cred1')], + }); + mockReadProjectSpec.mockResolvedValue(project); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.remove('managerA'); + + expect(result.success).toBe(true); + + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments).toHaveLength(1); + expect(written.payments[0]!.name).toBe('managerB'); + // credential no longer referenced — should be removed + expect(written.credentials).toHaveLength(0); + }); + + it('cascading delete — removes multiple connectors and their credentials', async () => { + const project = makeProject({ + payments: [ + makePaymentManager('bigManager', [ + { name: 'connA', credentialName: 'credA' }, + { name: 'connB', credentialName: 'credB' }, + ]), + ], + credentials: [makePaymentCredential('credA'), makePaymentCredential('credB')], + }); + mockReadProjectSpec.mockResolvedValue(project); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.remove('bigManager'); + + expect(result.success).toBe(true); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments).toHaveLength(0); + expect(written.credentials).toHaveLength(0); + }); + + it('non-existent name — returns error without writing', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + + const result = await primitive.remove('doesNotExist'); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toContain('doesNotExist'); + expect(result.error.message).toContain('not found'); + } + expect(mockWriteProjectSpec).not.toHaveBeenCalled(); + }); + + it('credential shared across managers — credential kept after removing one manager', async () => { + const project = makeProject({ + payments: [ + makePaymentManager('managerA', [{ name: 'connA', credentialName: 'sharedCred' }]), + makePaymentManager('managerB', [{ name: 'connB', credentialName: 'sharedCred' }]), + ], + credentials: [makePaymentCredential('sharedCred')], + }); + mockReadProjectSpec.mockResolvedValue(project); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.remove('managerA'); + + expect(result.success).toBe(true); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments).toHaveLength(1); + expect(written.payments[0]!.name).toBe('managerB'); + // sharedCred still referenced by managerB — must be kept + expect(written.credentials).toHaveLength(1); + expect(written.credentials[0]!.name).toBe('sharedCred'); + }); + + it('manager with no connectors — removes cleanly without touching credentials', async () => { + const project = makeProject({ + payments: [makePaymentManager('emptyManager'), makePaymentManager('otherManager')], + credentials: [makePaymentCredential('unrelatedCred')], + }); + mockReadProjectSpec.mockResolvedValue(project); + mockWriteProjectSpec.mockResolvedValue(undefined); + + const result = await primitive.remove('emptyManager'); + + expect(result.success).toBe(true); + const written = mockWriteProjectSpec.mock.calls[0]![0] as AgentCoreProjectSpec; + expect(written.payments).toHaveLength(1); + expect(written.payments[0]!.name).toBe('otherManager'); + expect(written.credentials).toHaveLength(1); + }); + + it('readProjectSpec failure — returns error', async () => { + mockReadProjectSpec.mockRejectedValue(new Error('io error')); + + const result = await primitive.remove('anyManager'); + + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.message).toBe('io error'); + } + }); + }); + + describe('getRemovable()', () => { + it('returns manager names from spec', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [makePaymentManager('alpha'), makePaymentManager('beta')], + }) + ); + + const result = await primitive.getRemovable(); + + expect(result).toEqual([{ name: 'alpha' }, { name: 'beta' }]); + }); + + it('returns empty array when no managers exist', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + + expect(await primitive.getRemovable()).toEqual([]); + }); + + it('returns empty array on readProjectSpec error', async () => { + mockReadProjectSpec.mockRejectedValue(new Error('fail')); + + expect(await primitive.getRemovable()).toEqual([]); + }); + }); + + describe('getExistingManagers()', () => { + it('returns manager names as strings', async () => { + mockReadProjectSpec.mockResolvedValue( + makeProject({ + payments: [makePaymentManager('m1'), makePaymentManager('m2')], + }) + ); + + const result = await primitive.getExistingManagers(); + + expect(result).toEqual(['m1', 'm2']); + }); + + it('returns empty array on error', async () => { + mockReadProjectSpec.mockRejectedValue(new Error('fail')); + + expect(await primitive.getExistingManagers()).toEqual([]); + }); + }); + + describe('previewRemove()', () => { + it('returns summary and schema changes for a manager with connectors', async () => { + const project = makeProject({ + payments: [makePaymentManager('previewManager', [{ name: 'connA', credentialName: 'credA' }])], + credentials: [makePaymentCredential('credA')], + }); + mockReadProjectSpec.mockResolvedValue(project); + + const preview = await primitive.previewRemove('previewManager'); + + expect(preview.summary[0]).toContain('previewManager'); + expect(preview.summary.some(s => s.includes('connA'))).toBe(true); + expect(preview.schemaChanges).toHaveLength(1); + expect(preview.schemaChanges[0]!.file).toBe('agentcore/agentcore.json'); + const after = preview.schemaChanges[0]!.after as AgentCoreProjectSpec; + expect(after.payments).toHaveLength(0); + }); + + it('notes shared credential is kept in preview', async () => { + const project = makeProject({ + payments: [ + makePaymentManager('mgr1', [{ name: 'connA', credentialName: 'sharedCred' }]), + makePaymentManager('mgr2', [{ name: 'connB', credentialName: 'sharedCred' }]), + ], + credentials: [makePaymentCredential('sharedCred')], + }); + mockReadProjectSpec.mockResolvedValue(project); + + const preview = await primitive.previewRemove('mgr1'); + + expect(preview.summary.some(s => s.includes('kept'))).toBe(true); + }); + + it('throws when manager not found', async () => { + mockReadProjectSpec.mockResolvedValue(makeProject()); + + await expect(primitive.previewRemove('missing')).rejects.toThrow('not found'); + }); + }); +}); diff --git a/src/cli/primitives/__tests__/auth-utils.test.ts b/src/cli/primitives/__tests__/auth-utils.test.ts index 5f0e1a7c9..088acef4c 100644 --- a/src/cli/primitives/__tests__/auth-utils.test.ts +++ b/src/cli/primitives/__tests__/auth-utils.test.ts @@ -96,6 +96,7 @@ describe('createManagedOAuthCredential', () => { configBundles: [], abTests: [], httpGateways: [], + payments: [], }; const jwtConfig: JwtConfigOptions = { diff --git a/src/cli/primitives/__tests__/credential-utils.test.ts b/src/cli/primitives/__tests__/credential-utils.test.ts new file mode 100644 index 000000000..b04424b9d --- /dev/null +++ b/src/cli/primitives/__tests__/credential-utils.test.ts @@ -0,0 +1,60 @@ +import { + computeDefaultCredentialEnvVarName, + computePaymentCredentialEnvVarNames, + computeStripePrivyCredentialEnvVarNames, +} from '../credential-utils'; +import { describe, expect, it } from 'vitest'; + +describe('computeDefaultCredentialEnvVarName', () => { + it('uppercases the credential name', () => { + expect(computeDefaultCredentialEnvVarName('myCredential')).toBe('AGENTCORE_CREDENTIAL_MYCREDENTIAL'); + }); + + it('converts hyphens to underscores', () => { + expect(computeDefaultCredentialEnvVarName('my-api-key')).toBe('AGENTCORE_CREDENTIAL_MY_API_KEY'); + }); + + it('handles names already containing underscores', () => { + expect(computeDefaultCredentialEnvVarName('my_cred')).toBe('AGENTCORE_CREDENTIAL_MY_CRED'); + }); + + it('handles mixed hyphens and underscores', () => { + expect(computeDefaultCredentialEnvVarName('my-cred_name')).toBe('AGENTCORE_CREDENTIAL_MY_CRED_NAME'); + }); +}); + +describe('computePaymentCredentialEnvVarNames', () => { + it('returns three env var names with correct suffixes', () => { + const result = computePaymentCredentialEnvVarNames('myMgr-conn-cdp'); + expect(result).toEqual({ + apiKeyId: 'AGENTCORE_CREDENTIAL_MYMGR_CONN_CDP_API_KEY_ID', + apiKeySecret: 'AGENTCORE_CREDENTIAL_MYMGR_CONN_CDP_API_KEY_SECRET', + walletSecret: 'AGENTCORE_CREDENTIAL_MYMGR_CONN_CDP_WALLET_SECRET', + }); + }); + + it('converts hyphens to underscores in prefix', () => { + const result = computePaymentCredentialEnvVarNames('a-b-c'); + expect(result.apiKeyId).toBe('AGENTCORE_CREDENTIAL_A_B_C_API_KEY_ID'); + }); +}); + +describe('computeStripePrivyCredentialEnvVarNames', () => { + it('returns four env var names with correct suffixes', () => { + const result = computeStripePrivyCredentialEnvVarNames('mgr-conn-stripe-privy'); + expect(result).toEqual({ + appId: 'AGENTCORE_CREDENTIAL_MGR_CONN_STRIPE_PRIVY_APP_ID', + appSecret: 'AGENTCORE_CREDENTIAL_MGR_CONN_STRIPE_PRIVY_APP_SECRET', + authorizationPrivateKey: 'AGENTCORE_CREDENTIAL_MGR_CONN_STRIPE_PRIVY_AUTHORIZATION_PRIVATE_KEY', + authorizationId: 'AGENTCORE_CREDENTIAL_MGR_CONN_STRIPE_PRIVY_AUTHORIZATION_ID', + }); + }); + + it('handles name with no hyphens', () => { + const result = computeStripePrivyCredentialEnvVarNames('simple'); + expect(result.appId).toBe('AGENTCORE_CREDENTIAL_SIMPLE_APP_ID'); + expect(result.appSecret).toBe('AGENTCORE_CREDENTIAL_SIMPLE_APP_SECRET'); + expect(result.authorizationPrivateKey).toBe('AGENTCORE_CREDENTIAL_SIMPLE_AUTHORIZATION_PRIVATE_KEY'); + expect(result.authorizationId).toBe('AGENTCORE_CREDENTIAL_SIMPLE_AUTHORIZATION_ID'); + }); +}); diff --git a/src/cli/primitives/__tests__/payment-validation.test.ts b/src/cli/primitives/__tests__/payment-validation.test.ts new file mode 100644 index 000000000..4eb829e80 --- /dev/null +++ b/src/cli/primitives/__tests__/payment-validation.test.ts @@ -0,0 +1,135 @@ +import { describe, expect, it } from 'vitest'; + +describe('autoPayment CLI parsing', () => { + function parseAutoPayment(value: string | boolean | undefined): boolean | undefined { + if (value === undefined) return undefined; + return !['false', 'no', '0', 'off'].includes(String(value).toLowerCase()); + } + + describe('falsy string values produce false', () => { + it.each(['false', 'False', 'FALSE', 'no', 'No', 'NO', '0', 'off', 'Off', 'OFF'])( + 'parseAutoPayment("%s") returns false', + (val) => { + expect(parseAutoPayment(val)).toBe(false); + } + ); + }); + + describe('truthy values produce true', () => { + it.each(['true', 'True', 'TRUE', 'yes', '1', 'on', 'anything'])( + 'parseAutoPayment("%s") returns true', + (val) => { + expect(parseAutoPayment(val)).toBe(true); + } + ); + }); + + it('boolean true passes through as true', () => { + expect(parseAutoPayment(true)).toBe(true); + }); + + it('boolean false passes through as false', () => { + expect(parseAutoPayment(false)).toBe(false); + }); + + it('undefined returns undefined', () => { + expect(parseAutoPayment(undefined)).toBeUndefined(); + }); +}); + +describe('defaultSpendLimit validation', () => { + function validateSpendLimit(value: string): { valid: boolean } { + const num = Number(value); + if (Number.isNaN(num) || num < 0) return { valid: false }; + return { valid: true }; + } + + it('accepts "0"', () => expect(validateSpendLimit('0')).toEqual({ valid: true })); + it('accepts "10.50"', () => expect(validateSpendLimit('10.50')).toEqual({ valid: true })); + it('accepts large numbers', () => expect(validateSpendLimit('999999.99')).toEqual({ valid: true })); + it('rejects negative values', () => expect(validateSpendLimit('-1')).toEqual({ valid: false })); + it('rejects non-numeric strings', () => expect(validateSpendLimit('abc')).toEqual({ valid: false })); + it('accepts empty string as 0 (Number("") === 0)', () => expect(validateSpendLimit('')).toEqual({ valid: true })); +}); + +describe('base64 key validation', () => { + const BASE64_REGEX = /^[A-Za-z0-9+/]+=*$/; + + function validateBase64Key(key: string): { valid: boolean; error?: string } { + const trimmed = key.trim(); + if (!BASE64_REGEX.test(trimmed)) return { valid: false, error: 'not base64' }; + const decoded = Buffer.from(trimmed, 'base64'); + if (decoded.length < 100 || decoded.length > 200) return { valid: false, error: 'unexpected length' }; + return { valid: true }; + } + + it('rejects non-base64 characters', () => { + expect(validateBase64Key('not-base64!').valid).toBe(false); + }); + + it('rejects too-short decoded key (< 100 bytes)', () => { + expect(validateBase64Key('dGVzdA==').valid).toBe(false); + }); + + it('rejects too-long decoded key (> 200 bytes)', () => { + const buf = Buffer.alloc(201, 0x42); + expect(validateBase64Key(buf.toString('base64')).valid).toBe(false); + }); + + it('accepts decoded key of exactly 100 bytes', () => { + const buf = Buffer.alloc(100, 0x41); + expect(validateBase64Key(buf.toString('base64')).valid).toBe(true); + }); + + it('accepts decoded key of exactly 200 bytes', () => { + const buf = Buffer.alloc(200, 0x41); + expect(validateBase64Key(buf.toString('base64')).valid).toBe(true); + }); + + it('accepts a valid ~138 byte key', () => { + const key = 'RkFLRV9TVFJJUEVfUFJJVllfVEVTVF9LRVlfQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ=='; + expect(validateBase64Key(key).valid).toBe(true); + }); +}); + +describe('credential sanitization regex', () => { + const REGEX = /("apiKeySecret"|"walletSecret"|"apiKeyId"|"appId"|"appSecret"|"authorizationPrivateKey"|"authorizationId")\s*:\s*"[^"]*"/g; + + function sanitize(body: string): string { + return body.replace(REGEX, '$1:"[REDACTED]"').slice(0, 500); + } + + it('redacts all 7 credential field names', () => { + const body = JSON.stringify({ + apiKeyId: 'key-123', + apiKeySecret: 'secret-456', + walletSecret: 'wallet-789', + appId: 'app-abc', + appSecret: 'app-secret-def', + authorizationPrivateKey: 'priv-key-ghi', + authorizationId: 'auth-jkl', + }); + const result = sanitize(body); + expect(result).not.toContain('key-123'); + expect(result).not.toContain('secret-456'); + expect(result).not.toContain('wallet-789'); + expect(result).not.toContain('app-abc'); + expect(result).not.toContain('app-secret-def'); + expect(result).not.toContain('priv-key-ghi'); + expect(result).not.toContain('auth-jkl'); + expect(result).toContain('[REDACTED]'); + }); + + it('preserves non-credential fields', () => { + const body = JSON.stringify({ message: 'Not found', code: 'ResourceNotFoundException', apiKeySecret: 'leaked' }); + const result = sanitize(body); + expect(result).toContain('Not found'); + expect(result).toContain('ResourceNotFoundException'); + expect(result).not.toContain('leaked'); + }); + + it('truncates to 500 characters', () => { + const longBody = '{"apiKeyId":"x"}'.repeat(100); + expect(sanitize(longBody).length).toBeLessThanOrEqual(500); + }); +}); diff --git a/src/cli/primitives/__tests__/wirePaymentCapability.test.ts b/src/cli/primitives/__tests__/wirePaymentCapability.test.ts new file mode 100644 index 000000000..1a30b3822 --- /dev/null +++ b/src/cli/primitives/__tests__/wirePaymentCapability.test.ts @@ -0,0 +1,562 @@ +import type { AgentCoreProjectSpec } from '../../../schema'; +import { PaymentManagerPrimitive } from '../PaymentManagerPrimitive'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +// --------------------------------------------------------------------------- +// Hoisted mocks — must be defined before any imports are processed +// --------------------------------------------------------------------------- +const { + mockFindConfigRoot, + mockReadProjectSpec, + mockWriteProjectSpec, + mockExistsSync, + mockMkdirSync, + mockCopyFileSync, + mockWriteFileSync, + mockReadFileSync, +} = vi.hoisted(() => ({ + mockFindConfigRoot: vi.fn().mockReturnValue('/project/agentcore'), + mockReadProjectSpec: vi.fn(), + mockWriteProjectSpec: vi.fn().mockResolvedValue(undefined), + mockExistsSync: vi.fn(), + mockMkdirSync: vi.fn(), + mockCopyFileSync: vi.fn(), + mockWriteFileSync: vi.fn(), + mockReadFileSync: vi.fn(), +})); + +vi.mock('../../../lib', () => { + const MockConfigIO = vi.fn(function (this: Record) { + this.configExists = vi.fn().mockReturnValue(true); + this.readProjectSpec = mockReadProjectSpec; + this.writeProjectSpec = mockWriteProjectSpec; + }); + return { + ConfigIO: MockConfigIO, + findConfigRoot: mockFindConfigRoot, + setEnvVar: vi.fn().mockResolvedValue(undefined), + removeEnvVars: vi.fn().mockResolvedValue(undefined), + toError: (err: unknown) => (err instanceof Error ? err : new Error(String(err))), + serializeResult: (r: unknown) => r, + ResourceNotFoundError: class extends Error { + constructor(m: string) { + super(m); + this.name = 'ResourceNotFoundError'; + } + }, + }; +}); + +vi.mock('node:fs', () => ({ + existsSync: mockExistsSync, + mkdirSync: mockMkdirSync, + copyFileSync: mockCopyFileSync, + writeFileSync: mockWriteFileSync, + readFileSync: mockReadFileSync, +})); + +vi.mock('../../templates/templateRoot', () => ({ + getTemplatePath: (...segments: string[]) => `/cli-templates/${segments.join('/')}`, +})); + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/** Minimal valid AgentCoreProjectSpec with one runtime at the given codeLocation */ +function makeProject(codeLocation: string): AgentCoreProjectSpec { + return { + name: 'test-project', + version: 1, + managedBy: 'CDK' as const, + runtimes: [ + { + name: 'my-agent', + build: 'CodeZip' as const, + entrypoint: 'main.handler' as any, + codeLocation: codeLocation as any, + }, + ], + memories: [], + credentials: [], + evaluators: [], + onlineEvalConfigs: [], + agentCoreGateways: [], + policyEngines: [], + configBundles: [], + abTests: [], + httpGateways: [], + payments: [], + }; +} + +/** Absolute agent directory derived from project root + codeLocation */ +const PROJECT_ROOT = '/project'; +const CODE_LOCATION = 'agents/my-agent'; +const AGENT_DIR = `${PROJECT_ROOT}/${CODE_LOCATION}`; +const CAP_DIR = `${AGENT_DIR}/capabilities/payments`; +const PAYMENTS_PY_DEST = `${CAP_DIR}/payments.py`; +const PAYMENTS_PY_SRC = `/cli-templates/python/http/strands/capabilities/payments/payments.py`; +const TEMPLATE_DIR = `/cli-templates/python/http/strands/capabilities/payments`; +const MAIN_PY = `${AGENT_DIR}/main.py`; +const CAP_INIT = `${CAP_DIR}/__init__.py`; +const PARENT_INIT = `${AGENT_DIR}/capabilities/__init__.py`; + +/** Default add options that skip duplicate/CUSTOM_JWT guards */ +const ADD_OPTIONS = { + name: 'payments-mgr', + authorizerType: 'AWS_IAM' as const, + pattern: 'interceptor' as const, +}; + +/** Call primitive.add() which internally calls wirePaymentCapability() for every runtime */ +async function callAdd(primitive: PaymentManagerPrimitive, project: AgentCoreProjectSpec) { + mockReadProjectSpec.mockResolvedValue(project); + return primitive.add(ADD_OPTIONS); +} + +// --------------------------------------------------------------------------- +// Shared setup +// --------------------------------------------------------------------------- +describe('wirePaymentCapability (via PaymentManagerPrimitive.add)', () => { + let primitive: PaymentManagerPrimitive; + + beforeEach(() => { + vi.clearAllMocks(); + primitive = new PaymentManagerPrimitive(); + + // Default: template directory exists, cap dir does NOT yet exist (so we proceed) + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; // not yet copied — trigger wiring + return false; // everything else absent by default + }); + + // readFileSync returns a minimal main.py by default (overridden per test) + mockReadFileSync.mockReturnValue(''); + }); + + // ========================================================================= + // Test 1 – Template agent: get_or_create_agent() pattern + // ========================================================================= + describe('template agent with get_or_create_agent() pattern', () => { + const templateMain = [ + 'import os', + 'from strands import Agent, tool', + '', + '_agent = None', + '', + 'def get_or_create_agent():', + ' global _agent', + ' if _agent is None:', + ' _agent = Agent(', + ' model=load_model(),', + ' system_prompt="You are helpful.",', + ' tools=tools,', + ' )', + ' return _agent', + '', + '@app.entrypoint', + 'async def invoke(payload, context):', + ' agent = get_or_create_agent()', + ' stream = agent.stream_async(payload.get("prompt"))', + ' async for event in stream:', + ' yield event', + ].join('\n'); + + beforeEach(() => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(templateMain); + }); + + it('replaces "agent = get_or_create_agent()" with per-invocation plugin block', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + expect(mockWriteFileSync).toHaveBeenCalledWith(MAIN_PY, expect.any(String)); + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + // Original call is gone + expect(written).not.toContain('agent = get_or_create_agent()'); + + // Per-invocation plugin block inserted + expect(written).toContain('user_id = payload.get("user_id")'); + expect(written).toContain('instrument_id = payload.get("payment_instrument_id")'); + expect(written).toContain('session_id = payload.get("payment_session_id")'); + expect(written).toContain('payments_plugin = create_payments_plugin(user_id, instrument_id, session_id)'); + expect(written).toContain('plugins = [payments_plugin] if payments_plugin else []'); + + // Replacement spawns a new Agent() constructor + expect(written).toContain('agent = Agent('); + expect(written).toContain('plugins=plugins,'); + + // Import line inserted + expect(written).toContain('from capabilities.payments.payments import create_payments_plugin'); + }); + + it('inserts the import after the last existing import line', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + // 'from strands import Agent, tool' is the last import; new import comes after it + const strandsPos = written.indexOf('from strands import Agent, tool'); + const pluginImportPos = written.indexOf('from capabilities.payments.payments import create_payments_plugin'); + expect(strandsPos).toBeGreaterThanOrEqual(0); + expect(pluginImportPos).toBeGreaterThan(strandsPos); + }); + }); + + // ========================================================================= + // Test 2 – BYO agent: Agent() constructor present but no get_or_create_agent + // ========================================================================= + describe('BYO agent with existing Agent() constructor', () => { + const byoMain = [ + 'import os', + 'from strands import Agent, tool', + '', + '@app.entrypoint', + 'async def invoke(payload, context):', + ' agent = Agent(', + ' model="anthropic.claude-3-5-sonnet-20241022-v2:0",', + ' system_prompt="You are a payment assistant.",', + ' tools=my_tools,', + ' )', + ' stream = agent.stream_async(payload.get("prompt"))', + ' async for event in stream:', + ' yield event', + ].join('\n'); + + beforeEach(() => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(byoMain); + }); + + it('inserts plugin setup block before the existing Agent() constructor', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + // Plugin setup block is present + expect(written).toContain('user_id = payload.get("user_id")'); + expect(written).toContain('payments_plugin = create_payments_plugin(user_id, instrument_id, session_id)'); + expect(written).toContain('plugins = [payments_plugin] if payments_plugin else []'); + + // Plugin setup appears before Agent( + const pluginPos = written.indexOf('payments_plugin = create_payments_plugin'); + const agentPos = written.indexOf('agent = Agent('); + expect(pluginPos).toBeGreaterThanOrEqual(0); + expect(agentPos).toBeGreaterThan(pluginPos); + }); + + it('adds TODO comment to add plugins= to existing Agent() constructor', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + expect(written).toContain('# TODO: Add plugins=plugins to your Agent() constructor below'); + }); + + it('inserts the payment import line', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + expect(written).toContain('from capabilities.payments.payments import create_payments_plugin'); + }); + }); + + // ========================================================================= + // Test 3 – Minimal agent: no known pattern + // ========================================================================= + describe('minimal agent with neither get_or_create_agent nor Agent() pattern', () => { + const minimalMain = ['def h(e, c): pass'].join('\n'); + + beforeEach(() => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(minimalMain); + }); + + it('adds the import line at the top when there are no existing imports', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + expect(written).toContain('from capabilities.payments.payments import create_payments_plugin'); + }); + + it('does NOT insert a plugin block when no known agent pattern found', async () => { + const result = await callAdd(primitive, makeProject(CODE_LOCATION)); + expect(result.success).toBe(true); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + // No plugin setup injected + expect(written).not.toContain('payments_plugin = create_payments_plugin'); + expect(written).not.toContain('plugins = [payments_plugin]'); + }); + }); + + // ========================================================================= + // Test 4 – Idempotency: running twice doesn't double-add imports + // ========================================================================= + describe('idempotency', () => { + it('does not re-process main.py when payments.py already exists in cap dir', async () => { + // Simulate already-wired state: payments.py already present + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return true; // already wired + return false; + }); + mockReadFileSync.mockReturnValue( + 'from capabilities.payments.payments import create_payments_plugin\ndef h(e,c): pass' + ); + + // First add + const project = makeProject(CODE_LOCATION); + await callAdd(primitive, project); + + // Second add (simulate calling add again with updated project that now has the payment manager) + const _projectWithManager: AgentCoreProjectSpec = { + ...project, + payments: [ + { + name: ADD_OPTIONS.name, + authorizerType: ADD_OPTIONS.authorizerType, + pattern: ADD_OPTIONS.pattern, + connectors: [], + }, + ], + }; + // Reset the mock to allow the second write to the project spec + mockWriteProjectSpec.mockResolvedValue(undefined); + // But now payments already exist, so checkDuplicate will reject it + // Instead test that writeFileSync on main.py is never called when payments.py already exists + vi.clearAllMocks(); + mockWriteProjectSpec.mockResolvedValue(undefined); + mockFindConfigRoot.mockReturnValue('/project/agentcore'); + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return true; // already present + return false; + }); + mockReadProjectSpec.mockResolvedValue({ ...project, payments: [] }); + + await primitive.add(ADD_OPTIONS); + + // wirePaymentCapability exits early (payments.py already exists), so main.py never written + const mainPyWrite = mockWriteFileSync.mock.calls.find((c: unknown[]) => (c[0] as string) === MAIN_PY); + expect(mainPyWrite).toBeUndefined(); + }); + + it('does not double-add import if create_payments_plugin already in main.py', async () => { + const alreadyPatched = [ + 'from strands import Agent', + 'from capabilities.payments.payments import create_payments_plugin', + '', + '@app.entrypoint', + 'async def invoke(payload, context):', + ' payments_plugin = create_payments_plugin("u", None, None)', + ' pass', + ].join('\n'); + + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; // cap dir missing — enter wiring + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(alreadyPatched); + + await callAdd(primitive, makeProject(CODE_LOCATION)); + + // main.py must NOT be written because create_payments_plugin already present + const mainPyWrite = mockWriteFileSync.mock.calls.find((c: unknown[]) => (c[0] as string) === MAIN_PY); + expect(mainPyWrite).toBeUndefined(); + }); + }); + + // ========================================================================= + // Test 5 – capabilities/payments/ directory created and payments.py copied + // ========================================================================= + describe('capabilities/payments/ directory and payments.py', () => { + beforeEach(() => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return false; // no main.py → skip patching + return false; + }); + mockReadFileSync.mockReturnValue(''); + }); + + it('creates capabilities/payments/ directory with recursive flag', async () => { + await callAdd(primitive, makeProject(CODE_LOCATION)); + + expect(mockMkdirSync).toHaveBeenCalledWith(CAP_DIR, { recursive: true }); + }); + + it('copies payments.py from template to capabilities/payments/', async () => { + await callAdd(primitive, makeProject(CODE_LOCATION)); + + expect(mockCopyFileSync).toHaveBeenCalledWith(PAYMENTS_PY_SRC, PAYMENTS_PY_DEST); + }); + + it('skips wiring entirely when template directory does not exist', async () => { + mockExistsSync.mockImplementation((p: string) => { + if (p === PAYMENTS_PY_DEST) return false; + if (p === TEMPLATE_DIR) return false; // template missing + return false; + }); + + await callAdd(primitive, makeProject(CODE_LOCATION)); + + expect(mockMkdirSync).not.toHaveBeenCalled(); + expect(mockCopyFileSync).not.toHaveBeenCalled(); + }); + }); + + // ========================================================================= + // Test 6 – capabilities/__init__.py created if missing + // ========================================================================= + describe('__init__.py creation', () => { + beforeEach(() => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return false; + return false; // init files absent + }); + }); + + it('creates capabilities/payments/__init__.py when absent', async () => { + await callAdd(primitive, makeProject(CODE_LOCATION)); + + expect(mockWriteFileSync).toHaveBeenCalledWith(CAP_INIT, ''); + }); + + it('creates capabilities/__init__.py when absent', async () => { + await callAdd(primitive, makeProject(CODE_LOCATION)); + + expect(mockWriteFileSync).toHaveBeenCalledWith(PARENT_INIT, ''); + }); + + it('does not overwrite capabilities/payments/__init__.py when it already exists', async () => { + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return false; + if (p === CAP_INIT) return true; // already exists + if (p === PARENT_INIT) return true; // already exists + return false; + }); + + await callAdd(primitive, makeProject(CODE_LOCATION)); + + const initWrites = mockWriteFileSync.mock.calls.filter( + (c: unknown[]) => (c[0] as string) === CAP_INIT || (c[0] as string) === PARENT_INIT + ); + expect(initWrites).toHaveLength(0); + }); + }); + + // ========================================================================= + // Test 7 – Import line inserted at the correct position + // ========================================================================= + describe('import line position', () => { + it('inserts after the last import when multiple imports exist', async () => { + const main = [ + 'import os', + 'import logging', + 'from strands import Agent, tool', + 'from bedrock_agentcore.runtime import BedrockAgentCoreApp', + '', + 'app = BedrockAgentCoreApp()', + '', + '@app.entrypoint', + 'async def invoke(payload, context):', + ' pass', + ].join('\n'); + + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(main); + + await callAdd(primitive, makeProject(CODE_LOCATION)); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + const lastOriginalImport = 'from bedrock_agentcore.runtime import BedrockAgentCoreApp'; + const pluginImport = 'from capabilities.payments.payments import create_payments_plugin'; + + const lastImportPos = written.indexOf(lastOriginalImport); + const pluginImportPos = written.indexOf(pluginImport); + + // Import lands immediately after the last existing import + expect(pluginImportPos).toBeGreaterThan(lastImportPos); + // Nothing but a newline separates them + const between = written.slice(lastImportPos + lastOriginalImport.length, pluginImportPos); + expect(between).toBe('\n'); + }); + + it('prepends import at top of file when there are no existing imports', async () => { + const noImports = ['def handler(event, context):', ' return {}'].join('\n'); + + mockExistsSync.mockImplementation((p: string) => { + if (p === TEMPLATE_DIR) return true; + if (p === PAYMENTS_PY_DEST) return false; + if (p === MAIN_PY) return true; + return false; + }); + mockReadFileSync.mockReturnValue(noImports); + + await callAdd(primitive, makeProject(CODE_LOCATION)); + + const written: string = mockWriteFileSync.mock.calls.find( + (c: unknown[]) => (c[0] as string) === MAIN_PY + )![1] as string; + + expect(written.startsWith('from capabilities.payments.payments import create_payments_plugin')).toBe(true); + }); + }); +}); diff --git a/src/cli/primitives/credential-utils.ts b/src/cli/primitives/credential-utils.ts index 8c1df16e0..6431a0ec6 100644 --- a/src/cli/primitives/credential-utils.ts +++ b/src/cli/primitives/credential-utils.ts @@ -15,3 +15,39 @@ export function computeDefaultCredentialEnvVarName(credentialName: string): stri export function computeManagedOAuthCredentialName(gatewayName: string): string { return `${gatewayName}-oauth`; } + +/** + * Compute the env var names for a CoinbaseCDP payment credential. + * CoinbaseCDP credentials require 3 env vars. + */ +export function computePaymentCredentialEnvVarNames(credentialName: string): { + apiKeyId: string; + apiKeySecret: string; + walletSecret: string; +} { + const prefix = `AGENTCORE_CREDENTIAL_${credentialName.replace(/-/g, '_').toUpperCase()}`; + return { + apiKeyId: `${prefix}_API_KEY_ID`, + apiKeySecret: `${prefix}_API_KEY_SECRET`, + walletSecret: `${prefix}_WALLET_SECRET`, + }; +} + +/** + * Compute the env var names for a StripePrivy payment credential. + * StripePrivy credentials require 4 env vars. + */ +export function computeStripePrivyCredentialEnvVarNames(credentialName: string): { + appId: string; + appSecret: string; + authorizationPrivateKey: string; + authorizationId: string; +} { + const prefix = `AGENTCORE_CREDENTIAL_${credentialName.replace(/-/g, '_').toUpperCase()}`; + return { + appId: `${prefix}_APP_ID`, + appSecret: `${prefix}_APP_SECRET`, + authorizationPrivateKey: `${prefix}_AUTHORIZATION_PRIVATE_KEY`, + authorizationId: `${prefix}_AUTHORIZATION_ID`, + }; +} diff --git a/src/cli/primitives/registry.ts b/src/cli/primitives/registry.ts index 754b4e182..f4a210dba 100644 --- a/src/cli/primitives/registry.ts +++ b/src/cli/primitives/registry.ts @@ -8,6 +8,8 @@ import { GatewayPrimitive } from './GatewayPrimitive'; import { GatewayTargetPrimitive } from './GatewayTargetPrimitive'; import { MemoryPrimitive } from './MemoryPrimitive'; import { OnlineEvalConfigPrimitive } from './OnlineEvalConfigPrimitive'; +import { PaymentConnectorPrimitive } from './PaymentConnectorPrimitive'; +import { PaymentManagerPrimitive } from './PaymentManagerPrimitive'; import { PolicyEnginePrimitive } from './PolicyEnginePrimitive'; import { PolicyPrimitive } from './PolicyPrimitive'; import { RuntimeEndpointPrimitive } from './RuntimeEndpointPrimitive'; @@ -28,6 +30,8 @@ export const policyPrimitive = new PolicyPrimitive(); export const configBundlePrimitive = new ConfigBundlePrimitive(); export const abTestPrimitive = new ABTestPrimitive(); export const runtimeEndpointPrimitive = new RuntimeEndpointPrimitive(); +export const paymentManagerPrimitive = new PaymentManagerPrimitive(); +export const paymentConnectorPrimitive = new PaymentConnectorPrimitive(); /** * All primitives in display order. @@ -45,6 +49,8 @@ export const ALL_PRIMITIVES: BasePrimitive[] = [ configBundlePrimitive, abTestPrimitive, runtimeEndpointPrimitive, + paymentManagerPrimitive, + paymentConnectorPrimitive, ]; /** diff --git a/src/cli/project.ts b/src/cli/project.ts index 14ea7be3c..3af4b9d19 100644 --- a/src/cli/project.ts +++ b/src/cli/project.ts @@ -21,6 +21,7 @@ export function createDefaultProjectSpec(projectName: string): AgentCoreProjectS configBundles: [], abTests: [], httpGateways: [], + payments: [], tags: { 'agentcore:created-by': 'agentcore-cli', 'agentcore:project-name': projectName, diff --git a/src/cli/telemetry/schemas/command-run.ts b/src/cli/telemetry/schemas/command-run.ts index fae8f8394..18103e930 100644 --- a/src/cli/telemetry/schemas/command-run.ts +++ b/src/cli/telemetry/schemas/command-run.ts @@ -160,6 +160,8 @@ export const COMMAND_SCHEMAS = { 'add.policy-engine': AddPolicyEngineAttrs, 'add.policy': AddPolicyAttrs, 'add.runtime-endpoint': NoAttrs, + 'add.payment-manager': NoAttrs, + 'add.payment-connector': NoAttrs, // deploy deploy: DeployAttrs, @@ -210,6 +212,8 @@ export const COMMAND_SCHEMAS = { 'remove.runtime-endpoint': NoAttrs, 'remove.config-bundle': NoAttrs, 'remove.ab-test': NoAttrs, + 'remove.payment-manager': NoAttrs, + 'remove.payment-connector': NoAttrs, 'telemetry.disable': NoAttrs, 'telemetry.enable': NoAttrs, 'telemetry.status': NoAttrs, diff --git a/src/cli/templates/BaseRenderer.ts b/src/cli/templates/BaseRenderer.ts index 659722926..6d3c1f42b 100644 --- a/src/cli/templates/BaseRenderer.ts +++ b/src/cli/templates/BaseRenderer.ts @@ -1,7 +1,7 @@ import { APP_DIR } from '../../lib'; import { copyAndRenderDir } from './render'; import type { AgentRenderConfig } from './types'; -import { existsSync } from 'node:fs'; +import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import * as path from 'node:path'; export interface RendererContext { @@ -32,6 +32,10 @@ export abstract class BaseRenderer { return this.config.hasMemory; } + protected shouldRenderPayment(): boolean { + return this.config.hasPayment; + } + protected getTemplateDir(): string { const language = this.config.targetLanguage.toLowerCase(); return path.join(this.baseTemplateDir, language, this.protocolMode, this.sdkName); @@ -65,6 +69,18 @@ export abstract class BaseRenderer { } } + if (this.shouldRenderPayment()) { + const paymentCapabilityDir = path.join(templateDir, 'capabilities', 'payments'); + if (existsSync(paymentCapabilityDir)) { + const capabilitiesDir = path.join(projectDir, 'capabilities'); + mkdirSync(capabilitiesDir, { recursive: true }); + const capInitPath = path.join(capabilitiesDir, '__init__.py'); + if (!existsSync(capInitPath)) writeFileSync(capInitPath, ''); + const paymentTargetDir = path.join(capabilitiesDir, 'payments'); + await copyAndRenderDir(paymentCapabilityDir, paymentTargetDir, templateData); + } + } + // Generate Dockerfile and .dockerignore for Container builds if (this.config.buildType === 'Container') { const language = this.config.targetLanguage.toLowerCase(); diff --git a/src/cli/templates/render.ts b/src/cli/templates/render.ts index 55c228555..0d737f4ec 100644 --- a/src/cli/templates/render.ts +++ b/src/cli/templates/render.ts @@ -2,6 +2,8 @@ import Handlebars from 'handlebars'; import * as fs from 'node:fs/promises'; import * as path from 'node:path'; +const BINARY_EXTENSIONS = new Set(['.whl', '.tgz', '.gz', '.zip', '.tar', '.png', '.jpg', '.ico', '.pyc']); + // Register custom Handlebars helpers Handlebars.registerHelper('eq', (a: unknown, b: unknown) => a === b); Handlebars.registerHelper('includes', (array: unknown[], value: unknown) => { @@ -65,11 +67,16 @@ export async function copyAndRenderDir( if (entry.isDirectory()) { await copyAndRenderDir(srcPath, destPath, data); } else { - const content = await fs.readFile(srcPath, 'utf-8'); - const template = Handlebars.compile(content); - const rendered = template(data); await fs.mkdir(path.dirname(destPath), { recursive: true }); - await fs.writeFile(destPath, rendered, 'utf-8'); + const ext = path.extname(entry.name).toLowerCase(); + if (BINARY_EXTENSIONS.has(ext)) { + await fs.copyFile(srcPath, destPath); + } else { + const content = await fs.readFile(srcPath, 'utf-8'); + const template = Handlebars.compile(content); + const rendered = template(data); + await fs.writeFile(destPath, rendered, 'utf-8'); + } } } } diff --git a/src/cli/templates/types.ts b/src/cli/templates/types.ts index 907cc99dd..60db2b7c7 100644 --- a/src/cli/templates/types.ts +++ b/src/cli/templates/types.ts @@ -52,6 +52,7 @@ export interface AgentRenderConfig { hasMemory: boolean; hasIdentity: boolean; hasGateway: boolean; + hasPayment: boolean; /** Whether agent is deployed in VPC mode (affects example MCP endpoints) */ isVpc: boolean; /** Build type: CodeZip (default) or Container */ diff --git a/src/cli/tui/components/ResourceGraph.tsx b/src/cli/tui/components/ResourceGraph.tsx index 36504cd62..24363ba69 100644 --- a/src/cli/tui/components/ResourceGraph.tsx +++ b/src/cli/tui/components/ResourceGraph.tsx @@ -23,6 +23,7 @@ const ICONS = { 'config-bundle': '⬡', 'ab-test': '⚗', 'runtime-endpoint': '◉', + payment: '₿', } as const; interface ResourceGraphProps { diff --git a/src/cli/tui/hooks/useCdkPreflight.ts b/src/cli/tui/hooks/useCdkPreflight.ts index 062da752f..31ae4daa7 100644 --- a/src/cli/tui/hooks/useCdkPreflight.ts +++ b/src/cli/tui/hooks/useCdkPreflight.ts @@ -22,10 +22,100 @@ import { synthesizeCdk, validateProject, } from '../../operations/deploy'; +import { + hasPaymentCredentialProviders, + setupPaymentCredentialProviders, +} from '../../operations/deploy/pre-deploy-identity'; import type { Step } from '../components'; import * as path from 'node:path'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +const LABEL_PAYMENTS = 'Creating payment infrastructure'; + +interface RunPaymentSetupOptions { + projectSpec: PreflightContext['projectSpec']; + awsTargets: PreflightContext['awsTargets']; + runtimeCredentials?: SecureCredentials; + logger: ExecLogger; + setSteps: React.Dispatch>; + updateStepByLabel: (label: string, update: Partial) => void; + setPhase: (phase: PreflightPhase) => void; + isRunningRef: React.MutableRefObject; + setAllCredentials: React.Dispatch< + React.SetStateAction< + Record + > + >; +} + +async function runPaymentPreDeploy(opts: RunPaymentSetupOptions): Promise { + const { + projectSpec, + awsTargets, + runtimeCredentials, + logger, + setSteps, + updateStepByLabel, + setPhase, + isRunningRef, + setAllCredentials, + } = opts; + + if (!hasPaymentCredentialProviders(projectSpec)) return true; + + setSteps(prev => { + const synthIndex = prev.findIndex(s => s.label === LABEL_SYNTH); + return [...prev.slice(0, synthIndex), { label: LABEL_PAYMENTS, status: 'running' }, ...prev.slice(synthIndex)]; + }); + logger.startStep('Setting up payment credentials...'); + + const target = awsTargets[0]!; + const paymentConfigIO = new ConfigIO(); + + const paymentResult = await setupPaymentCredentialProviders({ + projectSpec, + configBaseDir: paymentConfigIO.getConfigRoot(), + region: target.region, + runtimeCredentials: runtimeCredentials ?? undefined, + }); + + if (paymentResult.hasErrors) { + const errorMsg = paymentResult.errors.join('; '); + logger.endStep('error', errorMsg); + updateStepByLabel(LABEL_PAYMENTS, { status: 'error', error: `Payment setup failed: ${errorMsg}` }); + setPhase('error'); + isRunningRef.current = false; + return false; + } + + // Merge payment credential provider ARNs into deployed credentials (same path as identity) + const existingState = await paymentConfigIO.readDeployedState().catch(() => ({ targets: {} }) as DeployedState); + const targetState = existingState.targets?.[target.name] ?? { resources: {} }; + targetState.resources ??= {}; + const existingCreds = targetState.resources.credentials ?? {}; + for (const [name, result] of Object.entries(paymentResult.credentialProviders)) { + existingCreds[name] = { credentialProviderArn: result.credentialProviderArn }; + } + targetState.resources.credentials = existingCreds; + await paymentConfigIO.writeDeployedState({ + ...existingState, + targets: { ...existingState.targets, [target.name]: targetState }, + }); + + // Update in-memory credentials so useDeployFlow.persistDeployedState has correct ARNs + setAllCredentials(prev => { + const updated = { ...prev }; + for (const [name, result] of Object.entries(paymentResult.credentialProviders)) { + updated[name] = { credentialProviderArn: result.credentialProviderArn }; + } + return updated; + }); + + logger.endStep('success'); + updateStepByLabel(LABEL_PAYMENTS, { status: 'success' }); + return true; +} + type PreflightPhase = | 'idle' | 'running' @@ -423,6 +513,19 @@ export function useCdkPreflight(options: PreflightOptions): PreflightResult { return; } + // Set up payment resources (no-identity-providers path) + const paymentOk = await runPaymentPreDeploy({ + projectSpec: preflightContext.projectSpec, + awsTargets: preflightContext.awsTargets, + logger, + setSteps, + updateStepByLabel, + setPhase, + isRunningRef, + setAllCredentials, + }); + if (!paymentOk) return; + // Step: Synthesize CloudFormation updateStepByLabel(LABEL_SYNTH, { status: 'running' }); logger.startStep('Synthesize CloudFormation'); @@ -538,11 +641,25 @@ export function useCdkPreflight(options: PreflightOptions): PreflightResult { isRunningRef.current = true; const runIdentitySetup = async () => { - // If user chose to skip, go directly to synth + // If user chose to skip, still run payment setup then go to synth if (skipIdentitySetup) { logger.log('Skipping identity provider setup (user choice)'); setSkipIdentitySetup(false); // Reset for next run + // Set up payment resources even when identity is skipped + const paymentOkSkip = await runPaymentPreDeploy({ + projectSpec: context.projectSpec, + awsTargets: context.awsTargets, + runtimeCredentials: runtimeCredentials ?? undefined, + logger, + setSteps, + updateStepByLabel, + setPhase, + isRunningRef, + setAllCredentials, + }); + if (!paymentOkSkip) return; + // Synthesize CloudFormation updateStepByLabel(LABEL_SYNTH, { status: 'running' }); logger.startStep('Synthesize CloudFormation'); @@ -781,6 +898,20 @@ export function useCdkPreflight(options: PreflightOptions): PreflightResult { }); } + // Set up payment resources (before CDK synth so ARNs are in deployed state) + const paymentOkIdentity = await runPaymentPreDeploy({ + projectSpec: context.projectSpec, + awsTargets: context.awsTargets, + runtimeCredentials: runtimeCredentials ?? undefined, + logger, + setSteps, + updateStepByLabel, + setPhase, + isRunningRef, + setAllCredentials, + }); + if (!paymentOkIdentity) return; + // Clear runtime credentials setRuntimeCredentials(null); diff --git a/src/cli/tui/hooks/useRemove.ts b/src/cli/tui/hooks/useRemove.ts index 9400ea2ad..d553686cf 100644 --- a/src/cli/tui/hooks/useRemove.ts +++ b/src/cli/tui/hooks/useRemove.ts @@ -16,6 +16,8 @@ import { gatewayTargetPrimitive, memoryPrimitive, onlineEvalConfigPrimitive, + paymentConnectorPrimitive, + paymentManagerPrimitive, policyEnginePrimitive, policyPrimitive, runtimeEndpointPrimitive, @@ -184,6 +186,16 @@ export function useRemovableRuntimeEndpoints() { return { endpoints, ...rest }; } +export function useRemovablePaymentManagers() { + const { items: paymentManagers, ...rest } = useRemovableResources(() => paymentManagerPrimitive.getRemovable()); + return { paymentManagers, ...rest }; +} + +export function useRemovablePaymentConnectors() { + const { items: paymentConnectors, ...rest } = useRemovableResources(() => paymentConnectorPrimitive.getRemovable()); + return { paymentConnectors, ...rest }; +} + // ============================================================================ // Preview Hook // ============================================================================ diff --git a/src/cli/tui/screens/add/AddFlow.tsx b/src/cli/tui/screens/add/AddFlow.tsx index eef7f4db2..4c10807df 100644 --- a/src/cli/tui/screens/add/AddFlow.tsx +++ b/src/cli/tui/screens/add/AddFlow.tsx @@ -14,6 +14,7 @@ import { AddIdentityFlow } from '../identity'; import { AddGatewayFlow, AddGatewayTargetFlow } from '../mcp'; import { AddMemoryFlow } from '../memory/AddMemoryFlow'; import { AddOnlineEvalFlow } from '../online-eval'; +import { AddPaymentFlow } from '../payment'; import { AddPolicyFlow } from '../policy'; import { AddRuntimeEndpointFlow } from '../runtime-endpoint'; import type { AddResourceType } from './AddScreen'; @@ -36,6 +37,7 @@ type FlowState = | { name: 'config-bundle-wizard' } | { name: 'ab-test-wizard' } | { name: 'runtime-endpoint-wizard' } + | { name: 'payment-wizard' } | { name: 'agent-create-success'; agentName: string; @@ -191,6 +193,8 @@ function getInitialFlowState(resource?: AddResourceType): FlowState { return { name: 'config-bundle-wizard' }; case 'ab-test': return { name: 'ab-test-wizard' }; + case 'payment': + return { name: 'payment-wizard' }; default: return { name: 'select' }; } @@ -247,6 +251,9 @@ export function AddFlow(props: AddFlowProps) { case 'runtime-endpoint': setFlow({ name: 'runtime-endpoint-wizard' }); break; + case 'payment': + setFlow({ name: 'payment-wizard' }); + break; } }, []); @@ -518,6 +525,19 @@ export function AddFlow(props: AddFlowProps) { ); } + // Payment wizard + if (flow.name === 'payment-wizard') { + return ( + setFlow({ name: 'select' })} + onDev={props.onDev} + onDeploy={props.onDeploy} + /> + ); + } + return ( ({ diff --git a/src/cli/tui/screens/deploy/useDeployFlow.ts b/src/cli/tui/screens/deploy/useDeployFlow.ts index e65aa77f5..ea4c32d58 100644 --- a/src/cli/tui/screens/deploy/useDeployFlow.ts +++ b/src/cli/tui/screens/deploy/useDeployFlow.ts @@ -8,13 +8,18 @@ import { parseGatewayOutputs, parseMemoryOutputs, parseOnlineEvalOutputs, + parsePaymentOutputs, parsePolicyEngineOutputs, parsePolicyOutputs, } from '../../../cloudformation'; import { DEFAULT_DEPLOY_ATTRS, computeDeployAttrs } from '../../../commands/deploy/utils.js'; import { getErrorMessage, isChangesetInProgressError, isExpiredTokenError } from '../../../errors'; import { ExecLogger } from '../../../logging'; -import { performStackTeardown, setupTransactionSearch } from '../../../operations/deploy'; +import { + cleanupPaymentCredentialProviders, + performStackTeardown, + setupTransactionSearch, +} from '../../../operations/deploy'; import { getGatewayTargetStatuses } from '../../../operations/deploy/gateway-status'; import { deleteOrphanedABTests, setupABTests } from '../../../operations/deploy/post-deploy-ab-tests'; import { @@ -312,6 +317,30 @@ export function useDeployFlow(options: DeployFlowOptions = {}): DeployFlowState // Expose outputs to UI setStackOutputs(outputs); + // Parse payment outputs from CFN stack + const paymentSpecs = (ctx.projectSpec.payments ?? []).map( + (p: { + name: string; + authorizerType?: 'AWS_IAM' | 'CUSTOM_JWT'; + autoPayment?: boolean; + paymentToolAllowlist?: string[]; + networkPreferences?: string[]; + connectors: { name: string; credentialName: string }[]; + }) => ({ + name: p.name, + authorizerType: p.authorizerType, + autoPayment: p.autoPayment, + paymentToolAllowlist: p.paymentToolAllowlist, + networkPreferences: p.networkPreferences, + connectors: p.connectors.map(c => ({ + name: c.name, + credentialProviderArn: allCredentials[c.credentialName]?.credentialProviderArn ?? '', + credentialProviderName: c.credentialName, + })), + }) + ); + const payments = paymentSpecs.length > 0 ? parsePaymentOutputs(outputs, paymentSpecs) : undefined; + const existingState = await configIO.readDeployedState().catch(() => undefined); let deployedState = buildDeployedState({ targetName: target.name, @@ -326,6 +355,7 @@ export function useDeployFlow(options: DeployFlowOptions = {}): DeployFlowState credentials: Object.keys(allCredentials).length > 0 ? allCredentials : undefined, policyEngines, policies, + payments, }); await configIO.writeDeployedState(deployedState); @@ -622,9 +652,21 @@ export function useDeployFlow(options: DeployFlowOptions = {}): DeployFlowState await cdkToolkitWrapper.deploy(); if (context?.isTeardownDeploy) { - // After deploying the empty spec, destroy the stack entirely + // Clean up imperative payment credential providers before stack teardown const targetName = context.awsTargets[0]?.name; if (targetName) { + try { + const configIO = new ConfigIO(); + const deployedState = await configIO.readDeployedState(); + const existingPayments = deployedState?.targets?.[targetName]?.resources?.payments; + if (existingPayments && Object.keys(existingPayments).length > 0) { + const target = context.awsTargets[0]!; + await cleanupPaymentCredentialProviders({ region: target.region, payments: existingPayments }); + } + } catch { + // Best-effort: continue with teardown even if credential cleanup fails + } + const teardown = await performStackTeardown(targetName); if (!teardown.success) { throw new Error(`Stack teardown failed: ${teardown.error.message}`); diff --git a/src/cli/tui/screens/payment/AddPaymentConnectorScreen.tsx b/src/cli/tui/screens/payment/AddPaymentConnectorScreen.tsx new file mode 100644 index 000000000..a2e8bcde0 --- /dev/null +++ b/src/cli/tui/screens/payment/AddPaymentConnectorScreen.tsx @@ -0,0 +1,279 @@ +import type { PaymentProvider } from '../../../../schema'; +import { PaymentConnectorNameSchema } from '../../../../schema'; +import { ConfirmReview, Panel, Screen, SecretInput, StepIndicator, TextInput, WizardSelect } from '../../components'; +import type { SelectableItem } from '../../components'; +import { HELP_TEXT } from '../../constants'; +import { useListNavigation } from '../../hooks'; +import { generateUniqueName } from '../../utils'; +import type { AddPaymentConnectorConfig } from './types'; +import { CONNECTOR_STEP_LABELS, PAYMENT_PROVIDER_OPTIONS } from './types'; +import { useAddPaymentConnectorWizard } from './useAddPaymentWizard'; +import React, { useMemo } from 'react'; + +interface AddPaymentConnectorScreenProps { + onComplete: (config: AddPaymentConnectorConfig) => void; + onExit: () => void; + existingManagerNames: string[]; + existingConnectorNames: string[]; + preSelectedManager?: string; + headerContent?: React.ReactNode; + /** When true, skip the confirm step and call onComplete after connector name */ + skipConfirm?: boolean; + /** Called when user selects a manager (for parent to refresh connector names) */ + onManagerSelected?: (managerName: string) => void; +} + +export function AddPaymentConnectorScreen({ + onComplete, + onExit, + existingManagerNames, + existingConnectorNames, + preSelectedManager, + headerContent: externalHeader, + skipConfirm = false, + onManagerSelected, +}: AddPaymentConnectorScreenProps) { + const wizard = useAddPaymentConnectorWizard(preSelectedManager); + + const managerItems: SelectableItem[] = useMemo( + () => + existingManagerNames.map(name => ({ + id: name, + title: name, + description: 'Payment manager', + })), + [existingManagerNames] + ); + + const providerItems: SelectableItem[] = useMemo( + () => PAYMENT_PROVIDER_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), + [] + ); + + const isManagerSelectStep = wizard.step === 'manager-select'; + const isProviderStep = wizard.step === 'provider-select'; + const isApiKeyIdStep = wizard.step === 'api-key-id'; + const isApiKeySecretStep = wizard.step === 'api-key-secret'; + const isWalletSecretStep = wizard.step === 'wallet-secret'; + const isAppIdStep = wizard.step === 'app-id'; + const isAppSecretStep = wizard.step === 'app-secret'; + const isAuthorizationPrivateKeyStep = wizard.step === 'authorization-private-key'; + const isAuthorizationIdStep = wizard.step === 'authorization-id'; + const isConnectorNameStep = wizard.step === 'connector-name'; + const isConfirmStep = wizard.step === 'confirm'; + + const managerNav = useListNavigation({ + items: managerItems, + onSelect: item => { + wizard.setManagerName(item.id); + onManagerSelected?.(item.id); + }, + onExit: () => onExit(), + isActive: isManagerSelectStep, + }); + + const providerNav = useListNavigation({ + items: providerItems, + onSelect: item => wizard.setProvider(item.id as PaymentProvider), + onExit: () => { + if (wizard.currentIndex === 0) { + onExit(); + } else { + wizard.goBack(); + } + }, + isActive: isProviderStep, + }); + + useListNavigation({ + items: [{ id: 'confirm', title: 'Confirm' }], + onSelect: () => onComplete(wizard.config), + onExit: () => wizard.goBack(), + isActive: isConfirmStep, + }); + + const helpText = + isManagerSelectStep || isProviderStep + ? HELP_TEXT.NAVIGATE_SELECT + : isConfirmStep + ? HELP_TEXT.CONFIRM_CANCEL + : HELP_TEXT.TEXT_INPUT; + + const headerContent = externalHeader ?? ( + + ); + + const defaultConnectorName = generateUniqueName( + wizard.config.provider === 'StripePrivy' ? 'MyStripePrivyConnector' : 'MyCdpConnector', + existingConnectorNames + ); + + const isFirstStep = wizard.currentIndex === 0; + const goBackOrExit = isFirstStep ? onExit : () => wizard.goBack(); + + return ( + + + {isManagerSelectStep && ( + + )} + + {isProviderStep && ( + + )} + + {isApiKeyIdStep && ( + value.trim().length > 0 || 'API Key ID is required'} + revealChars={4} + /> + )} + + {isApiKeySecretStep && ( + value.trim().length > 0 || 'API Key Secret is required'} + revealChars={4} + /> + )} + + {isWalletSecretStep && ( + value.trim().length > 0 || 'Wallet Secret is required'} + revealChars={4} + /> + )} + + {isAppIdStep && ( + value.trim().length > 0 || 'App ID is required'} + revealChars={4} + /> + )} + + {isAppSecretStep && ( + value.trim().length > 0 || 'App Secret is required'} + revealChars={4} + /> + )} + + {isAuthorizationPrivateKeyStep && ( + value.trim().length > 0 || 'Authorization Private Key is required'} + revealChars={4} + /> + )} + + {isAuthorizationIdStep && ( + value.trim().length > 0 || 'Authorization ID is required'} + revealChars={4} + /> + )} + + {isConnectorNameStep && ( + { + if (skipConfirm) { + onComplete({ ...wizard.config, connectorName: name }); + } else { + wizard.setConnectorName(name); + } + }} + onCancel={goBackOrExit} + schema={PaymentConnectorNameSchema} + customValidation={value => + !existingConnectorNames.includes(value) || 'Connector name already exists in this manager' + } + /> + )} + + {isConfirmStep && ( + 8 ? '****' + wizard.config.appId.slice(-4) : '••••••••' : '', + }, + { + label: 'App Secret', + value: wizard.config.appSecret ? wizard.config.appSecret.length > 8 ? '****' + wizard.config.appSecret.slice(-4) : '••••••••' : '', + }, + { + label: 'Authorization Private Key', + value: wizard.config.authorizationPrivateKey + ? wizard.config.authorizationPrivateKey.length > 8 ? '****' + wizard.config.authorizationPrivateKey.slice(-4) : '••••••••' + : '', + }, + { + label: 'Authorization ID', + value: wizard.config.authorizationId ? wizard.config.authorizationId.length > 8 ? '****' + wizard.config.authorizationId.slice(-4) : '••••••••' : '', + }, + ] + : [ + { + label: 'API Key ID', + value: wizard.config.apiKeyId ? wizard.config.apiKeyId.length > 8 ? '****' + wizard.config.apiKeyId.slice(-4) : '••••••••' : '', + }, + { + label: 'API Key Secret', + value: wizard.config.apiKeySecret ? wizard.config.apiKeySecret.length > 8 ? '****' + wizard.config.apiKeySecret.slice(-4) : '••••••••' : '', + }, + { + label: 'Wallet Secret', + value: wizard.config.walletSecret ? wizard.config.walletSecret.length > 8 ? '****' + wizard.config.walletSecret.slice(-4) : '••••••••' : '', + }, + ]), + ]} + /> + )} + + + ); +} diff --git a/src/cli/tui/screens/payment/AddPaymentFlow.tsx b/src/cli/tui/screens/payment/AddPaymentFlow.tsx new file mode 100644 index 000000000..99650a2f5 --- /dev/null +++ b/src/cli/tui/screens/payment/AddPaymentFlow.tsx @@ -0,0 +1,471 @@ +import { paymentManagerPrimitive } from '../../../primitives/registry'; +import { ConfirmReview, ErrorPrompt, Panel, Screen, SelectScreen } from '../../components'; +import type { SelectableItem } from '../../components'; +import { AddSuccessScreen } from '../add/AddSuccessScreen'; +import { AddPaymentConnectorScreen } from './AddPaymentConnectorScreen'; +import { AddPaymentManagerScreen } from './AddPaymentManagerScreen'; +import type { AddPaymentConnectorConfig, AddPaymentManagerConfig } from './types'; +import { useCreatePayment, useCreatePaymentConnector, useExistingConnectorNames } from './useCreatePayment'; +import { Box, Text, useInput } from 'ink'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; + +type FlowState = + | { name: 'loading' } + | { name: 'select' } + | { name: 'manager-wizard' } + | { name: 'connector-prompt'; managerConfig: AddPaymentManagerConfig } + | { name: 'connector-wizard-unified'; managerConfig: AddPaymentManagerConfig } + | { name: 'confirm'; managerConfig: AddPaymentManagerConfig; connectorConfig?: AddPaymentConnectorConfig } + | { name: 'connector-wizard'; preSelectedManager?: string } + | { name: 'success'; message: string } + | { name: 'error'; message: string }; + +interface AddPaymentFlowProps { + isInteractive?: boolean; + onExit: () => void; + onBack: () => void; + onDev?: () => void; + onDeploy?: () => void; +} + +export function AddPaymentFlow({ isInteractive = true, onExit, onBack, onDev, onDeploy }: AddPaymentFlowProps) { + const [flow, setFlow] = useState({ name: 'loading' }); + const [managerNames, setManagerNames] = useState([]); + const { createPayment, reset: resetCreate } = useCreatePayment(); + const { createConnector, reset: resetConnector } = useCreatePaymentConnector(); + const [connectorManagerName, setConnectorManagerName] = useState(undefined); + const { names: existingConnectorNames, refresh: refreshConnectorNames } = + useExistingConnectorNames(connectorManagerName); + const confirmHandlerRef = useRef<(() => void) | null>(null); + const isSubmittingRef = useRef(false); + + useInput( + (_input, key) => { + if (key.return && flow.name === 'confirm' && confirmHandlerRef.current && !isSubmittingRef.current) { + isSubmittingRef.current = true; + confirmHandlerRef.current(); + } + }, + { isActive: flow.name === 'confirm' } + ); + + useEffect(() => { + if (flow.name !== 'confirm') confirmHandlerRef.current = null; + }, [flow]); + + // Load existing managers from disk on mount — always show selection screen + useEffect(() => { + let cancelled = false; + void paymentManagerPrimitive + .getExistingManagers() + .then(names => { + if (cancelled) return; + setManagerNames(names); + setFlow({ name: 'select' }); + }) + .catch(() => { + if (cancelled) return; + setManagerNames([]); + setFlow({ name: 'select' }); + }); + return () => { + cancelled = true; + }; + }, []); + + // In non-interactive mode, exit after success + useEffect(() => { + if (!isInteractive && flow.name === 'success') { + onExit(); + } + }, [isInteractive, flow.name, onExit]); + + const buildSelectItems = useCallback((): SelectableItem[] => { + return [ + { + id: '__add_manager__', + title: 'Add a payment manager', + description: 'Create a new payment manager with authorization config', + }, + { + id: '__add_connector__', + title: 'Add a payment connector', + description: 'Link payment provider credentials to an existing manager', + }, + ]; + }, []); + + const handleSelectAction = useCallback( + (item: SelectableItem) => { + if (item.id === '__add_manager__') { + setFlow({ name: 'manager-wizard' }); + } else if (item.id === '__add_connector__') { + if (managerNames.length === 0) { + setFlow({ name: 'error', message: 'No payment managers exist. Create a manager first.' }); + } else if (managerNames.length === 1) { + // Only one manager, pre-select it + setConnectorManagerName(managerNames[0]); + void refreshConnectorNames(managerNames[0]); + setFlow({ name: 'connector-wizard', preSelectedManager: managerNames[0] }); + } else { + setFlow({ name: 'connector-wizard' }); + } + } + }, + [managerNames, refreshConnectorNames] + ); + + const handleManagerComplete = useCallback((config: AddPaymentManagerConfig) => { + setFlow({ name: 'connector-prompt', managerConfig: config }); + }, []); + + const handleConnectorComplete = useCallback( + (config: AddPaymentConnectorConfig) => { + const baseOptions = { + manager: config.managerName, + name: config.connectorName, + provider: config.provider, + } as const; + + const connectorOptions = + config.provider === 'StripePrivy' + ? { + ...baseOptions, + provider: 'StripePrivy' as const, + appId: config.appId, + appSecret: config.appSecret, + authorizationPrivateKey: config.authorizationPrivateKey, + authorizationId: config.authorizationId, + } + : { + ...baseOptions, + provider: 'CoinbaseCDP' as const, + apiKeyId: config.apiKeyId, + apiKeySecret: config.apiKeySecret, + walletSecret: config.walletSecret, + }; + + setFlow({ name: 'loading' }); + void createConnector(connectorOptions) + .then(result => { + if (result.ok) { + setFlow({ name: 'success', message: `Added payment connector: ${result.connectorName}` }); + } else { + setFlow({ name: 'error', message: result.error }); + } + }) + .catch(err => { + setFlow({ name: 'error', message: err instanceof Error ? err.message : 'Unexpected error' }); + }); + }, + [createConnector] + ); + + // Loading + if (flow.name === 'loading') { + return ( + + Loading... + + ); + } + + // Select action: add manager or add connector + if (flow.name === 'select') { + return ( + handleSelectAction(item)} + onExit={onBack} + /> + ); + } + + // Manager wizard + if (flow.name === 'manager-wizard') { + return ( + { + if (managerNames.length === 0) { + onBack(); + } else { + setFlow({ name: 'select' }); + } + }} + /> + ); + } + + // After manager config collected, ask about connector + if (flow.name === 'connector-prompt') { + const connectorChoiceItems = [ + { + id: 'add-connector', + title: 'Add a payment connector', + description: 'Link CoinbaseCDP or StripePrivy credentials', + }, + { id: 'skip', title: 'Skip for now' }, + ]; + return ( + { + if (item.id === 'add-connector') { + setFlow({ name: 'connector-wizard-unified', managerConfig: flow.managerConfig }); + } else { + setFlow({ name: 'confirm', managerConfig: flow.managerConfig }); + } + }} + onExit={() => setFlow({ name: 'manager-wizard' })} + /> + ); + } + + // Connector wizard within the unified manager flow (no confirm on this screen) + if (flow.name === 'connector-wizard-unified') { + return ( + { + setFlow({ name: 'confirm', managerConfig: flow.managerConfig, connectorConfig }); + }} + onExit={() => setFlow({ name: 'connector-prompt', managerConfig: flow.managerConfig })} + skipConfirm + /> + ); + } + + // Unified confirm screen — shows manager + optional connector, creates on Enter + if (flow.name === 'confirm') { + const managerFields = [ + { label: 'Auth Type', value: flow.managerConfig.authorizerType }, + { label: 'Manager Name', value: flow.managerConfig.managerName }, + { label: 'Pattern', value: flow.managerConfig.pattern }, + { label: 'Auto Payment', value: flow.managerConfig.autoPayment ? 'Enabled' : 'Disabled' }, + { label: 'Default Spend Limit', value: `$${flow.managerConfig.defaultSpendLimit}` }, + ...(flow.managerConfig.paymentToolAllowlist + ? [{ label: 'Tool Allowlist', value: flow.managerConfig.paymentToolAllowlist }] + : []), + ...(flow.managerConfig.networkPreferences + ? [{ label: 'Network Preferences', value: flow.managerConfig.networkPreferences }] + : []), + ]; + + const connectorFields = flow.connectorConfig + ? [ + { label: 'Connector Name', value: flow.connectorConfig.connectorName }, + { label: 'Provider', value: flow.connectorConfig.provider }, + ...(flow.connectorConfig.provider === 'StripePrivy' + ? [ + { + label: 'App ID', + value: + flow.connectorConfig.appId.length > 8 ? '****' + flow.connectorConfig.appId.slice(-4) : '••••••••', + }, + { + label: 'App Secret', + value: + flow.connectorConfig.appSecret.length > 8 + ? '****' + flow.connectorConfig.appSecret.slice(-4) + : '••••••••', + }, + { + label: 'Auth Key', + value: + flow.connectorConfig.authorizationPrivateKey.length > 8 + ? '****' + flow.connectorConfig.authorizationPrivateKey.slice(-4) + : '••••••••', + }, + { + label: 'Auth ID', + value: + flow.connectorConfig.authorizationId.length > 8 + ? '****' + flow.connectorConfig.authorizationId.slice(-4) + : '••••••••', + }, + ] + : [ + { + label: 'API Key ID', + value: + flow.connectorConfig.apiKeyId.length > 8 + ? '****' + flow.connectorConfig.apiKeyId.slice(-4) + : '••••••••', + }, + { + label: 'API Key Secret', + value: + flow.connectorConfig.apiKeySecret.length > 8 + ? '****' + flow.connectorConfig.apiKeySecret.slice(-4) + : '••••••••', + }, + { + label: 'Wallet Secret', + value: + flow.connectorConfig.walletSecret.length > 8 + ? '****' + flow.connectorConfig.walletSecret.slice(-4) + : '••••••••', + }, + ]), + ] + : []; + + const warningFields = !flow.connectorConfig + ? [{ label: '⚠ Warning', value: 'No connector — deploy will fail until you add one' }] + : []; + + const allFields = [...managerFields, ...connectorFields, ...warningFields]; + + const handleConfirmSubmit = async () => { + const mgrConfig = flow.managerConfig; + const parseList = (val: string): string[] | undefined => { + const items = val + .split(',') + .map(s => s.trim()) + .filter(Boolean); + return items.length > 0 ? items : undefined; + }; + + // Create manager + const mgrResult = await createPayment({ + name: mgrConfig.managerName, + authorizerType: mgrConfig.authorizerType, + discoveryUrl: mgrConfig.authorizerType === 'CUSTOM_JWT' ? mgrConfig.discoveryUrl : undefined, + allowedClients: mgrConfig.authorizerType === 'CUSTOM_JWT' ? parseList(mgrConfig.allowedClients) : undefined, + allowedAudience: mgrConfig.authorizerType === 'CUSTOM_JWT' ? parseList(mgrConfig.allowedAudience) : undefined, + allowedScopes: mgrConfig.authorizerType === 'CUSTOM_JWT' ? parseList(mgrConfig.allowedScopes) : undefined, + pattern: mgrConfig.pattern, + autoPayment: mgrConfig.autoPayment, + defaultSpendLimit: mgrConfig.defaultSpendLimit, + paymentToolAllowlist: mgrConfig.paymentToolAllowlist ? parseList(mgrConfig.paymentToolAllowlist) : undefined, + networkPreferences: mgrConfig.networkPreferences ? parseList(mgrConfig.networkPreferences) : undefined, + }); + + if (!mgrResult.ok) { + isSubmittingRef.current = false; + setFlow({ name: 'error', message: mgrResult.error }); + return; + } + + setManagerNames(prev => [...prev, mgrConfig.managerName]); + + // Create connector if provided + if (flow.connectorConfig) { + const connConfig = flow.connectorConfig; + const baseOptions = { + manager: mgrConfig.managerName, + name: connConfig.connectorName, + provider: connConfig.provider, + } as const; + const connectorOptions = + connConfig.provider === 'StripePrivy' + ? { + ...baseOptions, + provider: 'StripePrivy' as const, + appId: connConfig.appId, + appSecret: connConfig.appSecret, + authorizationPrivateKey: connConfig.authorizationPrivateKey, + authorizationId: connConfig.authorizationId, + } + : { + ...baseOptions, + provider: 'CoinbaseCDP' as const, + apiKeyId: connConfig.apiKeyId, + apiKeySecret: connConfig.apiKeySecret, + walletSecret: connConfig.walletSecret, + }; + + const connResult = await createConnector(connectorOptions); + if (!connResult.ok) { + isSubmittingRef.current = false; + setFlow({ + name: 'error', + message: `Manager "${mgrConfig.managerName}" was created, but connector failed: ${connResult.error}\n\nUse "Add a payment connector" to retry adding the connector.`, + }); + return; + } + } + + isSubmittingRef.current = false; + const msg = flow.connectorConfig + ? `Payment manager "${mgrConfig.managerName}" and connector "${flow.connectorConfig.connectorName}" created` + : `Payment manager "${mgrConfig.managerName}" created`; + setFlow({ name: 'success', message: msg }); + }; + + // eslint-disable-next-line react-hooks/refs -- intentional: handler must close over current flow state + confirmHandlerRef.current = () => void handleConfirmSubmit(); + + return ( + setFlow({ name: 'connector-prompt', managerConfig: flow.managerConfig })} + helpText="Enter confirm · Esc back · Ctrl+C quit" + > + + + + + ); + } + + // Connector wizard + if (flow.name === 'connector-wizard') { + return ( + { + setConnectorManagerName(name); + void refreshConnectorNames(name); + }} + onExit={() => { + resetConnector(); + setFlow({ name: 'select' }); + }} + /> + ); + } + + // Unified success screen + if (flow.name === 'success') { + return ( + + ); + } + + // Error + return ( + { + resetCreate(); + resetConnector(); + if (managerNames.length === 0) { + setFlow({ name: 'manager-wizard' }); + } else { + setFlow({ name: 'select' }); + } + }} + onExit={onExit} + /> + ); +} diff --git a/src/cli/tui/screens/payment/AddPaymentManagerScreen.tsx b/src/cli/tui/screens/payment/AddPaymentManagerScreen.tsx new file mode 100644 index 000000000..87a59f83c --- /dev/null +++ b/src/cli/tui/screens/payment/AddPaymentManagerScreen.tsx @@ -0,0 +1,330 @@ +import type { PaymentAuthorizerType, PaymentPattern } from '../../../../schema'; +import { PaymentManagerNameSchema } from '../../../../schema'; +import { Panel, Screen, StepIndicator, TextInput, WizardSelect } from '../../components'; +import type { SelectableItem } from '../../components'; +import { HELP_TEXT } from '../../constants'; +import { useListNavigation, useMultiSelectNavigation } from '../../hooks'; +import { generateUniqueName } from '../../utils'; +import type { AddPaymentManagerConfig } from './types'; +import { AUTH_TYPE_OPTIONS, AUTO_PAYMENT_ITEM_ID, MANAGER_STEP_LABELS, NETWORK_PREFS_ITEM_ID, PAYMENT_PATTERN_OPTIONS, TOOL_ALLOWLIST_ITEM_ID } from './types'; +import { useAddPaymentManagerWizard } from './useAddPaymentWizard'; +import { Box, Text } from 'ink'; +import React, { useMemo, useRef, useState } from 'react'; + +interface AddPaymentManagerScreenProps { + onComplete: (config: AddPaymentManagerConfig) => void; + onExit: () => void; + existingManagerNames: string[]; + headerContent?: React.ReactNode; +} + +export function AddPaymentManagerScreen({ + onComplete, + onExit, + existingManagerNames, + headerContent: externalHeader, +}: AddPaymentManagerScreenProps) { + const wizard = useAddPaymentManagerWizard(); + + const authTypeItems: SelectableItem[] = useMemo( + () => AUTH_TYPE_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), + [] + ); + + const patternItems: SelectableItem[] = useMemo( + () => PAYMENT_PATTERN_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), + [] + ); + + const BUDGET_ITEM_ID = 'default-budget'; + const advancedConfigItems: SelectableItem[] = useMemo( + () => [ + { id: AUTO_PAYMENT_ITEM_ID, title: 'Auto Payment' }, + { id: BUDGET_ITEM_ID, title: `Edit Default Budget (Current: $${wizard.config.defaultSpendLimit})` }, + { id: TOOL_ALLOWLIST_ITEM_ID, title: 'Edit Tool Allowlist' }, + { id: NETWORK_PREFS_ITEM_ID, title: 'Edit Network Preferences' }, + ], + [wizard.config.defaultSpendLimit] + ); + + const INITIAL_ADVANCED_SELECTED = [AUTO_PAYMENT_ITEM_ID]; + + // Advanced config sub-steps: 0 = multi-select, 1 = budget, 2 = tool allowlist, 3 = network prefs + const [advancedSubStep, setAdvancedSubStep] = useState(0); + const [pendingSubSteps, setPendingSubSteps] = useState([]); + const [prevWizardStep, setPrevWizardStep] = useState(wizard.step); + if (prevWizardStep !== wizard.step) { + setPrevWizardStep(wizard.step); + if (wizard.step === 'advanced-config') { + setAdvancedSubStep(0); + setPendingSubSteps([]); + } + } + + const isAuthTypeStep = wizard.step === 'auth-type'; + const isDiscoveryUrlStep = wizard.step === 'discovery-url'; + const isAllowedClientsStep = wizard.step === 'allowed-clients'; + const isAllowedAudienceStep = wizard.step === 'allowed-audience'; + const isAllowedScopesStep = wizard.step === 'allowed-scopes'; + const isManagerNameStep = wizard.step === 'manager-name'; + const isPatternStep = wizard.step === 'pattern-select'; + const isAdvancedConfigStep = wizard.step === 'advanced-config'; + + const authTypeNav = useListNavigation({ + items: authTypeItems, + onSelect: item => wizard.setAuthorizerType(item.id as PaymentAuthorizerType), + onExit: () => onExit(), + isActive: isAuthTypeStep, + }); + + const patternNav = useListNavigation({ + items: patternItems, + onSelect: item => { + wizard.setPattern(item.id as PaymentPattern); + }, + onExit: () => wizard.goBack(), + isActive: isPatternStep, + }); + + const [autoPaymentEnabled, setAutoPaymentEnabled] = useState(true); + const resolvedValuesRef = useRef({ + autoPayment: true, + defaultSpendLimit: wizard.config.defaultSpendLimit, + paymentToolAllowlist: wizard.config.paymentToolAllowlist, + networkPreferences: wizard.config.networkPreferences, + }); + + const advanceToNextSubStepOrComplete = (queue: number[]) => { + if (queue.length > 0) { + const [next, ...rest] = queue; + setPendingSubSteps(rest); + setAdvancedSubStep(next!); + } else { + onComplete({ + ...wizard.config, + autoPayment: resolvedValuesRef.current.autoPayment, + defaultSpendLimit: resolvedValuesRef.current.defaultSpendLimit, + paymentToolAllowlist: resolvedValuesRef.current.paymentToolAllowlist, + networkPreferences: resolvedValuesRef.current.networkPreferences, + }); + } + }; + + const advancedNav = useMultiSelectNavigation({ + items: advancedConfigItems, + getId: item => item.id, + initialSelectedIds: INITIAL_ADVANCED_SELECTED, + onConfirm: selectedIds => { + const autoEnabled = selectedIds.includes(AUTO_PAYMENT_ITEM_ID); + setAutoPaymentEnabled(autoEnabled); + resolvedValuesRef.current.autoPayment = autoEnabled; + const queue: number[] = []; + if (selectedIds.includes(BUDGET_ITEM_ID)) queue.push(1); + if (selectedIds.includes(TOOL_ALLOWLIST_ITEM_ID)) queue.push(2); + if (selectedIds.includes(NETWORK_PREFS_ITEM_ID)) queue.push(3); + advanceToNextSubStepOrComplete(queue); + }, + onExit: () => wizard.goBack(), + isActive: isAdvancedConfigStep && advancedSubStep === 0, + requireSelection: false, + }); + + const helpText = isAdvancedConfigStep + ? advancedSubStep === 0 + ? 'Space toggle · Enter confirm · Esc back' + : HELP_TEXT.TEXT_INPUT + : isAuthTypeStep || isPatternStep + ? HELP_TEXT.NAVIGATE_SELECT + : HELP_TEXT.TEXT_INPUT; + + const headerContent = externalHeader ?? ( + + ); + + const defaultManagerName = generateUniqueName('MyPaymentManager', existingManagerNames); + + const isFirstStep = wizard.currentIndex === 0; + const goBackOrExit = isFirstStep ? onExit : () => wizard.goBack(); + + return ( + + + {isAuthTypeStep && ( + + )} + + {isDiscoveryUrlStep && ( + { + if (!value.trim()) return 'Discovery URL is required for Custom JWT'; + try { + new URL(value.trim()); + return true; + } catch { + return 'Must be a valid URL'; + } + }} + /> + )} + + {isAllowedClientsStep && ( + + )} + + {isAllowedAudienceStep && ( + + )} + + {isAllowedScopesStep && ( + + )} + + {isManagerNameStep && ( + !existingManagerNames.includes(value) || 'Payment manager name already exists'} + /> + )} + + {isPatternStep && ( + + )} + + {isAdvancedConfigStep && advancedSubStep === 0 && ( + + Advanced Configuration + Space toggle · Enter continue · Esc back + + {advancedConfigItems.map((item, idx) => { + const isCursor = idx === advancedNav.cursorIndex; + const isChecked = advancedNav.selectedIds.has(item.id); + const checkbox = isChecked ? '[✓]' : '[ ]'; + return ( + + + {isCursor ? '❯' : ' '} + {checkbox} + {item.title} + + {isChecked ? 'Enabled' : 'Disabled'} + + ); + })} + + + Toggle items with Space. Press Enter to continue. + + + )} + + {isAdvancedConfigStep && advancedSubStep === 1 && ( + + Advanced Configuration + + Auto Payment: {autoPaymentEnabled ? '✓ Enabled' : '✗ Disabled'} + + + { + const resolved = value || '10.00'; + resolvedValuesRef.current.defaultSpendLimit = resolved; + wizard.setDefaultSpendLimit(value); + advanceToNextSubStepOrComplete(pendingSubSteps); + }} + onCancel={() => setAdvancedSubStep(0)} + customValidation={value => { + if (!value.trim()) return true; + const num = Number(value.trim()); + if (Number.isNaN(num) || num < 0) return 'Must be a valid positive number'; + return true; + }} + /> + + + )} + + {isAdvancedConfigStep && advancedSubStep === 2 && ( + + Advanced Configuration + + { + const resolved = value.trim() || undefined; + resolvedValuesRef.current.paymentToolAllowlist = resolved; + wizard.setPaymentToolAllowlist(resolved); + advanceToNextSubStepOrComplete(pendingSubSteps); + }} + onCancel={() => setAdvancedSubStep(0)} + /> + + + )} + + {isAdvancedConfigStep && advancedSubStep === 3 && ( + + Advanced Configuration + + { + const resolved = value.trim() || undefined; + resolvedValuesRef.current.networkPreferences = resolved; + wizard.setNetworkPreferences(resolved); + advanceToNextSubStepOrComplete(pendingSubSteps); + }} + onCancel={() => setAdvancedSubStep(0)} + /> + + + )} + + + + ); +} diff --git a/src/cli/tui/screens/payment/index.ts b/src/cli/tui/screens/payment/index.ts new file mode 100644 index 000000000..885163eb7 --- /dev/null +++ b/src/cli/tui/screens/payment/index.ts @@ -0,0 +1,15 @@ +export { AddPaymentFlow } from './AddPaymentFlow'; +export { AddPaymentManagerScreen } from './AddPaymentManagerScreen'; +export { AddPaymentConnectorScreen } from './AddPaymentConnectorScreen'; +export type { + AddPaymentManagerConfig, + AddPaymentManagerStep, + AddPaymentConnectorConfig, + AddPaymentConnectorStep, +} from './types'; +export { + useCreatePayment, + useCreatePaymentConnector, + useExistingPaymentNames, + useExistingConnectorNames, +} from './useCreatePayment'; diff --git a/src/cli/tui/screens/payment/types.ts b/src/cli/tui/screens/payment/types.ts new file mode 100644 index 000000000..ab82d76f5 --- /dev/null +++ b/src/cli/tui/screens/payment/types.ts @@ -0,0 +1,123 @@ +import type { PaymentAuthorizerType, PaymentPattern, PaymentProvider } from '../../../../schema'; + +// ───────────────────────────────────────────────────────────────────────────── +// Payment Manager Flow Types +// ───────────────────────────────────────────────────────────────────────────── + +export type AddPaymentManagerStep = + | 'auth-type' + | 'discovery-url' + | 'allowed-clients' + | 'allowed-audience' + | 'allowed-scopes' + | 'manager-name' + | 'pattern-select' + | 'advanced-config' + | 'confirm'; + +export interface AddPaymentManagerConfig { + authorizerType: PaymentAuthorizerType; + discoveryUrl: string; + allowedClients: string; + allowedAudience: string; + allowedScopes: string; + managerName: string; + pattern: PaymentPattern; + autoPayment: boolean; + defaultSpendLimit: string; + paymentToolAllowlist?: string; + networkPreferences?: string; +} + +export const TOOL_ALLOWLIST_ITEM_ID = 'tool-allowlist'; +export const NETWORK_PREFS_ITEM_ID = 'network-preferences'; + +export const MANAGER_STEP_LABELS: Record = { + 'auth-type': 'Auth Type', + 'discovery-url': 'Discovery URL', + 'allowed-clients': 'Clients', + 'allowed-audience': 'Audience', + 'allowed-scopes': 'Scopes', + 'manager-name': 'Name', + 'pattern-select': 'Pattern', + 'advanced-config': 'Advanced', + confirm: 'Confirm', +}; + +// ───────────────────────────────────────────────────────────────────────────── +// Payment Connector Flow Types +// ───────────────────────────────────────────────────────────────────────────── + +export type AddPaymentConnectorStep = + | 'manager-select' + | 'provider-select' + // CoinbaseCDP credentials + | 'api-key-id' + | 'api-key-secret' + | 'wallet-secret' + // StripePrivy credentials + | 'app-id' + | 'app-secret' + | 'authorization-private-key' + | 'authorization-id' + | 'connector-name' + | 'confirm'; + +export interface AddPaymentConnectorConfig { + managerName: string; + provider: PaymentProvider; + // CoinbaseCDP + apiKeyId: string; + apiKeySecret: string; + walletSecret: string; + // StripePrivy + appId: string; + appSecret: string; + authorizationPrivateKey: string; + authorizationId: string; + connectorName: string; +} + +export const CONNECTOR_STEP_LABELS: Record = { + 'manager-select': 'Manager', + 'provider-select': 'Provider', + 'api-key-id': 'API Key ID', + 'api-key-secret': 'API Key Secret', + 'wallet-secret': 'Wallet Secret', + 'app-id': 'App ID', + 'app-secret': 'App Secret', + 'authorization-private-key': 'Auth Key', + 'authorization-id': 'Auth ID', + 'connector-name': 'Name', + confirm: 'Confirm', +}; + +// ───────────────────────────────────────────────────────────────────────────── +// UI Option Constants +// ───────────────────────────────────────────────────────────────────────────── + +export const AUTH_TYPE_OPTIONS = [ + { + id: 'AWS_IAM' as const, + title: 'AWS IAM', + description: 'Use AWS IAM for authorization (default)', + }, + { + id: 'CUSTOM_JWT' as const, + title: 'Custom JWT', + description: 'Use a custom JWT authorizer via OIDC discovery', + }, +] as const; + +export const PAYMENT_PROVIDER_OPTIONS = [ + { id: 'CoinbaseCDP' as const, title: 'Coinbase CDP', description: 'Coinbase Developer Platform wallet credentials' }, + { id: 'StripePrivy' as const, title: 'Stripe + Privy', description: 'Stripe payments via Privy embedded wallets' }, +] as const; + +export const PAYMENT_PATTERN_OPTIONS = [ + { id: 'interceptor' as const, title: 'Interceptor', description: 'Automatically handle x402 payment responses' }, + { id: 'tool-based' as const, title: 'Tool-based', description: 'Expose payment as an agent tool' }, +] as const; + +/** Item ID for the auto payment toggle in the advanced config pane. */ +export const AUTO_PAYMENT_ITEM_ID = 'auto-payment'; diff --git a/src/cli/tui/screens/payment/useAddPaymentWizard.ts b/src/cli/tui/screens/payment/useAddPaymentWizard.ts new file mode 100644 index 000000000..8516c7836 --- /dev/null +++ b/src/cli/tui/screens/payment/useAddPaymentWizard.ts @@ -0,0 +1,344 @@ +import type { PaymentAuthorizerType, PaymentPattern, PaymentProvider } from '../../../../schema'; +import type { + AddPaymentConnectorConfig, + AddPaymentConnectorStep, + AddPaymentManagerConfig, + AddPaymentManagerStep, +} from './types'; +import { useCallback, useMemo, useState } from 'react'; + +// ───────────────────────────────────────────────────────────────────────────── +// Payment Manager Wizard +// ───────────────────────────────────────────────────────────────────────────── + +const BASE_MANAGER_STEPS: AddPaymentManagerStep[] = ['auth-type', 'manager-name', 'pattern-select', 'advanced-config']; +const JWT_MANAGER_STEPS: AddPaymentManagerStep[] = [ + 'auth-type', + 'discovery-url', + 'allowed-clients', + 'allowed-audience', + 'allowed-scopes', + 'manager-name', + 'pattern-select', + 'advanced-config', +]; + +function getDefaultManagerConfig(): AddPaymentManagerConfig { + return { + authorizerType: 'AWS_IAM', + discoveryUrl: '', + allowedClients: '', + allowedAudience: '', + allowedScopes: '', + managerName: '', + pattern: 'interceptor', + autoPayment: true, + defaultSpendLimit: '10.00', + }; +} + +export function useAddPaymentManagerWizard() { + const [config, setConfig] = useState(getDefaultManagerConfig); + const [step, setStep] = useState('auth-type'); + + const steps = useMemo( + () => (config.authorizerType === 'CUSTOM_JWT' ? JWT_MANAGER_STEPS : BASE_MANAGER_STEPS), + [config.authorizerType] + ); + + const currentIndex = steps.indexOf(step); + + const goBack = useCallback(() => { + const prevStep = steps[currentIndex - 1]; + if (prevStep) setStep(prevStep); + }, [currentIndex, steps]); + + const advanceFrom = useCallback( + (currentStep: AddPaymentManagerStep) => { + const idx = steps.indexOf(currentStep); + const next = steps[idx + 1]; + if (next) setStep(next); + }, + [steps] + ); + + const setAuthorizerType = useCallback((authorizerType: PaymentAuthorizerType) => { + setConfig(c => ({ ...c, authorizerType })); + if (authorizerType === 'AWS_IAM') { + // Skip OIDC fields, go straight to name + setStep('manager-name'); + } else { + setStep('discovery-url'); + } + }, []); + + const setDiscoveryUrl = useCallback( + (discoveryUrl: string) => { + setConfig(c => ({ ...c, discoveryUrl })); + advanceFrom('discovery-url'); + }, + [advanceFrom] + ); + + const setAllowedClients = useCallback( + (allowedClients: string) => { + setConfig(c => ({ ...c, allowedClients })); + advanceFrom('allowed-clients'); + }, + [advanceFrom] + ); + + const setAllowedAudience = useCallback( + (allowedAudience: string) => { + setConfig(c => ({ ...c, allowedAudience })); + advanceFrom('allowed-audience'); + }, + [advanceFrom] + ); + + const setAllowedScopes = useCallback( + (allowedScopes: string) => { + setConfig(c => ({ ...c, allowedScopes })); + advanceFrom('allowed-scopes'); + }, + [advanceFrom] + ); + + const setManagerName = useCallback( + (managerName: string) => { + setConfig(c => ({ ...c, managerName })); + advanceFrom('manager-name'); + }, + [advanceFrom] + ); + + const setPattern = useCallback( + (pattern: PaymentPattern) => { + setConfig(c => ({ ...c, pattern })); + advanceFrom('pattern-select'); + }, + [advanceFrom] + ); + + const setAdvancedConfig = useCallback( + (advanced: { autoPayment: boolean; defaultSpendLimit: string }) => { + setConfig(c => ({ ...c, autoPayment: advanced.autoPayment, defaultSpendLimit: advanced.defaultSpendLimit })); + advanceFrom('advanced-config'); + }, + [advanceFrom] + ); + + const setDefaultSpendLimit = useCallback((defaultSpendLimit: string) => { + setConfig(c => ({ ...c, defaultSpendLimit: defaultSpendLimit || '10.00' })); + }, []); + + const setPaymentToolAllowlist = useCallback((paymentToolAllowlist: string | undefined) => { + setConfig(c => ({ ...c, paymentToolAllowlist })); + }, []); + + const setNetworkPreferences = useCallback((networkPreferences: string | undefined) => { + setConfig(c => ({ ...c, networkPreferences })); + }, []); + + const reset = useCallback(() => { + setConfig(getDefaultManagerConfig()); + setStep('auth-type'); + }, []); + + return { + config, + step, + steps, + currentIndex, + goBack, + setAuthorizerType, + setDiscoveryUrl, + setAllowedClients, + setAllowedAudience, + setAllowedScopes, + setManagerName, + setPattern, + setAdvancedConfig, + setDefaultSpendLimit, + setPaymentToolAllowlist, + setNetworkPreferences, + reset, + }; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Payment Connector Wizard +// ───────────────────────────────────────────────────────────────────────────── + +const CDP_CREDENTIAL_STEPS: AddPaymentConnectorStep[] = ['api-key-id', 'api-key-secret', 'wallet-secret']; +const STRIPE_PRIVY_CREDENTIAL_STEPS: AddPaymentConnectorStep[] = [ + 'app-id', + 'app-secret', + 'authorization-private-key', + 'authorization-id', +]; + +function getConnectorStepsForProvider( + provider: PaymentProvider, + needsManagerSelect: boolean +): AddPaymentConnectorStep[] { + const steps: AddPaymentConnectorStep[] = []; + if (needsManagerSelect) steps.push('manager-select'); + steps.push('provider-select'); + if (provider === 'StripePrivy') { + steps.push(...STRIPE_PRIVY_CREDENTIAL_STEPS); + } else { + steps.push(...CDP_CREDENTIAL_STEPS); + } + steps.push('connector-name', 'confirm'); + return steps; +} + +function getDefaultConnectorConfig(preSelectedManager?: string): AddPaymentConnectorConfig { + return { + managerName: preSelectedManager ?? '', + provider: 'CoinbaseCDP', + apiKeyId: '', + apiKeySecret: '', + walletSecret: '', + appId: '', + appSecret: '', + authorizationPrivateKey: '', + authorizationId: '', + connectorName: '', + }; +} + +export function useAddPaymentConnectorWizard(preSelectedManager?: string) { + const needsManagerSelect = !preSelectedManager; + const [config, setConfig] = useState(() => getDefaultConnectorConfig(preSelectedManager)); + + const steps = useMemo( + () => getConnectorStepsForProvider(config.provider, needsManagerSelect), + [config.provider, needsManagerSelect] + ); + const [step, setStep] = useState(steps[0]!); + + const currentIndex = steps.indexOf(step); + + const goBack = useCallback(() => { + const prevStep = steps[currentIndex - 1]; + if (prevStep) setStep(prevStep); + }, [currentIndex, steps]); + + const advanceFrom = useCallback( + (currentStep: AddPaymentConnectorStep) => { + const idx = steps.indexOf(currentStep); + const next = steps[idx + 1]; + if (next) setStep(next); + }, + [steps] + ); + + const setManagerName = useCallback( + (managerName: string) => { + setConfig(c => ({ ...c, managerName })); + advanceFrom('manager-select'); + }, + [advanceFrom] + ); + + const setProvider = useCallback((provider: PaymentProvider) => { + setConfig(c => ({ ...c, provider })); + // After selecting provider, advance to the first credential step + // The steps list will recompute via useMemo on next render + if (provider === 'StripePrivy') { + setStep('app-id'); + } else { + setStep('api-key-id'); + } + }, []); + + const setApiKeyId = useCallback( + (apiKeyId: string) => { + setConfig(c => ({ ...c, apiKeyId })); + advanceFrom('api-key-id'); + }, + [advanceFrom] + ); + + const setApiKeySecret = useCallback( + (apiKeySecret: string) => { + setConfig(c => ({ ...c, apiKeySecret })); + advanceFrom('api-key-secret'); + }, + [advanceFrom] + ); + + const setWalletSecret = useCallback( + (walletSecret: string) => { + setConfig(c => ({ ...c, walletSecret })); + advanceFrom('wallet-secret'); + }, + [advanceFrom] + ); + + const setAppId = useCallback( + (appId: string) => { + setConfig(c => ({ ...c, appId })); + advanceFrom('app-id'); + }, + [advanceFrom] + ); + + const setAppSecret = useCallback( + (appSecret: string) => { + setConfig(c => ({ ...c, appSecret })); + advanceFrom('app-secret'); + }, + [advanceFrom] + ); + + const setAuthorizationPrivateKey = useCallback( + (authorizationPrivateKey: string) => { + setConfig(c => ({ ...c, authorizationPrivateKey })); + advanceFrom('authorization-private-key'); + }, + [advanceFrom] + ); + + const setAuthorizationId = useCallback( + (authorizationId: string) => { + setConfig(c => ({ ...c, authorizationId })); + advanceFrom('authorization-id'); + }, + [advanceFrom] + ); + + const setConnectorName = useCallback( + (connectorName: string) => { + setConfig(c => ({ ...c, connectorName })); + advanceFrom('connector-name'); + }, + [advanceFrom] + ); + + const reset = useCallback(() => { + setConfig(getDefaultConnectorConfig(preSelectedManager)); + setStep(steps[0]!); + }, [preSelectedManager, steps]); + + return { + config, + step, + steps, + currentIndex, + goBack, + setManagerName, + setProvider, + setApiKeyId, + setApiKeySecret, + setWalletSecret, + setAppId, + setAppSecret, + setAuthorizationPrivateKey, + setAuthorizationId, + setConnectorName, + reset, + }; +} diff --git a/src/cli/tui/screens/payment/useCreatePayment.ts b/src/cli/tui/screens/payment/useCreatePayment.ts new file mode 100644 index 000000000..ac59417e2 --- /dev/null +++ b/src/cli/tui/screens/payment/useCreatePayment.ts @@ -0,0 +1,151 @@ +import { ConfigIO } from '../../../../lib'; +import type { PaymentManager } from '../../../../schema'; +import type { AddPaymentConnectorOptions } from '../../../primitives/PaymentConnectorPrimitive'; +import type { AddPaymentManagerOptions } from '../../../primitives/PaymentManagerPrimitive'; +import { paymentConnectorPrimitive, paymentManagerPrimitive } from '../../../primitives/registry'; +import { useCallback, useEffect, useState } from 'react'; + +// ───────────────────────────────────────────────────────────────────────────── +// Manager creation hook +// ───────────────────────────────────────────────────────────────────────────── + +interface CreateStatus { + state: 'idle' | 'loading' | 'success' | 'error'; + error?: string; + result?: T; +} + +export function useCreatePayment() { + const [status, setStatus] = useState>({ state: 'idle' }); + + const create = useCallback(async (config: AddPaymentManagerOptions) => { + setStatus({ state: 'loading' }); + try { + const result = await paymentManagerPrimitive.add(config); + if (!result.success) { + throw result.error ?? new Error('Failed to create payment manager'); + } + const configIO = new ConfigIO(); + const project = await configIO.readProjectSpec(); + const manager = project.payments.find(p => p.name === config.name); + if (!manager) { + throw new Error(`Payment manager "${config.name}" not found after creation`); + } + setStatus({ state: 'success', result: manager }); + return { ok: true as const, result: manager }; + } catch (err) { + const message = err instanceof Error ? err.message : 'Failed to create payment manager.'; + setStatus({ state: 'error', error: message }); + return { ok: false as const, error: message }; + } + }, []); + + const reset = useCallback(() => { + setStatus({ state: 'idle' }); + }, []); + + return { status, createPayment: create, reset }; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Connector creation hook +// ───────────────────────────────────────────────────────────────────────────── + +export function useCreatePaymentConnector() { + const [status, setStatus] = useState>({ + state: 'idle', + }); + + const create = useCallback(async (config: AddPaymentConnectorOptions) => { + setStatus({ state: 'loading' }); + try { + const result = await paymentConnectorPrimitive.add(config); + if (!result.success) { + throw result.error ?? new Error('Failed to create payment connector'); + } + setStatus({ + state: 'success', + result: { connectorName: result.connectorName, managerName: result.managerName }, + }); + return { + ok: true as const, + connectorName: result.connectorName, + managerName: result.managerName, + credentialName: result.credentialName, + }; + } catch (err) { + const message = err instanceof Error ? err.message : 'Failed to create payment connector.'; + setStatus({ state: 'error', error: message }); + return { ok: false as const, error: message }; + } + }, []); + + const reset = useCallback(() => { + setStatus({ state: 'idle' }); + }, []); + + return { status, createConnector: create, reset }; +} + +// ───────────────────────────────────────────────────────────────────────────── +// Existing names hooks +// ───────────────────────────────────────────────────────────────────────────── + +export function useExistingPaymentNames() { + const [names, setNames] = useState([]); + + useEffect(() => { + void paymentManagerPrimitive.getRemovable().then(items => setNames(items.map(i => i.name))); + }, []); + + const refresh = useCallback(async () => { + const items = await paymentManagerPrimitive.getRemovable(); + setNames(items.map(i => i.name)); + }, []); + + return { names, refresh }; +} + +export function useExistingConnectorNames(managerName?: string) { + const [names, setNames] = useState([]); + + useEffect(() => { + if (!managerName) return; + let cancelled = false; + void (async () => { + try { + const configIO = new ConfigIO(); + const project = await configIO.readProjectSpec(); + if (cancelled) return; + const manager = project.payments.find(p => p.name === managerName); + setNames(manager ? manager.connectors.map(c => c.name) : []); + } catch { + if (!cancelled) setNames([]); + } + })(); + return () => { + cancelled = true; + }; + }, [managerName]); + + const refresh = useCallback( + async (mgr?: string) => { + const target = mgr ?? managerName; + if (!target) { + setNames([]); + return; + } + try { + const configIO = new ConfigIO(); + const project = await configIO.readProjectSpec(); + const manager = project.payments.find(p => p.name === target); + setNames(manager ? manager.connectors.map(c => c.name) : []); + } catch { + setNames([]); + } + }, + [managerName] + ); + + return { names, refresh }; +} diff --git a/src/cli/tui/screens/remove/RemoveFlow.tsx b/src/cli/tui/screens/remove/RemoveFlow.tsx index 696107486..f0f8f3b77 100644 --- a/src/cli/tui/screens/remove/RemoveFlow.tsx +++ b/src/cli/tui/screens/remove/RemoveFlow.tsx @@ -1,5 +1,6 @@ import type { RemovableGatewayTarget, RemovalPreview } from '../../../operations/remove'; -import { ErrorPrompt, Panel, Screen } from '../../components'; +import { ErrorPrompt, Panel, Screen, SelectScreen } from '../../components'; +import { paymentManagerPrimitive } from '../../../primitives/registry'; import { useRemovableABTests, useRemovableAgents, @@ -12,6 +13,7 @@ import { useRemovableOnlineEvalConfigs, useRemovablePolicies, useRemovablePolicyEngines, + useRemovablePaymentManagers, useRemovableRuntimeEndpoints, useRemovalPreview, useRemoveABTest, @@ -62,6 +64,7 @@ type FlowState = | { name: 'select-config-bundle' } | { name: 'select-ab-test' } | { name: 'select-runtime-endpoint' } + | { name: 'select-payment' } | { name: 'confirm-agent'; agentName: string; preview: RemovalPreview } | { name: 'confirm-gateway'; gatewayName: string; preview: RemovalPreview } | { name: 'confirm-gateway-target'; tool: RemovableGatewayTarget; preview: RemovalPreview } @@ -74,6 +77,7 @@ type FlowState = | { name: 'confirm-config-bundle'; bundleName: string; preview: RemovalPreview } | { name: 'confirm-ab-test'; testName: string; preview: RemovalPreview } | { name: 'confirm-runtime-endpoint'; endpointName: string; preview: RemovalPreview } + | { name: 'confirm-payment'; managerName: string; preview: RemovalPreview } | { name: 'loading'; message: string } | { name: 'agent-success'; agentName: string; logFilePath?: string } | { name: 'gateway-success'; gatewayName: string; logFilePath?: string } @@ -87,6 +91,7 @@ type FlowState = | { name: 'config-bundle-success'; bundleName: string; logFilePath?: string } | { name: 'ab-test-success'; testName: string; logFilePath?: string } | { name: 'runtime-endpoint-success'; endpointName: string; logFilePath?: string } + | { name: 'payment-success'; managerName: string } | { name: 'remove-all' } | { name: 'error'; message: string }; @@ -111,7 +116,10 @@ interface RemoveFlowProps { | 'policy-engine' | 'policy' | 'config-bundle' - | 'ab-test'; + | 'ab-test' + | 'payment' + | 'payment-manager' + | 'payment-connector'; /** Initial resource name to auto-select (for CLI --name flag) */ initialResourceName?: string; } @@ -151,6 +159,10 @@ export function RemoveFlow({ return { name: 'select-ab-test' }; case 'runtime-endpoint': return { name: 'select-runtime-endpoint' }; + case 'payment': + case 'payment-manager': + case 'payment-connector': + return { name: 'select-payment' }; default: return { name: 'select' }; } @@ -186,6 +198,11 @@ export function RemoveFlow({ isLoading: isLoadingRuntimeEndpoints, refresh: refreshRuntimeEndpoints, } = useRemovableRuntimeEndpoints(); + const { + paymentManagers, + isLoading: isLoadingPayments, + refresh: refreshPayments, + } = useRemovablePaymentManagers(); // Check if any data is still loading const isLoading = @@ -199,7 +216,8 @@ export function RemoveFlow({ isLoadingPolicyEngines || isLoadingPolicies || isLoadingConfigBundles || - isLoadingRuntimeEndpoints; + isLoadingRuntimeEndpoints || + isLoadingPayments; // Preview hook const { @@ -264,6 +282,7 @@ export function RemoveFlow({ 'config-bundle-success', 'ab-test-success', 'runtime-endpoint-success', + 'payment-success', ]; if (successStates.includes(flow.name)) { onExit(); @@ -312,6 +331,9 @@ export function RemoveFlow({ case 'runtime-endpoint': setFlow({ name: 'select-runtime-endpoint' }); break; + case 'payment': + setFlow({ name: 'select-payment' }); + break; case 'all': setFlow({ name: 'remove-all' }); break; @@ -588,6 +610,28 @@ export function RemoveFlow({ [loadRuntimeEndpointPreview, force, removeRuntimeEndpointOp] ); + const handleSelectPaymentManager = useCallback( + async (managerName: string) => { + try { + const preview = await paymentManagerPrimitive.previewRemove(managerName); + if (force) { + setFlow({ name: 'loading', message: `Removing payment manager ${managerName}...` }); + const removeResult = await paymentManagerPrimitive.remove(managerName); + if (removeResult.success) { + setFlow({ name: 'payment-success', managerName }); + } else { + setFlow({ name: 'error', message: removeResult.error?.message ?? 'Failed to remove payment manager' }); + } + } else { + setFlow({ name: 'confirm-payment', managerName, preview }); + } + } catch (err) { + setFlow({ name: 'error', message: err instanceof Error ? err.message : String(err) }); + } + }, + [force] + ); + // Auto-select resource when initialResourceName is provided and data is loaded useEffect(() => { if (!initialResourceName || isLoading || hasTriggeredInitialSelection.current) { @@ -633,6 +677,10 @@ export function RemoveFlow({ case 'runtime-endpoint': void handleSelectRuntimeEndpoint(initialResourceName); break; + case 'payment': + case 'payment-manager': + void handleSelectPaymentManager(initialResourceName); + break; } }, 0); }, [ @@ -650,6 +698,7 @@ export function RemoveFlow({ handleSelectConfigBundle, handleSelectABTest, handleSelectRuntimeEndpoint, + handleSelectPaymentManager, ]); // Confirm handlers - pass preview for logging @@ -888,6 +937,7 @@ export function RemoveFlow({ refreshPolicies(), refreshConfigBundles(), refreshRuntimeEndpoints(), + refreshPayments(), ]); }, [ refreshAgents, @@ -901,6 +951,7 @@ export function RemoveFlow({ refreshPolicies, refreshConfigBundles, refreshRuntimeEndpoints, + refreshPayments, ]); // Select screen - wait for data to load to avoid arrow position issues @@ -924,6 +975,7 @@ export function RemoveFlow({ configBundleCount={configBundles.length} abTestCount={abTests.length} runtimeEndpointCount={runtimeEndpoints.length} + paymentCount={paymentManagers.length} /> ); } @@ -1097,6 +1149,28 @@ export function RemoveFlow({ ); } + if (flow.name === 'select-payment') { + if (isLoading) return null; + if (paymentManagers.length === 0) { + return ( + setFlow({ name: 'select' })}> + + No payment managers to remove. + + + ); + } + const items = paymentManagers.map(m => ({ id: m.name, title: m.name, description: 'Payment manager' })); + return ( + void handleSelectPaymentManager(item.id)} + onExit={() => setFlow({ name: 'select' })} + /> + ); + } + // Confirmation screens if (flow.name === 'confirm-agent') { return ( @@ -1230,6 +1304,27 @@ export function RemoveFlow({ ); } + if (flow.name === 'confirm-payment') { + return ( + { + void (async () => { + setFlow({ name: 'loading', message: `Removing payment manager ${flow.managerName}...` }); + const result = await paymentManagerPrimitive.remove(flow.managerName); + if (result.success) { + setFlow({ name: 'payment-success', managerName: flow.managerName }); + } else { + setFlow({ name: 'error', message: result.error?.message ?? 'Failed to remove payment manager' }); + } + })(); + }} + onCancel={() => setFlow({ name: 'select-payment' })} + /> + ); + } + // Success screens if (flow.name === 'agent-success') { return ( @@ -1423,6 +1518,21 @@ export function RemoveFlow({ ); } + if (flow.name === 'payment-success') { + return ( + { + resetAll(); + void refreshAll().then(() => setFlow({ name: 'select' })); + }} + onExit={onExit} + /> + ); + } + // Remove all screen if (flow.name === 'remove-all') { return ; diff --git a/src/cli/tui/screens/remove/RemoveScreen.tsx b/src/cli/tui/screens/remove/RemoveScreen.tsx index b1178e530..ac6b838e9 100644 --- a/src/cli/tui/screens/remove/RemoveScreen.tsx +++ b/src/cli/tui/screens/remove/RemoveScreen.tsx @@ -10,6 +10,7 @@ const REMOVE_RESOURCES = [ { id: 'online-eval', title: 'Online Eval Config', description: 'Remove an online eval config' }, { id: 'policy-engine', title: 'Policy Engine', description: 'Remove a policy engine' }, { id: 'policy', title: 'Policy', description: 'Remove a policy from a policy engine' }, + { id: 'payment', title: 'Payment', description: 'Remove a payment manager' }, { id: 'gateway', title: 'Gateway', description: 'Remove a gateway' }, { id: 'gateway-target', title: 'Gateway Target', description: 'Remove a gateway target' }, { id: 'config-bundle', title: 'Configuration Bundle [preview]', description: 'Remove a configuration bundle' }, @@ -47,6 +48,8 @@ interface RemoveScreenProps { abTestCount: number; /** Number of runtime endpoints available for removal */ runtimeEndpointCount: number; + /** Number of payment managers available for removal */ + paymentCount: number; } export function RemoveScreen({ @@ -64,6 +67,7 @@ export function RemoveScreen({ configBundleCount, abTestCount, runtimeEndpointCount, + paymentCount, }: RemoveScreenProps) { const items: SelectableItem[] = useMemo(() => { return REMOVE_RESOURCES.map(r => { @@ -143,6 +147,12 @@ export function RemoveScreen({ description = 'No runtime endpoints to remove'; } break; + case 'payment': + if (paymentCount === 0) { + disabled = true; + description = 'No payment managers to remove'; + } + break; case 'all': // 'all' is always available break; @@ -163,6 +173,7 @@ export function RemoveScreen({ configBundleCount, abTestCount, runtimeEndpointCount, + paymentCount, ]); const isDisabled = (item: SelectableItem) => item.disabled ?? false; diff --git a/src/cli/tui/screens/remove/__tests__/RemoveScreen.test.tsx b/src/cli/tui/screens/remove/__tests__/RemoveScreen.test.tsx index ccc59e9da..5ca9dbd6a 100644 --- a/src/cli/tui/screens/remove/__tests__/RemoveScreen.test.tsx +++ b/src/cli/tui/screens/remove/__tests__/RemoveScreen.test.tsx @@ -24,6 +24,7 @@ describe('RemoveScreen', () => { configBundleCount={1} abTestCount={0} runtimeEndpointCount={1} + paymentCount={1} /> ); @@ -57,6 +58,7 @@ describe('RemoveScreen', () => { configBundleCount={0} abTestCount={0} runtimeEndpointCount={0} + paymentCount={0} /> ); @@ -86,6 +88,7 @@ describe('RemoveScreen', () => { configBundleCount={0} abTestCount={2} runtimeEndpointCount={0} + paymentCount={0} /> ); @@ -113,6 +116,7 @@ describe('RemoveScreen', () => { configBundleCount={0} abTestCount={0} runtimeEndpointCount={0} + paymentCount={0} /> ); diff --git a/src/cli/tui/screens/remove/useRemoveFlow.ts b/src/cli/tui/screens/remove/useRemoveFlow.ts index 36062d520..47804a1c2 100644 --- a/src/cli/tui/screens/remove/useRemoveFlow.ts +++ b/src/cli/tui/screens/remove/useRemoveFlow.ts @@ -89,6 +89,15 @@ export function useRemoveFlow({ force, dryRun }: RemoveFlowOptions): RemoveFlowS items.push(`${totalPolicies} polic${totalPolicies > 1 ? 'ies' : 'y'}`); } } + if (projectSpec.payments && projectSpec.payments.length > 0) { + items.push( + `${projectSpec.payments.length} payment manager${projectSpec.payments.length > 1 ? 's' : ''}` + ); + const totalConnectors = projectSpec.payments.reduce((sum, p) => sum + p.connectors.length, 0); + if (totalConnectors > 0) { + items.push(`${totalConnectors} payment connector${totalConnectors > 1 ? 's' : ''}`); + } + } } catch { // Project exists but has issues - still allow reset items.push('AgentCore project (corrupted or incomplete)'); diff --git a/src/lib/utils/env.ts b/src/lib/utils/env.ts index 4fed9989c..f3884e096 100644 --- a/src/lib/utils/env.ts +++ b/src/lib/utils/env.ts @@ -61,3 +61,25 @@ export async function writeEnvFile(updates: Record, configRoot?: export async function setEnvVar(key: string, value: string, configRoot?: string): Promise { await writeEnvFile({ [key]: value }, configRoot); } + +/** + * Remove keys from agentcore/.env.local. + */ +export async function removeEnvVars(keys: string[], configRoot?: string): Promise { + const path = getEnvPath(configRoot); + const current = await readEnvFile(configRoot); + for (const key of keys) { + delete current[key]; + } + const entries = Object.entries(current); + const content = + entries.length > 0 + ? entries + .map( + ([k, v]) => + `${k}="${String(v).replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"` + ) + .join('\n') + '\n' + : ''; + await writeFile(path, content); +} diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 8902fca44..b5d25e2b4 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -1,6 +1,6 @@ export { detectAwsAccount } from './aws-account'; export { SecureCredentials } from './credentials'; -export { getEnvPath, readEnvFile, writeEnvFile, getEnvVar, setEnvVar } from './env'; +export { getEnvPath, readEnvFile, writeEnvFile, getEnvVar, setEnvVar, removeEnvVars } from './env'; export { isWindows } from './platform'; export { runSubprocess, diff --git a/src/schema/schemas/__tests__/payment.test.ts b/src/schema/schemas/__tests__/payment.test.ts new file mode 100644 index 000000000..7cf948375 --- /dev/null +++ b/src/schema/schemas/__tests__/payment.test.ts @@ -0,0 +1,111 @@ +import { PaymentConnectorNameSchema, PaymentManagerNameSchema, PaymentManagerSchema } from '../primitives/payment'; +import { describe, expect, it } from 'vitest'; + +describe('PaymentManagerNameSchema', () => { + describe('length boundaries', () => { + it('accepts exactly 48 characters', () => { + const name = 'A' + 'b'.repeat(47); + expect(name).toHaveLength(48); + expect(PaymentManagerNameSchema.safeParse(name).success).toBe(true); + }); + + it('rejects 49 characters', () => { + const name = 'A' + 'b'.repeat(48); + expect(name).toHaveLength(49); + expect(PaymentManagerNameSchema.safeParse(name).success).toBe(false); + }); + + it('rejects empty string', () => { + expect(PaymentManagerNameSchema.safeParse('').success).toBe(false); + }); + + it('accepts single letter', () => { + expect(PaymentManagerNameSchema.safeParse('A').success).toBe(true); + }); + }); + + describe('format validation', () => { + it('rejects name starting with a digit', () => { + expect(PaymentManagerNameSchema.safeParse('1manager').success).toBe(false); + }); + + it('rejects name starting with an underscore', () => { + expect(PaymentManagerNameSchema.safeParse('_manager').success).toBe(false); + }); + + it('accepts underscores after first character', () => { + expect(PaymentManagerNameSchema.safeParse('my_manager').success).toBe(true); + }); + + it('rejects hyphens', () => { + expect(PaymentManagerNameSchema.safeParse('my-manager').success).toBe(false); + }); + + it('rejects spaces', () => { + expect(PaymentManagerNameSchema.safeParse('my manager').success).toBe(false); + }); + + it('rejects special characters', () => { + expect(PaymentManagerNameSchema.safeParse('mgr@1').success).toBe(false); + expect(PaymentManagerNameSchema.safeParse('mgr.one').success).toBe(false); + }); + }); +}); + +describe('PaymentConnectorNameSchema', () => { + it('accepts exactly 48 characters', () => { + const name = 'C' + 'o'.repeat(47); + expect(PaymentConnectorNameSchema.safeParse(name).success).toBe(true); + }); + + it('rejects 49 characters', () => { + const name = 'C' + 'o'.repeat(48); + expect(PaymentConnectorNameSchema.safeParse(name).success).toBe(false); + }); + + it('rejects hyphens', () => { + expect(PaymentConnectorNameSchema.safeParse('my-connector').success).toBe(false); + }); + + it('rejects name starting with digit', () => { + expect(PaymentConnectorNameSchema.safeParse('9connector').success).toBe(false); + }); +}); + +describe('PaymentManagerSchema', () => { + const validBase = { name: 'testManager', pattern: 'interceptor' as const, connectors: [] }; + + describe('CUSTOM_JWT requires authorizerConfiguration', () => { + it('fails when authorizerConfiguration is missing', () => { + const result = PaymentManagerSchema.safeParse({ ...validBase, authorizerType: 'CUSTOM_JWT' }); + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.issues.some(i => i.path.includes('authorizerConfiguration'))).toBe(true); + } + }); + + it('passes with valid customJWTAuthorizer', () => { + const result = PaymentManagerSchema.safeParse({ + ...validBase, + authorizerType: 'CUSTOM_JWT', + authorizerConfiguration: { + customJWTAuthorizer: { discoveryUrl: 'https://example.com/.well-known/openid-configuration' }, + }, + }); + expect(result.success).toBe(true); + }); + + it('passes with AWS_IAM and no authorizerConfiguration', () => { + const result = PaymentManagerSchema.safeParse({ ...validBase, authorizerType: 'AWS_IAM' }); + expect(result.success).toBe(true); + }); + }); + + describe('autoPayment defaults', () => { + it('accepts explicit false', () => { + const result = PaymentManagerSchema.safeParse({ ...validBase, autoPayment: false }); + expect(result.success).toBe(true); + if (result.success) expect(result.data.autoPayment).toBe(false); + }); + }); +}); diff --git a/src/schema/schemas/agentcore-project.ts b/src/schema/schemas/agentcore-project.ts index b3f4d3d6f..b5f3c6a50 100644 --- a/src/schema/schemas/agentcore-project.ts +++ b/src/schema/schemas/agentcore-project.ts @@ -27,6 +27,15 @@ import { MemoryStrategyTypeSchema, } from './primitives/memory'; import { OnlineEvalConfigSchema } from './primitives/online-eval-config'; +import { + PaymentAuthorizerTypeSchema, + PaymentConnectorNameSchema, + PaymentConnectorSchema, + PaymentManagerNameSchema, + PaymentManagerSchema, + PaymentPatternSchema, + PaymentProviderSchema, +} from './primitives/payment'; import { PolicyEngineSchema } from './primitives/policy'; import { TagsSchema } from './primitives/tags'; import { uniqueBy } from './zod-util'; @@ -73,6 +82,22 @@ export type { ABTestMode, TargetRef, GatewayFilter, PerVariantOnlineEvaluationCo export { ABTestModeSchema, TargetRefSchema, GatewayFilterSchema } from './primitives/ab-test'; export type { HttpGatewayTarget } from './primitives/http-gateway'; export { HttpGatewayTargetSchema } from './primitives/http-gateway'; +export { + PaymentManagerSchema, + PaymentManagerNameSchema, + PaymentConnectorSchema, + PaymentConnectorNameSchema, + PaymentProviderSchema, + PaymentPatternSchema, + PaymentAuthorizerTypeSchema, +}; +export type { + PaymentManager, + PaymentConnector, + PaymentProvider, + PaymentPattern, + PaymentAuthorizerType, +} from './primitives/payment'; // ============================================================================ // ManagedBy Schema @@ -182,7 +207,11 @@ export const CredentialNameSchema = z .max(128, 'Credential name must be 128 characters or less') .regex(/^[a-zA-Z0-9\-_]+$/, 'Must contain only alphanumeric characters, hyphens, and underscores (1-128 chars)'); -export const CredentialTypeSchema = z.enum(['ApiKeyCredentialProvider', 'OAuthCredentialProvider']); +export const CredentialTypeSchema = z.enum([ + 'ApiKeyCredentialProvider', + 'OAuthCredentialProvider', + 'PaymentCredentialProvider', +]); export type CredentialType = z.infer; export const ApiKeyCredentialSchema = z.object({ @@ -209,7 +238,19 @@ export const OAuthCredentialSchema = z.object({ export type OAuthCredential = z.infer; -export const CredentialSchema = z.discriminatedUnion('authorizerType', [ApiKeyCredentialSchema, OAuthCredentialSchema]); +export const PaymentCredentialSchema = z.object({ + authorizerType: z.literal('PaymentCredentialProvider'), + name: CredentialNameSchema, + provider: PaymentProviderSchema, +}); + +export type PaymentCredential = z.infer; + +export const CredentialSchema = z.discriminatedUnion('authorizerType', [ + ApiKeyCredentialSchema, + OAuthCredentialSchema, + PaymentCredentialSchema, +]); export type Credential = z.infer; @@ -368,6 +409,16 @@ export const AgentCoreProjectSpecSchema = z name => `Duplicate HTTP gateway name: ${name}` ) ), + + payments: z + .array(PaymentManagerSchema) + .default([]) + .superRefine( + uniqueBy( + manager => manager.name, + name => `Duplicate payment manager name: ${name}` + ) + ), }) .strict() .superRefine((spec, ctx) => { @@ -459,6 +510,28 @@ export const AgentCoreProjectSpecSchema = z } } } + + // Validate payment connector credential references + for (const payment of spec.payments) { + const paymentIndex = spec.payments.indexOf(payment); + for (const connector of payment.connectors) { + const connectorIndex = payment.connectors.indexOf(connector); + const credential = spec.credentials.find(c => c.name === connector.credentialName); + if (!credential) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Payment connector "${connector.name}" in manager "${payment.name}" references credential "${connector.credentialName}" which does not exist in credentials[]`, + path: ['payments', paymentIndex, 'connectors', connectorIndex, 'credentialName'], + }); + } else if (credential.authorizerType !== 'PaymentCredentialProvider') { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `Payment connector "${connector.name}" in manager "${payment.name}" references credential "${connector.credentialName}" which is a ${credential.authorizerType}, not a PaymentCredentialProvider`, + path: ['payments', paymentIndex, 'connectors', connectorIndex, 'credentialName'], + }); + } + } + } }); export type AgentCoreProjectSpec = z.infer; diff --git a/src/schema/schemas/deployed-state.ts b/src/schema/schemas/deployed-state.ts index a37469799..3a1247959 100644 --- a/src/schema/schemas/deployed-state.ts +++ b/src/schema/schemas/deployed-state.ts @@ -193,11 +193,8 @@ export type ConfigBundleDeployedState = z.infer; +// ============================================================================ +// Payment Connector Deployed State +// ============================================================================ + +export const PaymentConnectorDeployedStateSchema = z.object({ + connectorId: z.string().min(1), + credentialProviderArn: z.string().min(1), + credentialProviderName: z.string().optional(), +}); + +export type PaymentConnectorDeployedState = z.infer; + +// ============================================================================ +// Payment Deployed State +// ============================================================================ + +export const PaymentDeployedStateSchema = z.object({ + managerId: z.string().min(1), + managerArn: z.string().min(1), + connectors: z.record(z.string(), PaymentConnectorDeployedStateSchema).default({}), + processPaymentRoleArn: z.string().min(1), + resourceRetrievalRoleArn: z.string().min(1), + authorizerType: z.enum(['AWS_IAM', 'CUSTOM_JWT']).optional(), + autoPayment: z.boolean().optional(), + paymentToolAllowlist: z.array(z.string()).optional(), + networkPreferences: z.array(z.string()).optional(), +}); + +export type PaymentDeployedState = z.infer; + // ============================================================================ // Deployed Resource State // ============================================================================ @@ -247,6 +274,7 @@ export const DeployedResourceStateSchema = z.object({ policyEngines: z.record(z.string(), PolicyEngineDeployedStateSchema).optional(), policies: z.record(z.string(), PolicyDeployedStateSchema).optional(), runtimeEndpoints: z.record(z.string(), RuntimeEndpointDeployedStateSchema).optional(), + payments: z.record(z.string(), PaymentDeployedStateSchema).optional(), stackName: z.string().optional(), identityKmsKeyArn: z.string().optional(), }); diff --git a/src/schema/schemas/primitives/index.ts b/src/schema/schemas/primitives/index.ts index 38967a181..f37b73c30 100644 --- a/src/schema/schemas/primitives/index.ts +++ b/src/schema/schemas/primitives/index.ts @@ -70,3 +70,20 @@ export { export type { HttpGateway } from './http-gateway'; export { HttpGatewayNameSchema, HttpGatewaySchema } from './http-gateway'; + +export type { + PaymentManager, + PaymentConnector, + PaymentProvider, + PaymentPattern, + PaymentAuthorizerType, +} from './payment'; +export { + PaymentManagerSchema, + PaymentManagerNameSchema, + PaymentConnectorSchema, + PaymentConnectorNameSchema, + PaymentProviderSchema, + PaymentPatternSchema, + PaymentAuthorizerTypeSchema, +} from './payment'; diff --git a/src/schema/schemas/primitives/payment.ts b/src/schema/schemas/primitives/payment.ts new file mode 100644 index 000000000..6ec13ddf3 --- /dev/null +++ b/src/schema/schemas/primitives/payment.ts @@ -0,0 +1,98 @@ +import { z } from 'zod'; + +// ============================================================================ +// Payment Provider Schema +// ============================================================================ + +export const PaymentProviderSchema = z.enum(['CoinbaseCDP', 'StripePrivy']); +export type PaymentProvider = z.infer; + +// ============================================================================ +// Payment Pattern Schema +// ============================================================================ + +export const PaymentPatternSchema = z.enum(['interceptor', 'tool-based']); +export type PaymentPattern = z.infer; + +// ============================================================================ +// Payment Manager Name Schema +// ============================================================================ + +export const PaymentManagerNameSchema = z + .string() + .min(1, 'Payment manager name is required') + .max(48) + .regex( + /^[a-zA-Z][a-zA-Z0-9_]{0,47}$/, + 'Must begin with a letter and contain only alphanumeric characters and underscores (max 48 chars)' + ); + +// ============================================================================ +// Payment Connector Name Schema +// ============================================================================ + +export const PaymentConnectorNameSchema = z + .string() + .min(1, 'Payment connector name is required') + .max(48) + .regex( + /^[a-zA-Z][a-zA-Z0-9_]{0,47}$/, + 'Must begin with a letter and contain only alphanumeric characters and underscores (max 48 chars)' + ); + +// ============================================================================ +// Payment Connector Schema +// ============================================================================ + +export const PaymentConnectorSchema = z.object({ + name: PaymentConnectorNameSchema, + provider: PaymentProviderSchema.default('CoinbaseCDP'), + credentialName: z.string().min(1), +}); + +export type PaymentConnector = z.infer; + +// ============================================================================ +// Payment Manager Schema +// ============================================================================ + +export const PaymentManagerSchema = z + .object({ + name: PaymentManagerNameSchema, + authorizerType: z.enum(['AWS_IAM', 'CUSTOM_JWT']).default('AWS_IAM'), + authorizerConfiguration: z + .object({ + customJWTAuthorizer: z.object({ + discoveryUrl: z.string().url(), + allowedClients: z.array(z.string()).optional(), + allowedAudience: z.array(z.string()).optional(), + allowedScopes: z.array(z.string()).optional(), + }), + }) + .optional(), + pattern: PaymentPatternSchema.default('interceptor'), + connectors: z.array(PaymentConnectorSchema).default([]), + description: z.string().optional(), + autoPayment: z.boolean().optional(), + defaultSpendLimit: z.string().optional(), + paymentToolAllowlist: z.array(z.string()).optional(), + networkPreferences: z.array(z.string()).optional(), + }) + .superRefine((data, ctx) => { + if (data.authorizerType === 'CUSTOM_JWT' && !data.authorizerConfiguration?.customJWTAuthorizer) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'authorizerConfiguration with customJWTAuthorizer is required when authorizerType is CUSTOM_JWT', + path: ['authorizerConfiguration'], + }); + } + }); + +export type PaymentManager = z.infer; + +// ============================================================================ +// Payment Authorizer Type Schema (for CLI parsing) +// ============================================================================ + +export const PaymentAuthorizerTypeSchema = z.enum(['AWS_IAM', 'CUSTOM_JWT']); +export type PaymentAuthorizerType = z.infer;