From 02752dfc8e8ffcf04a7d93ac3157b5007e2274a9 Mon Sep 17 00:00:00 2001 From: Aayush Jain Date: Thu, 16 Apr 2026 02:06:16 +0530 Subject: [PATCH 01/33] feat: add support for openai models --- CHANGELOG.md | 6 ++++++ README.md | 1 + src/models.ts | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c5b52..f132de9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- **OpenAI Support**: Direct integration with OpenAI models via `@ai-sdk/openai` and `OPENAI_API_KEY` + ## [1.0.0] - 2026-03-27 ### Added diff --git a/README.md b/README.md index c253a2c..97e2bc9 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ configure({ | `REDIS_URL` | No | - | Redis connection URL for step caching and global state | | `ANTHROPIC_API_KEY` | Yes | - | Anthropic API key for Claude models | | `GOOGLE_GENERATIVE_AI_API_KEY` | Yes | - | Google API key for Gemini models | +| `OPENAI_API_KEY` | No | - | OpenAI API key for OpenAI models | | `AI_GATEWAY_API_KEY` | If gateway=vercel | - | Vercel AI Gateway API key | | `OPENROUTER_API_KEY` | If gateway=openrouter | - | OpenRouter API key | | `AXIOM_TOKEN` | No | - | Axiom token for OpenTelemetry tracing | diff --git a/src/models.ts b/src/models.ts index daa89a6..79ad807 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1,6 +1,7 @@ import { AIModelError, ConfigurationError } from "./errors"; import { createAnthropic } from "@ai-sdk/anthropic"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; +import { createOpenAI } from "@ai-sdk/openai"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { gateway, type LanguageModel } from "ai"; import { wrapAISDKModel } from "axiom/ai"; @@ -13,6 +14,7 @@ function wrapModel(model: LanguageModel): LanguageModel { let _google: ReturnType | null = null; let _anthropic: ReturnType | null = null; +let _openai: ReturnType | null = null; let _openrouter: ReturnType | null = null; function getGoogleProvider() { @@ -43,6 +45,20 @@ function getAnthropicProvider() { return _anthropic; } +function getOpenAIProvider() { + if (!_openai) { + if (!process.env.OPENAI_API_KEY) { + throw new ConfigurationError( + "OPENAI_API_KEY isn't set. Add it to your environment (for example: export OPENAI_API_KEY=your_key), or use a gateway by calling configure({ ai: { gateway: 'vercel' } }) with AI_GATEWAY_API_KEY, or configure({ ai: { gateway: 'openrouter' } }) with OPENROUTER_API_KEY. See .env.example for reference.", + ); + } + _openai = createOpenAI({ + apiKey: process.env.OPENAI_API_KEY, + }); + } + return _openai; +} + function getOpenRouterProvider() { if (!_openrouter) { if (!process.env.OPENROUTER_API_KEY) { @@ -120,6 +136,8 @@ export function resolveModel(modelId: string): LanguageModel { return wrapModel(getGoogleProvider()(resolveDirectModelName(modelName))); case "anthropic": return wrapModel(getAnthropicProvider()(resolveDirectModelName(modelName))); + case "openai": + return wrapModel(getOpenAIProvider()(resolveDirectModelName(modelName))); default: throw new AIModelError(`Unknown AI provider: ${provider}`); } From c30ba4dc8ca3253ea5d7ff5d263a334bb735c9c1 Mon Sep 17 00:00:00 2001 From: Sung-Heon Date: Tue, 21 Apr 2026 14:49:00 +0900 Subject: [PATCH 02/33] feat: add OpenCode Zen gateway support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `opencodezen` as a new AI gateway option alongside the existing `vercel`, `openrouter`, and `cloudflare` options. Uses @ai-sdk/openai with baseURL https://opencode.ai/zen/v1 (OpenAI-compatible endpoint). Includes model ID aliasing to map canonical provider/model IDs to Zen's naming convention (e.g. anthropic/claude-haiku-4.5 → claude-haiku-4-5). Co-Authored-By: Claude Sonnet 4.6 --- .env.example | 7 ++++++ src/__tests__/config.test.ts | 5 ++++ src/config.ts | 2 +- src/models.ts | 44 ++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 26583e8..cd856d1 100644 --- a/.env.example +++ b/.env.example @@ -25,6 +25,13 @@ GOOGLE_GENERATIVE_AI_API_KEY=AIza... # Required only if ai.gateway is set to "openrouter" in configure() # OPENROUTER_API_KEY=sk-or-... +# ============================================================================= +# Optional: OpenCode Zen +# ============================================================================= + +# Required only if ai.gateway is set to "opencodezen" in configure() +# OPENCODEZEN_API_KEY= + # ============================================================================= # Optional: Cloudflare AI Gateway # ============================================================================= diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index 5a6f22c..0ea0aee 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -29,6 +29,11 @@ describe("config", () => { expect(getConfig().ai?.gateway).toBe("openrouter"); }); + it("configure sets ai.gateway to opencodezen", () => { + configure({ ai: { gateway: "opencodezen" } }); + expect(getConfig().ai?.gateway).toBe("opencodezen"); + }); + it("configure merges without overwriting other keys", () => { configure({ uploadBasePath: "./uploads" }); configure({ ai: { gateway: "none" } }); diff --git a/src/config.ts b/src/config.ts index a3b8f88..8176ead 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,7 +9,7 @@ export type EmailProvider = { extractContent: (params: { email: string; prompt: string }) => Promise; }; -export type AIGateway = "vercel" | "openrouter" | "cloudflare" | "none"; +export type AIGateway = "vercel" | "openrouter" | "opencodezen" | "cloudflare" | "none"; export type ModelConfig = { /** Model for executing individual steps. Default: google/gemini-3-flash */ diff --git a/src/models.ts b/src/models.ts index afc6fff..c175e7d 100644 --- a/src/models.ts +++ b/src/models.ts @@ -2,6 +2,7 @@ import { AIModelError, ConfigurationError } from "./errors"; import { createAnthropic } from "@ai-sdk/anthropic"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; +import { createOpenAI } from "@ai-sdk/openai"; import { gateway, type LanguageModel } from "ai"; import { wrapAISDKModel } from "axiom/ai"; import { getConfig } from "./config"; @@ -14,6 +15,7 @@ function wrapModel(model: LanguageModel): LanguageModel { let _google: ReturnType | null = null; let _anthropic: ReturnType | null = null; let _openrouter: ReturnType | null = null; +let _opencodezen: ReturnType | null = null; let _cloudflareGoogle: ReturnType | null = null; let _cloudflareAnthropic: ReturnType | null = null; @@ -59,6 +61,21 @@ function getOpenRouterProvider() { return _openrouter; } +function getOpenCodeZenProvider() { + if (!_opencodezen) { + if (!process.env.OPENCODEZEN_API_KEY) { + throw new ConfigurationError( + "OPENCODEZEN_API_KEY isn't set. Add it to your environment (for example: export OPENCODEZEN_API_KEY=your_key). See .env.example for reference.", + ); + } + _opencodezen = createOpenAI({ + baseURL: "https://opencode.ai/zen/v1", + apiKey: process.env.OPENCODEZEN_API_KEY, + }); + } + return _opencodezen; +} + /** * Builds the per-provider Cloudflare AI Gateway base URL and (optional) * `cf-aig-authorization` header. We route through Cloudflare's native @@ -148,6 +165,29 @@ function resolveOpenRouterModelId(modelId: string): string { return OPENROUTER_MODEL_ALIASES[modelId] ?? modelId; } +/** + * Maps canonical model IDs (provider/model) to OpenCode Zen model IDs. + * Zen strips the provider prefix and uses its own naming for some models. + */ +const OPENCODEZEN_MODEL_ALIASES: Record = { + "google/gemini-3.1-pro-preview": "gemini-3.1-pro", + "anthropic/claude-haiku-4.5": "claude-haiku-4-5", + "anthropic/claude-haiku-4-5": "claude-haiku-4-5", + "anthropic/claude-sonnet-4.6": "claude-sonnet-4-6", + "anthropic/claude-sonnet-4-6": "claude-sonnet-4-6", + "anthropic/claude-opus-4.7": "claude-opus-4-7", + "anthropic/claude-opus-4-7": "claude-opus-4-7", +}; + +function resolveOpenCodeZenModelId(modelId: string): string { + if (OPENCODEZEN_MODEL_ALIASES[modelId]) { + return OPENCODEZEN_MODEL_ALIASES[modelId]; + } + // Strip provider prefix: "google/gemini-3-flash" → "gemini-3-flash" + const slashIndex = modelId.indexOf("/"); + return slashIndex !== -1 ? modelId.slice(slashIndex + 1) : modelId; +} + /** * Resolves a canonical model ID to a LanguageModel instance wrapped with Axiom instrumentation. * Input format: "provider/model-name" (e.g. "google/gemini-3-flash") @@ -180,6 +220,10 @@ export function resolveModel(modelId: string): LanguageModel { return wrapModel(getOpenRouterProvider()(resolveOpenRouterModelId(modelId))); } + if (gatewayConfig === "opencodezen") { + return wrapModel(getOpenCodeZenProvider()(resolveOpenCodeZenModelId(modelId))); + } + const [provider, ...rest] = modelId.split("/"); const modelName = rest.join("/"); From d86f1374cd3dd2f0b82498e027314cd9d60bf35a Mon Sep 17 00:00:00 2001 From: Sung-Heon Date: Tue, 21 Apr 2026 15:01:40 +0900 Subject: [PATCH 03/33] docs: update README and CHANGELOG for opencodezen gateway Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 6 ++++++ README.md | 12 +++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0c5b52..72910d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added + +- **OpenCode Zen gateway support**: set `gateway: "opencodezen"` in `configure()` and provide `OPENCODEZEN_API_KEY` to route all model requests through [OpenCode Zen](https://opencode.ai/docs/ko/zen/) (`https://opencode.ai/zen/v1`), an OpenAI-compatible gateway with 30+ curated models including Claude, Gemini, GPT, Qwen, and more. + ## [1.0.0] - 2026-03-27 ### Added diff --git a/README.md b/README.md index 95a814f..a70c070 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,9 @@ ANTHROPIC_API_KEY=sk-ant-... GOOGLE_GENERATIVE_AI_API_KEY=AIza... ``` -Alternatively, you can use an AI gateway like Vercel AI Gateway or OpenRouter to route requests to multiple providers without managing individual API keys. If you choose this option, set `AI_GATEWAY_API_KEY` (for Vercel) or `OPENROUTER_API_KEY` (for OpenRouter) instead. +Alternatively, you can use an AI gateway like Vercel AI Gateway, OpenRouter, or OpenCode Zen to route requests to multiple providers without managing individual API keys. If you choose this option, set `AI_GATEWAY_API_KEY` (for Vercel), `OPENROUTER_API_KEY` (for OpenRouter), or `OPENCODEZEN_API_KEY` (for OpenCode Zen) instead. -You can also route requests through Cloudflare AI Gateway for observability, caching, and rate limiting. Unlike Vercel/OpenRouter, Cloudflare is a proxy (not a reseller), so you still need your own `ANTHROPIC_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY` alongside `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AI_GATEWAY` (and `CLOUDFLARE_AI_GATEWAY_API_KEY` if the gateway has authentication enabled). +You can also route requests through Cloudflare AI Gateway for observability, caching, and rate limiting. Unlike Vercel/OpenRouter/OpenCode Zen, Cloudflare is a proxy (not a reseller), so you still need your own `ANTHROPIC_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY` alongside `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AI_GATEWAY` (and `CLOUDFLARE_AI_GATEWAY_API_KEY` if the gateway has authentication enabled). Set your Playwright project to read `.env` by adding the following to `playwright.config.ts` (after `import { defineConfig, devices } from '@playwright/test';`): @@ -82,8 +82,9 @@ import { runSteps, configure } from "passmark"; configure({ ai: { - gateway: "vercel" // or "openrouter" or "cloudflare" - // Set AI_GATEWAY_API_KEY (Vercel), OPENROUTER_API_KEY (OpenRouter), or + gateway: "vercel" // or "openrouter", "opencodezen", or "cloudflare" + // Set AI_GATEWAY_API_KEY (Vercel), OPENROUTER_API_KEY (OpenRouter), + // OPENCODEZEN_API_KEY (OpenCode Zen), or // CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_AI_GATEWAY (+ CLOUDFLARE_AI_GATEWAY_API_KEY // if the gateway is authenticated) in your .env file. Cloudflare also requires // the upstream provider keys (ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY). @@ -170,7 +171,7 @@ import { configure } from "passmark"; configure({ ai: { - gateway: "none", // "none" (default), "vercel", "openrouter", or "cloudflare" + gateway: "none", // "none" (default), "vercel", "openrouter", "opencodezen", or "cloudflare" models: { stepExecution: "google/gemini-3-flash", utility: "google/gemini-2.5-flash", @@ -189,6 +190,7 @@ configure({ | `GOOGLE_GENERATIVE_AI_API_KEY` | Yes | - | Google API key for Gemini models | | `AI_GATEWAY_API_KEY` | If gateway=vercel | - | Vercel AI Gateway API key | | `OPENROUTER_API_KEY` | If gateway=openrouter | - | OpenRouter API key | +| `OPENCODEZEN_API_KEY` | If gateway=opencodezen | - | OpenCode Zen API key | | `CLOUDFLARE_ACCOUNT_ID` | If gateway=cloudflare | - | Cloudflare account ID that owns the AI Gateway | | `CLOUDFLARE_AI_GATEWAY` | If gateway=cloudflare | - | Cloudflare AI Gateway name (slug) | | `CLOUDFLARE_AI_GATEWAY_API_KEY` | If gateway=cloudflare and the gateway is authenticated | - | Cloudflare AI Gateway token (sent as `cf-aig-authorization`) | From 06e4b74d2e0eb87dc3e798d5f2eef4962989ffd7 Mon Sep 17 00:00:00 2001 From: Ipseeta Date: Thu, 23 Apr 2026 18:26:54 +0530 Subject: [PATCH 04/33] feat(cua): add CUA mode via OpenAI Responses API --- .env.example | 10 + CHANGELOG.md | 3 + README.md | 43 + TROUBLESHOOTING.md | 13 +- package-lock.json | 8068 +++++++++++++++++++++++++++++ package.json | 1 + src/__tests__/config.test.ts | 4 +- src/__tests__/cua-actions.test.ts | 164 + src/__tests__/cua-client.test.ts | 44 + src/__tests__/cua-config.test.ts | 33 + src/__tests__/cua-loop.test.ts | 176 + src/config.ts | 20 + src/cua/actions.ts | 147 + src/cua/client.ts | 38 + src/cua/index.ts | 4 + src/cua/loop.ts | 229 + src/cua/prompts.ts | 118 + src/index.ts | 114 +- 18 files changed, 9225 insertions(+), 4 deletions(-) create mode 100644 package-lock.json create mode 100644 src/__tests__/cua-actions.test.ts create mode 100644 src/__tests__/cua-client.test.ts create mode 100644 src/__tests__/cua-config.test.ts create mode 100644 src/__tests__/cua-loop.test.ts create mode 100644 src/cua/actions.ts create mode 100644 src/cua/client.ts create mode 100644 src/cua/index.ts create mode 100644 src/cua/loop.ts create mode 100644 src/cua/prompts.ts diff --git a/.env.example b/.env.example index 26583e8..ac8a7e1 100644 --- a/.env.example +++ b/.env.example @@ -36,6 +36,16 @@ GOOGLE_GENERATIVE_AI_API_KEY=AIza... # CLOUDFLARE_AI_GATEWAY= # CLOUDFLARE_AI_GATEWAY_API_KEY= +# ============================================================================= +# Optional: CUA mode (OpenAI computer-use agent) +# ============================================================================= + +# Required only if ai.mode is set to "cua" in configure(). +# CUA requires direct OpenAI access (gateway: "none") and an API key with +# access to the CUA model (default: gpt-5.4) and the built-in `computer` +# tool on the Responses API. +# OPENAI_API_KEY=sk-... + # ============================================================================= # Optional: Telemetry (Axiom) # ============================================================================= diff --git a/CHANGELOG.md b/CHANGELOG.md index 69cb5bf..204684b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `maxRetries` option to `AssertionOptions` (default: `1`) to control how many times a failed assertion is retried with a fresh page snapshot and screenshot. Setting it to `0` disables retries. - `onRetry` callback to `AssertionOptions` that fires before each retry, receiving the retry index and the full `AssertionResult` from the previous attempt for debugging flaky assertions. +- **CUA mode** (`configure({ ai: { mode: "cua" } })`): execute `runSteps` and `runUserFlow` through OpenAI's Responses API with the built-in `computer` tool. Screenshot-driven, coordinate-based actions via Playwright's `page.mouse` / `page.keyboard`. Default mode remains `"snapshot"` so existing tests are unaffected. Requires `OPENAI_API_KEY` and `gateway: "none"`; Redis step caching is skipped in this mode because coordinate actions aren't portable across viewport sizes. +- `cua` model slot in `ModelConfig` (default: `gpt-5.4`). +- `getMode()` helper and `AIMode` type exported from `src/config.ts`. ## [1.0.0] - 2026-03-27 diff --git a/README.md b/README.md index 95a814f..0f69950 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,47 @@ npx playwright test example.spec.ts --project chromium After the test completes, you can run `npx playwright show-report` to see a detailed report of the test execution, including an AI summary at the top, provided by Passmark. +### Using CUA mode (OpenAI computer-use agent) + +By default Passmark uses ARIA accessibility snapshots. For visual, screenshot-driven automation via OpenAI's computer-use agent, opt in with `mode: "cua"`: + +```typescript +import { configure } from "passmark"; + +configure({ + ai: { + mode: "cua", + gateway: "none", // CUA requires direct OpenAI access + }, +}); +``` + +Set `OPENAI_API_KEY` in your `.env`. Because CUA sees only the page screenshot (there is no browser address bar in the screenshot), use Playwright's `page.goto()` to land on the starting URL before calling `runSteps()`: + +```typescript +test("Shopping cart tests", async ({ page }) => { + await page.goto("https://demo.vercel.store"); + await runSteps({ + page, + userFlow: "Add product to cart", + steps: [ + { description: "Click Acme Circles T-Shirt" }, + { description: "Select color", data: { value: "White" } }, + { description: "Add to cart", waitUntil: "My Cart is visible" }, + ], + test, + expect, + }); +}); +``` + +Notes: + +- CUA mode uses OpenAI's `gpt-5.4` + built-in `computer` tool. Override with `configure({ ai: { models: { cua: "..." } } })`. +- Redis step caching is skipped in CUA mode because coordinate actions aren't portable across viewport sizes. +- `gateway: "vercel" | "openrouter" | "cloudflare"` is not compatible with CUA — the Responses-API `computer` tool is only exposed on direct OpenAI access. +- Account requirements: your OpenAI API key must have access to the CUA model and the built-in `computer` tool on the Responses API. + ## Features - **Core Execution** — `runSteps()` and `runUserFlow()` for flexible test orchestration in natural language, with smart caching and auto-healing @@ -192,6 +233,7 @@ configure({ | `CLOUDFLARE_ACCOUNT_ID` | If gateway=cloudflare | - | Cloudflare account ID that owns the AI Gateway | | `CLOUDFLARE_AI_GATEWAY` | If gateway=cloudflare | - | Cloudflare AI Gateway name (slug) | | `CLOUDFLARE_AI_GATEWAY_API_KEY` | If gateway=cloudflare and the gateway is authenticated | - | Cloudflare AI Gateway token (sent as `cf-aig-authorization`) | +| `OPENAI_API_KEY` | If mode=cua | - | OpenAI API key (required for CUA mode; must have Responses-API `computer` tool access) | | `AXIOM_TOKEN` | No | - | Axiom token for OpenTelemetry tracing | | `AXIOM_DATASET` | No | - | Axiom dataset for trace storage | | `PASSMARK_LOG_LEVEL` | No | `info` | Log level: `debug`, `info`, `warn`, `error`, `silent` | @@ -209,6 +251,7 @@ All models are configurable via `configure({ ai: { models: { ... } } })`: | `assertionSecondary` | `google/gemini-3-flash` | Secondary assertion model (Gemini) | | `assertionArbiter` | `google/gemini-3.1-pro-preview` | Arbiter for assertion disagreements | | `utility` | `google/gemini-2.5-flash` | Data extraction, wait conditions | +| `cua` | `gpt-5.4` | CUA mode — OpenAI Responses API with the built-in `computer` tool | ## Caching diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 702f7fa..7cb0bb8 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -10,6 +10,7 @@ This guide helps you diagnose and fix the common problems contributors hit when - Redis available at `REDIS_URL` (see `.env.example`) - Required AI keys set when using direct providers: `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY` - If using the Vercel AI Gateway, set `AI_GATEWAY_API_KEY` +- If using CUA mode (`configure({ ai: { mode: "cua" } })`), set `OPENAI_API_KEY` and use `gateway: "none"` Refer to `.env.example` for the full list of environment variables. @@ -93,7 +94,17 @@ Fix: - Increase timeouts or retry values where appropriate (see `src/constants.ts`). - Make sure your network to the AI provider is reliable and your API quota isn't exhausted. -### 7) Enable debug logs +### 7) CUA mode errors + +`mode: "cua"` calls OpenAI's Responses API directly with the built-in `computer` tool. + +- **"CUA mode requires gateway: 'none'"** — CUA doesn't work through Vercel / OpenRouter / Cloudflare gateways (the Responses-API `computer` tool is only available on direct OpenAI access). Use `configure({ ai: { mode: "cua", gateway: "none" } })`. +- **"OPENAI_API_KEY isn't set"** — add `OPENAI_API_KEY` to your environment / `.env`. +- **Generic 400 with `param: null` in the error body** — your OpenAI API key likely doesn't have access to the CUA model or the built-in `computer` tool on the Responses API. Verify access at https://platform.openai.com/settings/organization/limits. +- **"Tool 'computer_use_preview' is not supported with gpt-5.4"** — you're on an old build. In the current API, `gpt-5.4` uses the new simpler tool shape `{ type: "computer" }`, not the legacy `computer_use_preview`. Rebuild from `main`. +- **Model can't complete a "Navigate to URL" step** — CUA has no browser chrome / address bar in its screenshot view, so it cannot type a URL. Use Playwright's `await page.goto(url)` before calling `runSteps()`. + +### 8) Enable debug logs Set the `PASSMARK_LOG_LEVEL` environment variable to `debug` to get more information from the logger: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..58deff4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,8068 @@ +{ + "name": "passmark", + "version": "1.0.8", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "passmark", + "version": "1.0.8", + "license": "FSL-1.1-Apache-2.0", + "dependencies": { + "@ai-sdk/anthropic": "^3.0.69", + "@ai-sdk/google": "^3.0.63", + "@ai-sdk/google-vertex": "^4.0.105", + "@ai-sdk/openai": "^3.0.52", + "@faker-js/faker": "^10.1.0", + "@openrouter/ai-sdk-provider": "^2.5.1", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.207.0", + "@opentelemetry/resources": "^2.2.0", + "@opentelemetry/sdk-trace-node": "^2.2.0", + "@opentelemetry/semantic-conventions": "^1.37.0", + "acorn": "^8.15.0", + "ai": "^6.0.161", + "axiom": "^0.22.2", + "ioredis": "^5.10.1", + "openai": "^6.34.0", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", + "shortid": "^2.2.17", + "uuid": "^13.0.0", + "zod": "^4.1.12" + }, + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/ioredis": "^4.28.10", + "@types/node": "^22.13.10", + "@types/shortid": "^2.2.0", + "@typescript-eslint/eslint-plugin": "^8.57.2", + "@typescript-eslint/parser": "^8.57.2", + "@vitest/coverage-v8": "^4.1.2", + "eslint": "^10.1.0", + "prettier": "^3.8.1", + "typescript": "^5.9.2", + "typescript-eslint": "^8.57.2", + "vitest": "^4.1.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@playwright/test": "^1.59.0", + "playwright-core": "^1.59.0" + } + }, + "node_modules/@ai-sdk/anthropic": { + "version": "3.0.71", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.71.tgz", + "integrity": "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/gateway": { + "version": "3.0.104", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.104.tgz", + "integrity": "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23", + "@vercel/oidc": "3.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/google": { + "version": "3.0.64", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.64.tgz", + "integrity": "sha512-CbR82EgGPNrj/6q0HtclwuCqe0/pDShyv3nWDP/A9DroujzWXnLMlUJVrgPOsg4b40zQCwwVs2XSKCxvt/4QaA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/google-vertex": { + "version": "4.0.112", + "resolved": "https://registry.npmjs.org/@ai-sdk/google-vertex/-/google-vertex-4.0.112.tgz", + "integrity": "sha512-cSfHCkM+9ZrFtQWIN1WlV93JPD+isGSdFxKj7u1L9m2aLVZajlXdcE41GL9hMt7ld7bZYE4NnZ+4VLxBAHE+Eg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/anthropic": "3.0.71", + "@ai-sdk/google": "3.0.64", + "@ai-sdk/openai-compatible": "2.0.41", + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23", + "google-auth-library": "^10.5.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "3.0.53", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.53.tgz", + "integrity": "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai-compatible": { + "version": "2.0.41", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-2.0.41.tgz", + "integrity": "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", + "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/provider-utils": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.23.tgz", + "integrity": "sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "3.0.8", + "@standard-schema/spec": "^1.1.0", + "eventsource-parser": "^3.0.6" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "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==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@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/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.5", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", + "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", + "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@faker-js/faker": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", + "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", + "npm": ">=10" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", + "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", + "license": "MIT" + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@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/@next/env": { + "version": "15.5.15", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.15.tgz", + "integrity": "sha512-vcmyu5/MyFzN7CdqRHO3uHO44p/QPCZkuTUXroeUmhNP8bL5PHFEhik22JUazt+CDDoD6EpBYRCaS2pISL+/hg==", + "license": "MIT" + }, + "node_modules/@openrouter/ai-sdk-provider": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@openrouter/ai-sdk-provider/-/ai-sdk-provider-2.8.0.tgz", + "integrity": "sha512-oDDW/0KMqz4suHVloB9sNv0YyKLGNYf1FTevXH6adDkid5dsmbbcYuiEsbIhpZSZtHa6o5AVjK1jEAfePOLxww==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "ai": "^6.0.0", + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.207.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.207.0.tgz", + "integrity": "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node": { + "version": "0.60.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.60.1.tgz", + "integrity": "sha512-oMBVXiun0qWhj693Y24Ie+75q45YXHRFeH9vX/XBWKRNJIM/02ufjmNvmOdoHY0EPxU9rBmWCW82Uidf54iSPA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/instrumentation-amqplib": "^0.49.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.53.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.54.0", + "@opentelemetry/instrumentation-bunyan": "^0.48.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.48.0", + "@opentelemetry/instrumentation-connect": "^0.46.0", + "@opentelemetry/instrumentation-cucumber": "^0.17.0", + "@opentelemetry/instrumentation-dataloader": "^0.19.0", + "@opentelemetry/instrumentation-dns": "^0.46.0", + "@opentelemetry/instrumentation-express": "^0.51.0", + "@opentelemetry/instrumentation-fastify": "^0.47.0", + "@opentelemetry/instrumentation-fs": "^0.22.0", + "@opentelemetry/instrumentation-generic-pool": "^0.46.0", + "@opentelemetry/instrumentation-graphql": "^0.50.0", + "@opentelemetry/instrumentation-grpc": "^0.202.0", + "@opentelemetry/instrumentation-hapi": "^0.49.0", + "@opentelemetry/instrumentation-http": "^0.202.0", + "@opentelemetry/instrumentation-ioredis": "^0.50.0", + "@opentelemetry/instrumentation-kafkajs": "^0.11.0", + "@opentelemetry/instrumentation-knex": "^0.47.0", + "@opentelemetry/instrumentation-koa": "^0.50.1", + "@opentelemetry/instrumentation-lru-memoizer": "^0.47.0", + "@opentelemetry/instrumentation-memcached": "^0.46.0", + "@opentelemetry/instrumentation-mongodb": "^0.55.1", + "@opentelemetry/instrumentation-mongoose": "^0.49.0", + "@opentelemetry/instrumentation-mysql": "^0.48.0", + "@opentelemetry/instrumentation-mysql2": "^0.48.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.48.0", + "@opentelemetry/instrumentation-net": "^0.46.1", + "@opentelemetry/instrumentation-oracledb": "^0.28.0", + "@opentelemetry/instrumentation-pg": "^0.54.0", + "@opentelemetry/instrumentation-pino": "^0.49.0", + "@opentelemetry/instrumentation-redis": "^0.49.1", + "@opentelemetry/instrumentation-redis-4": "^0.49.0", + "@opentelemetry/instrumentation-restify": "^0.48.1", + "@opentelemetry/instrumentation-router": "^0.47.0", + "@opentelemetry/instrumentation-runtime-node": "^0.16.0", + "@opentelemetry/instrumentation-socket.io": "^0.49.0", + "@opentelemetry/instrumentation-tedious": "^0.21.0", + "@opentelemetry/instrumentation-undici": "^0.13.1", + "@opentelemetry/instrumentation-winston": "^0.47.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.31.2", + "@opentelemetry/resource-detector-aws": "^2.2.0", + "@opentelemetry/resource-detector-azure": "^0.9.0", + "@opentelemetry/resource-detector-container": "^0.7.2", + "@opentelemetry/resource-detector-gcp": "^0.36.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/sdk-node": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.4.1", + "@opentelemetry/core": "^2.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.0.tgz", + "integrity": "sha512-MWXggArM+Y11mPS8VOrqxOj+YMGQSRuvhM91eSBX4xFpJa05mpkeVvM8pPux5ElkEjV5RMgrkisrlP/R83SpBQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", + "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.202.0.tgz", + "integrity": "sha512-Y84L8Yja/A2qjGEzC/To0yrMUXHrtwJzHtZ2za1/ulZplRe5QFsLNyHixIS42ZYUKuNyWMDgOFhnN2Pz5uThtg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/sdk-logs": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.202.0.tgz", + "integrity": "sha512-mJWLkmoG+3r+SsYQC+sbWoy1rjowJhMhFvFULeIPTxSI+EZzKPya0+NZ3+vhhgx2UTybGQlye3FBtCH3o6Rejg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/sdk-logs": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.202.0.tgz", + "integrity": "sha512-qYwbmNWPkP7AbzX8o4DRu5bb/a0TWYNcpZc1NEAOhuV7pgBpAUPEClxRWPN94ulIia+PfQjzFGMaRwmLGmNP6g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.202.0.tgz", + "integrity": "sha512-/dq/rf4KCkTYoP+NyPXTE+5wjvfhAHSqK62vRsJ/IalG61VPQvwaL18yWcavbI+44ImQwtMeZxfIJSox7oQL0w==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-metrics": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.202.0.tgz", + "integrity": "sha512-ooYcrf/m9ZuVGpQnER7WRH+JZbDPD389HG7VS/EnvIEF5WpNYEqf+NdmtaAcs51d81QrytTYAubc5bVWi//28w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-metrics": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.202.0.tgz", + "integrity": "sha512-X0RpPpPjyCAmIq9tySZm0Hk3Ltw8KWsqeNq5I7gS9AR9RzbVHb/l+eiMI1CqSRvW9R47HXcUu/epmEzY8ebFAg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-metrics": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.202.0.tgz", + "integrity": "sha512-6RvQqZHAPFiwL1OKRJe4ta6SgJx/g8or41B+OovVVEie3HeCDhDGL9S1VJNkBozUz6wTY8a47fQwdMrCOUdMhQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-metrics": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.202.0.tgz", + "integrity": "sha512-d5wLdbNA3ahpSeD0I34vbDFMTh4vPsXemH0bKDXLeCVULCAjOJXuZmEiuRammiDgVvvX7CAb/IGLDz8d2QHvoA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.207.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.207.0.tgz", + "integrity": "sha512-HSRBzXHIC7C8UfPQdu15zEEoBGv0yWkhEwxqgPCHVUKUQ9NLHVGXkVrf65Uaj7UwmAkC1gQfkuVYvLlD//AnUQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/otlp-exporter-base": "0.207.0", + "@opentelemetry/otlp-transformer": "0.207.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.202.0.tgz", + "integrity": "sha512-z3vzdMclCETGIn8uUBgpz7w651ftCiH2qh3cewhBk+rF0EYPNQ3mJvyxktLnKIBZ/ci0zUknAzzYC7LIIZmggQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.0.1.tgz", + "integrity": "sha512-a9eeyHIipfdxzCfc2XPrE+/TI3wmrZUDFtG2RRXHSbZZULAny7SyybSvaDvS77a7iib5MPiAvluwVvbGTsHxsw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.202.0.tgz", + "integrity": "sha512-Uz3BxZWPgDwgHM2+vCKEQRh0R8WKrd/q6Tus1vThRClhlPO39Dyz7mDrOr6KuqGXAlBQ1e5Tnymzri4RMZNaWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.49.0.tgz", + "integrity": "sha512-OCGkE+1JoUN+gOzs3u0GSa7GV//KX6NMKzaPchedae7ZwFVyyBQ8VECJngHgW3k/FLABFnq9Oiym2WZGiWugVQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-lambda": { + "version": "0.53.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.53.1.tgz", + "integrity": "sha512-canWSwigcvxq2mIrrxAdj6Cf21ysoxpRoe1T4UGINlKuyvrFiYAKLVZlPqVgP2Dwh9w/5+6yGBouoDhO/dQ0Kg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/aws-lambda": "8.10.150" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-sdk": { + "version": "0.54.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.54.0.tgz", + "integrity": "sha512-4XnXfpACX8fpOnt/D8d/1AFg3uOwBTG9TopQBuikDZJYUrLUSdT7UiotCFqAM/Z6hQJh72Jy3591C/OrmKct7A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/propagation-utils": "^0.31.2", + "@opentelemetry/semantic-conventions": "^1.31.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-bunyan": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.48.0.tgz", + "integrity": "sha512-Q6ay5CXIKuyejadPoLboz+jKumB3Zuxyk35ycFh9vfIeww3+mNRyMVj6KxHRS0Imbv9zhNbP3uyrUpvEMMyHuw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "^0.202.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@types/bunyan": "1.8.11" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-bunyan/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cassandra-driver": { + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.48.0.tgz", + "integrity": "sha512-0dcX8Kx0S6ZAOknrbA+BBh1j5lg5F20W18m5VYoGUxkuLIUbWkQA3uaqeTfqbOwmnBmb1upDPUWPR+g5N12B4Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.46.0.tgz", + "integrity": "sha512-YNq/7M1JXnWRkpKPC9dbYZA36cg547gY0p1bijW7vuZJ9t5f3alo6w8TWtZwV/hOFtBGHDXVhKVfp2Mh6zVHjQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.38" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cucumber": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.17.1.tgz", + "integrity": "sha512-s/18qxBzjEWcJ8BIPJx5oP6GCB7huOaQai3lpJRXe9AcRTOUn6Jzp6oOeY52GE2uvTebo9/3CurM8So2J96fag==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.19.0.tgz", + "integrity": "sha512-zIVRnRs3zDZCqStQcpIdRx3Dz9WXFSVj9qimqI7CRuKao9qnrZYUVQHvvVlLZX3JAg+nDC6JRS95zvbq50hj4A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dns": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.46.0.tgz", + "integrity": "sha512-m8u72x2fSIjhP1ITJX9Ims3eR4Qn8ze+QWy9NHYO01JlmiMamoc9TfIOd4dyOtxVja4tjnkWceKQdlEH9F9BoA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.51.1.tgz", + "integrity": "sha512-cKmzev7RolYGedQ82hVUoH+74BP4E0xmhUCEagOxmW3aKilXYx01KwsNN6wnx3IXR7u2nlYugQsEsLLA4d829A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.47.1.tgz", + "integrity": "sha512-zTVFju7I67wA7Y2ZJ9Gb5u3zqiXIx5Zcaa2KSapal6VZ6gS8OkoC3t35M/6iazfBIPd9e1uCsonbm8jz8v+x1A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.22.0.tgz", + "integrity": "sha512-ktQVFD6pd8eAIW6t2DtDuXj2lxq+wnQ8WUkJLNZzl3rEE2TZEiHg7wIkWVoxl4Cz4pJ2YZJbdU2fHAizuDebDw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.46.1.tgz", + "integrity": "sha512-4rH/7nqxY2rnAodfP5nHMpwC6aFJUGRq9PZ44L5nUf+dxNyeuSPkuvxUr1tOf+qduqkhs2sZDP8/53n9/YmNzQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.50.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.50.0.tgz", + "integrity": "sha512-Nn3vBS5T0Dv4+9WF1dGR0Lgsxuz6ztQmTsxoHvesm6YAAXiHffnwsxBEJUKEJcjxfXzjO1SVuLDkv1bAeQ3NFw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.202.0.tgz", + "integrity": "sha512-dWvefHNAyAfaHVmxQ/ySLQSI2hGKLgK1sBtvae4w9xruqU08bBMtvmVeGMA/5whfiUDU8ftp1/84U4Zoe5N56A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "0.202.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.49.0.tgz", + "integrity": "sha512-d4BcCjbW7Pfg4FpbAAF0cK/ue3dN02WMw0uO2G792KzDjxj05MtZm3eBTz672j3ejV9hM0HvPPhUHUsIC0H6Gw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.202.0.tgz", + "integrity": "sha512-oX+jyY2KBg4/nVH3vZhSWDbhywkHgE0fq3YinhUBx0jv+YUWC2UKA7qLkxr/CSzfKsFi/Km0NKV+llH17yYGKw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/instrumentation": "0.202.0", + "@opentelemetry/semantic-conventions": "^1.29.0", + "forwarded-parse": "2.1.2" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.50.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.50.1.tgz", + "integrity": "sha512-HKrWKOM23qNwqNjWfzkw7mePversmcH5ac6T1dUdiRyJVYaLr4qfydyYkgKIGWHOF2TKvQGobXo3CjvxABQWVw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/redis-common": "^0.38.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.11.0.tgz", + "integrity": "sha512-+i9VqVEPNObB1tkwcLV6zAafnve72h2Iwo48E11M/kVXMNXlgGhiYckYCmzba8c2u5XD/V98XZDrCIyO8CLCNA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.30.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.47.0.tgz", + "integrity": "sha512-OjqjnzXD5+FXVGkOznbRAz9yByb4UWzIUhXjuHvOQ50IUY8mv3rM2Gj6Ar7m5JsENiS5DtAy2Vfwk4e9zNC0ng==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.33.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.50.2.tgz", + "integrity": "sha512-+XTWg7a+u6lu4bm6HN0ItirTF0bBFUJlayqe+iVE87Cwpha7W47DV0aoNL8AzGPczlF1UQVVO0kvcfI8bnrkHw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.47.0.tgz", + "integrity": "sha512-UJ2UlCAIF+N4zNkiHdMr4O0caN0K6YboAso3/zaFdG1QiPR2zqZcbWAGFBikZ9HSByU+NwbxTXDzlpkcDZIqWg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-memcached": { + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.46.0.tgz", + "integrity": "sha512-FFDcOVJUxZQqbg57gVskZGXRfEsZXwOvCaPv6/qIZRw5glLXPTulpnfG/s8NAltsj2buXSvS4eKFo+0HKH0apw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/memcached": "^2.2.6" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.55.1.tgz", + "integrity": "sha512-Wb13YixWm8nB27ZSQW3h070UWkivoh6bjeyDUY6lLimSUulALr+YHBn0t71U1aTcUeaZv3IBNaPRimFXhz6gBA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.49.0.tgz", + "integrity": "sha512-nF+43QFe8IoW20TmTJZdxZhnVZGEglODUvzAo3fRmaBFAkwUXRGzRgABS255PCjIbScEaRRDCXc6EAsSkwRNPg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.48.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.48.1.tgz", + "integrity": "sha512-wP5+wIfQXmnKY4riKlx+1PiHpMSkG8Zu2cMXkiX6u84HqAWY62+N/Wv3fx9FU+/DU+fz3BdQQbo0EpVWziqqvg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.27" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.48.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.48.1.tgz", + "integrity": "sha512-deJbaCC595WYhqDoXR5UfRx0bPmYyr1WhiFv6BjHRndMEUStHYYnsF6+mjpa3f0nebVj8Nv8eDcke4iTs7AfBw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.41.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-nestjs-core": { + "version": "0.48.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.48.1.tgz", + "integrity": "sha512-rH0IUQRf9wjxEkiPfltM17DVqgSe/rgeIlg1CKRDAhuxWkbXlcHwdOnBfngGKhJNGOlGUo6HzZesavPAlmm3Fw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.30.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-net": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.46.1.tgz", + "integrity": "sha512-r7Buqem+odrTTPlWfT7EqS24QnDAL4U+c4e38RzcRtdZF00Z34oqEpge7TZcQLo0vEASWbHQ/WjWNR7ZYKFKBA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-oracledb": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-oracledb/-/instrumentation-oracledb-0.28.0.tgz", + "integrity": "sha512-VObbQRd3g8nDLLOeGjm5l6TnB9dtEaJoedLfLwMGrlD6lkai+hdfalYh6FOF5dce+dJouZdW6NUUAaBj4f4KcA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/oracledb": "6.5.2" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.54.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.54.1.tgz", + "integrity": "sha512-vy2WbrB76iRpJccGCC7HNICVm+f5zg20dYBuB4r1X7TaXYsi1txrjvemOEH0h9lTpm2vVFoheHsVoClxleXvvQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.41.0", + "@types/pg": "8.15.4", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pino": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.49.1.tgz", + "integrity": "sha512-QTD4HQA0fhtu4Hvw9iIlnroDiQju8nmEmnTQrS3xrb6g9AsdBMYnXXyzNBlLpSvtqwfPvgAxfY4DY1IYtnNwDg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "^0.202.0", + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pino/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.49.1.tgz", + "integrity": "sha512-Ds5Ke9qE9kTlDThqLSJJntkIvuMQCBPiFKwHntocb/3q/9q5D47BNwawO5Mj9sVMV6zkld5M5Pb9Av39iieuOg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/redis-common": "^0.37.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.49.0.tgz", + "integrity": "sha512-i+Wsl7M2LXEDA2yXouNJ3fttSzzb5AhlehvSBVRIFuinY51XrrKSH66biO0eox+pYQMwAlPxJ778XcMQffN78A==", + "deprecated": "Use \"@opentelemetry/instrumentation-redis\", which (as of v0.50.0) includes support for instrumenting redis v4.", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/redis-common": "^0.37.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4/node_modules/@opentelemetry/redis-common": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.37.0.tgz", + "integrity": "sha512-tJwgE6jt32bLs/9J6jhQRKU2EZnsD8qaO13aoFyXwF6s4LhpT7YFHf3Z03MqdILk6BA2BFUhoyh7k9fj9i032A==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis/node_modules/@opentelemetry/redis-common": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.37.0.tgz", + "integrity": "sha512-tJwgE6jt32bLs/9J6jhQRKU2EZnsD8qaO13aoFyXwF6s4LhpT7YFHf3Z03MqdILk6BA2BFUhoyh7k9fj9i032A==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + } + }, + "node_modules/@opentelemetry/instrumentation-restify": { + "version": "0.48.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.48.2.tgz", + "integrity": "sha512-V+Bac9zMkQI7p1BsJV/jqg175nBs5aIpeh5HRHxrvlnDaH7TDlHDpax2i+sSrTHjSqxF/jeaIDDjuCW5C5WKbg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-router": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.47.0.tgz", + "integrity": "sha512-U0zA1LTDqtTWyd5e4SdoqQA/8QUOhc4LDv9U7b+8FMFTty95OF84apUdatl09Dzc51XeWPWIV7VutmSCd/zsUg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-runtime-node": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-runtime-node/-/instrumentation-runtime-node-0.16.0.tgz", + "integrity": "sha512-Q/GB9LsKLrRCEIPLAQTDQvydnLmLXBSRkYkWzwKzY/LCkOs+Cl8YiJG08p6D4CaJ6lvP0iG4kwPHk1ydNbdehg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-socket.io": { + "version": "0.49.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.49.0.tgz", + "integrity": "sha512-DpMtNBEcaLCcbP1WVBPCSgRiBs31igTQkal1gUm40VL/XAv5GUqRAUnvHZrQh3yPipOqzV65pdb0jJXdps/tug==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.21.1.tgz", + "integrity": "sha512-RDQyesAIJ3JHw8w5vthJjrzI3jTm/l6aeEQzIZ6cMG5hcW7ySPSyaxWbtmmp0FHPkdoGwc3Li+UQfV77+xLA1Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.202.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.13.2.tgz", + "integrity": "sha512-rO8CNuHnVN13rKrXayvtuXMXwPQkem3H0r/UWZhyNGQeHlqlQgpgtu5mR9dzSuv9kLRrxZb/WjK+sGOP5kwetg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/instrumentation-winston": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.47.0.tgz", + "integrity": "sha512-r+GqnZU/aFldQyB5QdOlxsMlH9KZ4+zJfnYplz3lbC9f9ozAIlVAeoshvWTtbv7Oxp2NnK64EfnNP1pClaGEqA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "^0.202.0", + "@opentelemetry/instrumentation": "^0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-winston/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.207.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.207.0.tgz", + "integrity": "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/otlp-transformer": "0.207.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.202.0.tgz", + "integrity": "sha512-yIEHVxFA5dmYif7lZbbB66qulLLhrklj6mI2X3cuGW5hYPyUErztEmbroM+6teu/XobBi9bLHid2VT4NIaRuGg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.207.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.207.0.tgz", + "integrity": "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.207.0", + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/sdk-logs": "0.207.0", + "@opentelemetry/sdk-metrics": "2.2.0", + "@opentelemetry/sdk-trace-base": "2.2.0", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagation-utils": { + "version": "0.31.18", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.31.18.tgz", + "integrity": "sha512-gIMtbHW+UvzOlnD/20e/zbYoDPRQch9kcevwniyO9GrdhSphaIQwoR6jFi4NvFjQpIoHGAwpNA7BcfRBgwAxPQ==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.0.1.tgz", + "integrity": "sha512-Hc09CaQ8Tf5AGLmf449H726uRoBNGPBL4bjr7AnnUpzWMvhdn61F78z9qb6IqB737TffBsokGAK1XykFEZ1igw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.0.1.tgz", + "integrity": "sha512-7PMdPBmGVH2eQNb/AtSJizQNgeNTfh6jQFqys6lfhd6P4r+m/nTh3gKPPpaCXVdRQ+z93vfKk+4UGty390283w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.3.tgz", + "integrity": "sha512-VCghU1JYs/4gP6Gqf/xro9MEsZ7LrMv2uONVsaESKL38ZOB9BqnI98FfS23wjMnHlpuE+TTaWSoAVNpTwYXzjw==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + } + }, + "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { + "version": "0.31.11", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.31.11.tgz", + "integrity": "sha512-R/asn6dAOWMfkLeEwqHCUz0cNbb9oiHVyd11iwlypeT/p9bR1lCX5juu5g/trOwxo62dbuFcDbBdKCJd3O2Edg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-aws": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-2.15.0.tgz", + "integrity": "sha512-+aiEkI+JA94XVIJtltt3XKYbLSaHRqHFdvGOwulBpfNKtEIWDEkKm3qfTl7Q0q9gY9621oXMU1sT5MM7koCnyA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-azure": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.9.0.tgz", + "integrity": "sha512-5wJwAAW2vhbqIhgaRisU1y0F5mUco59F/dKgmnnnT6YNbxjrbdUZYxKF5Wl7deJoACVdL5wi/3N97GCXPEwwCQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-container": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.7.11.tgz", + "integrity": "sha512-XUxnGuANa/EdxagipWMXKYFC7KURwed9/V0+NtYjFmwWHzV9/J4IYVGTK8cWDpyUvAQf/vE4sMa3rnS025ivXQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-gcp": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.36.0.tgz", + "integrity": "sha512-mWnEcg4tA+IDPrkETWo42psEsDN20dzYZSm4ZH8m8uiQALnNksVmf5C3An0GUEj5zrrxMasjSuv4zEH1gI40XQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/resources": "^2.0.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.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", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/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" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.207.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.207.0.tgz", + "integrity": "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.207.0", + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.2.0.tgz", + "integrity": "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.202.0.tgz", + "integrity": "sha512-SF9vXWVd9I5CZ69mW3GfwfLI2SHgyvEqntcg0en5y8kRp5+2PPoa3Mkgj0WzFLrbSgTw4PsXn7c7H6eSdrtV0w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/exporter-logs-otlp-grpc": "0.202.0", + "@opentelemetry/exporter-logs-otlp-http": "0.202.0", + "@opentelemetry/exporter-logs-otlp-proto": "0.202.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.202.0", + "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", + "@opentelemetry/exporter-metrics-otlp-proto": "0.202.0", + "@opentelemetry/exporter-prometheus": "0.202.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.202.0", + "@opentelemetry/exporter-trace-otlp-http": "0.202.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.202.0", + "@opentelemetry/exporter-zipkin": "2.0.1", + "@opentelemetry/instrumentation": "0.202.0", + "@opentelemetry/propagator-b3": "2.0.1", + "@opentelemetry/propagator-jaeger": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "@opentelemetry/sdk-trace-node": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/context-async-hooks": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.0.1.tgz", + "integrity": "sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw==", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.202.0.tgz", + "integrity": "sha512-/hKE8DaFCJuaQqE1IxpgkcjOolUIwgi3TgHElPVKGdGRBSmJMTmN/cr6vWa55pCJIXPyhKvcMrbrya7DZ3VmzA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.0.1.tgz", + "integrity": "sha512-UhdbPF19pMpBtCWYP5lHbTogLWx9N0EBxtdagvkn5YtsAnCBZzL7SjktG+ZmupRgifsHMjwUaCCaVmqGfSADmA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.0.1", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", + "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", + "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.0.tgz", + "integrity": "sha512-RrFHOXw0IYp/OThew6QORdybnnLitUAUMCJKcQNBYS0hDkCYarO2vTkVxfrGxCIqd5XHSMvbCpBd/T8ZMw8oSg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/context-async-hooks": "2.7.0", + "@opentelemetry/core": "2.7.0", + "@opentelemetry/sdk-trace-base": "2.7.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node/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" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node/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", + "@opentelemetry/resources": "2.7.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.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/@opentelemetry/sql-common": { + "version": "0.41.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.2.tgz", + "integrity": "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@playwright/test": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "playwright": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "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-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@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/aws-lambda": { + "version": "8.10.150", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.150.tgz", + "integrity": "sha512-AX+AbjH/rH5ezX1fbK8onC/a+HyQHo7QGmvoxAE42n22OsciAxvZoZNEr22tbXs8WfP1nIsBjKDpgPm3HjOZbA==", + "license": "MIT" + }, + "node_modules/@types/bunyan": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.11.tgz", + "integrity": "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/memcached": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.10.tgz", + "integrity": "sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mysql": { + "version": "2.15.27", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", + "integrity": "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/oracledb": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-6.5.2.tgz", + "integrity": "sha512-kK1eBS/Adeyis+3OlBDMeQQuasIDLUYXsi2T15ccNJ0iyUpQ4xDF7svFu3+bGVrI0CMBUclPciz+lsQR3JX3TQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.15.4", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.4.tgz", + "integrity": "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "license": "MIT", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/shortid": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-2.2.0.tgz", + "integrity": "sha512-jBG2FgBxcaSf0h662YloTGA32M8UtNbnTPekUr/eCmWXq0JWQXgNEQ/P5Gf05Cv66QZtE1Ttr83I1AJBPdzCBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.0.tgz", + "integrity": "sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/type-utils": "8.59.0", + "@typescript-eslint/utils": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.59.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.0.tgz", + "integrity": "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.0.tgz", + "integrity": "sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.59.0", + "@typescript-eslint/types": "^8.59.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.0.tgz", + "integrity": "sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.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/tsconfig-utils": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.0.tgz", + "integrity": "sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.0.tgz", + "integrity": "sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/utils": "8.59.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.0.tgz", + "integrity": "sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.0.tgz", + "integrity": "sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.59.0", + "@typescript-eslint/tsconfig-utils": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/visitor-keys": "8.59.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.0.tgz", + "integrity": "sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.59.0", + "@typescript-eslint/types": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.0.tgz", + "integrity": "sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.59.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vercel/oidc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz", + "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==", + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz", + "integrity": "sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.5", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.5", + "vitest": "4.1.5" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.5", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.5", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ai": { + "version": "6.0.168", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.168.tgz", + "integrity": "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@ai-sdk/gateway": "3.0.104", + "@ai-sdk/provider": "3.0.8", + "@ai-sdk/provider-utils": "4.0.23", + "@opentelemetry/api": "1.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ai/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.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": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axiom": { + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/axiom/-/axiom-0.22.2.tgz", + "integrity": "sha512-OlOudN3KM86YpOlOf5vuJHAVbYd5Xe9jnENIB30AvvNCFkxtAmUFW3OLC+svjjeurULRdjoKKRiFsUjBNlt6pA==", + "license": "MIT", + "dependencies": { + "@next/env": "^15.4.2", + "@opentelemetry/auto-instrumentations-node": "^0.60.1", + "@opentelemetry/context-async-hooks": "^2.0.1", + "@opentelemetry/exporter-trace-otlp-http": "^0.202.0", + "@opentelemetry/resources": "^2.0.1", + "@opentelemetry/sdk-trace-node": "^2.0.1", + "@opentelemetry/semantic-conventions": "^1.37.0", + "@sinclair/typebox": "^0.34.37", + "c12": "^2.0.4", + "commander": "^14.0.0", + "defu": "^6.1.4", + "handlebars": "^4.7.8", + "nanoid": "^5.1.5" + }, + "bin": { + "axiom": "dist/bin.js" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/api-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", + "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/core": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", + "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.202.0.tgz", + "integrity": "sha512-/hKE8DaFCJuaQqE1IxpgkcjOolUIwgi3TgHElPVKGdGRBSmJMTmN/cr6vWa55pCJIXPyhKvcMrbrya7DZ3VmzA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-exporter-base": "0.202.0", + "@opentelemetry/otlp-transformer": "0.202.0", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", + "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/otlp-transformer": "0.202.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", + "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/sdk-logs": "0.202.0", + "@opentelemetry/sdk-metrics": "2.0.1", + "@opentelemetry/sdk-trace-base": "2.0.1", + "protobufjs": "^7.3.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/resources": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", + "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/sdk-logs": { + "version": "0.202.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", + "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.202.0", + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/sdk-metrics": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", + "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/axiom/node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", + "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.0.1", + "@opentelemetry/resources": "2.0.1", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/axiom/node_modules/c12": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/c12/-/c12-2.0.4.tgz", + "integrity": "sha512-3DbbhnFt0fKJHxU4tEUPmD1ahWE4PWPMomqfYsTJdrhpmEnRKJi3qSC4rO5U6E6zN1+pjBY7+z8fUmNRMaVKLw==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.1.8", + "defu": "^6.1.4", + "dotenv": "^16.4.7", + "giget": "^1.2.4", + "jiti": "^2.4.2", + "mlly": "^1.7.4", + "ohash": "^2.0.4", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^1.3.1", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/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" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "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" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/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/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", + "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/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-copy": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", + "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", + "license": "MIT" + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/giget": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.5.tgz", + "integrity": "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.5.4", + "pathe": "^2.0.3", + "tar": "^6.2.1" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/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", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", + "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/ioredis": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz", + "integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.5.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "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/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.9.tgz", + "integrity": "sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/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-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/nypm": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.5.4.tgz", + "integrity": "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "tinyexec": "^0.3.2", + "ufo": "^1.5.4" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "license": "MIT" + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.34.0.tgz", + "integrity": "sha512-yEr2jdGf4tVFYG6ohmr3pF6VJuveP0EA/sS8TBx+4Eq5NT10alu5zg2dmxMXMgqpihRDQlFGpRt2XwsGj+Fyxw==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/playwright": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/protobufjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "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" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@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/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shortid": { + "version": "2.2.17", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", + "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8" + } + }, + "node_modules/shortid/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/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/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "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" + } + }, + "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==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/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/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/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/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.59.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.0.tgz", + "integrity": "sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.59.0", + "@typescript-eslint/parser": "8.59.0", + "@typescript-eslint/typescript-estree": "8.59.0", + "@typescript-eslint/utils": "8.59.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, + "node_modules/uglify-js": { + "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": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vite": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitest": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@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", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.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" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/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", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json index b1c2405..dfae803 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "ai": "^6.0.161", "axiom": "^0.22.2", "ioredis": "^5.10.1", + "openai": "^6.34.0", "pino": "^10.3.1", "pino-pretty": "^13.1.3", "shortid": "^2.2.17", diff --git a/src/__tests__/config.test.ts b/src/__tests__/config.test.ts index 5a6f22c..f3e5f67 100644 --- a/src/__tests__/config.test.ts +++ b/src/__tests__/config.test.ts @@ -44,9 +44,9 @@ describe("config", () => { expect(getConfig().uploadBasePath).toBe("./second"); }); - it("getModelId returns default for each of the 7 keys", () => { + it("getModelId returns default for each DEFAULT_MODELS key", () => { const keys = Object.keys(DEFAULT_MODELS) as Array; - expect(keys).toHaveLength(7); + expect(keys.length).toBeGreaterThanOrEqual(7); for (const key of keys) { expect(getModelId(key)).toBe(DEFAULT_MODELS[key]); diff --git a/src/__tests__/cua-actions.test.ts b/src/__tests__/cua-actions.test.ts new file mode 100644 index 0000000..1c38054 --- /dev/null +++ b/src/__tests__/cua-actions.test.ts @@ -0,0 +1,164 @@ +import type { Page } from "@playwright/test"; +import { describe, it, expect, vi } from "vitest"; +import { executeAction, mapKey, type ComputerAction } from "../cua/actions"; + +type MouseStub = { + click: ReturnType; + dblclick: ReturnType; + move: ReturnType; + wheel: ReturnType; + down: ReturnType; + up: ReturnType; +}; + +type KeyboardStub = { + type: ReturnType; + press: ReturnType; +}; + +function makePage() { + const mouse: MouseStub = { + click: vi.fn().mockResolvedValue(undefined), + dblclick: vi.fn().mockResolvedValue(undefined), + move: vi.fn().mockResolvedValue(undefined), + wheel: vi.fn().mockResolvedValue(undefined), + down: vi.fn().mockResolvedValue(undefined), + up: vi.fn().mockResolvedValue(undefined), + }; + const keyboard: KeyboardStub = { + type: vi.fn().mockResolvedValue(undefined), + press: vi.fn().mockResolvedValue(undefined), + }; + const waitForTimeout = vi.fn().mockResolvedValue(undefined); + const page = { mouse, keyboard, waitForTimeout }; + return { page, mouse, keyboard, waitForTimeout }; +} + +describe("cua/actions/mapKey", () => { + it("maps OpenAI uppercase keys to Playwright names", () => { + expect(mapKey("ENTER")).toBe("Enter"); + expect(mapKey("CTRL")).toBe("Control"); + expect(mapKey("META")).toBe("Meta"); + expect(mapKey("CMD")).toBe("Meta"); + expect(mapKey("ARROWDOWN")).toBe("ArrowDown"); + expect(mapKey("UP")).toBe("ArrowUp"); + expect(mapKey("ESC")).toBe("Escape"); + }); + + it("passes unknown keys through unchanged", () => { + expect(mapKey("a")).toBe("a"); + expect(mapKey("1")).toBe("1"); + expect(mapKey("F5")).toBe("F5"); + }); + + it("is case-insensitive for mapped keys", () => { + expect(mapKey("enter")).toBe("Enter"); + expect(mapKey("Ctrl")).toBe("Control"); + }); +}); + +describe("cua/actions/executeAction", () => { + it("click calls page.mouse.click with coords and button", async () => { + const { page, mouse } = makePage(); + await executeAction(page as unknown as Page, { type: "click", x: 120, y: 80, button: "right" }); + expect(mouse.click).toHaveBeenCalledWith(120, 80, { button: "right" }); + }); + + it("click defaults to left button", async () => { + const { page, mouse } = makePage(); + await executeAction(page as unknown as Page, { type: "click", x: 10, y: 20 }); + expect(mouse.click).toHaveBeenCalledWith(10, 20, { button: "left" }); + }); + + it("double_click calls page.mouse.dblclick", async () => { + const { page, mouse } = makePage(); + await executeAction(page as unknown as Page, { type: "double_click", x: 50, y: 60 }); + expect(mouse.dblclick).toHaveBeenCalledWith(50, 60); + }); + + it("type calls page.keyboard.type with text", async () => { + const { page, keyboard } = makePage(); + await executeAction(page as unknown as Page, { type: "type", text: "hello world" }); + expect(keyboard.type).toHaveBeenCalledWith("hello world"); + }); + + it("keypress joins mapped keys with +", async () => { + const { page, keyboard } = makePage(); + await executeAction(page as unknown as Page, { type: "keypress", keys: ["CTRL", "A"] }); + expect(keyboard.press).toHaveBeenCalledWith("Control+A"); + }); + + it("keypress handles single Enter", async () => { + const { page, keyboard } = makePage(); + await executeAction(page as unknown as Page, { type: "keypress", keys: ["ENTER"] }); + expect(keyboard.press).toHaveBeenCalledWith("Enter"); + }); + + it("scroll moves then wheels", async () => { + const { page, mouse } = makePage(); + await executeAction(page as unknown as Page, { + type: "scroll", + x: 100, + y: 200, + scrollX: 0, + scrollY: 400, + }); + expect(mouse.move).toHaveBeenCalledWith(100, 200); + expect(mouse.wheel).toHaveBeenCalledWith(0, 400); + }); + + it("drag: tuple path triggers move+down, intermediate move, up", async () => { + const { page, mouse } = makePage(); + const action: ComputerAction = { + type: "drag", + path: [ + [10, 10] as [number, number], + [20, 20] as [number, number], + [30, 30] as [number, number], + ], + }; + await executeAction(page as unknown as Page, action); + expect(mouse.move).toHaveBeenNthCalledWith(1, 10, 10); + expect(mouse.down).toHaveBeenCalledOnce(); + expect(mouse.move).toHaveBeenNthCalledWith(2, 20, 20); + expect(mouse.move).toHaveBeenNthCalledWith(3, 30, 30); + expect(mouse.up).toHaveBeenCalledOnce(); + }); + + it("drag: object-shape path also works", async () => { + const { page, mouse } = makePage(); + await executeAction(page as unknown as Page, { + type: "drag", + path: [ + { x: 1, y: 2 }, + { x: 3, y: 4 }, + ], + }); + expect(mouse.move).toHaveBeenNthCalledWith(1, 1, 2); + expect(mouse.move).toHaveBeenNthCalledWith(2, 3, 4); + }); + + it("wait calls page.waitForTimeout", async () => { + const { page, waitForTimeout } = makePage(); + await executeAction(page as unknown as Page, { type: "wait" }); + expect(waitForTimeout).toHaveBeenCalledWith(1000); + }); + + it("screenshot is a no-op (loop captures separately)", async () => { + const { page, mouse, keyboard } = makePage(); + await executeAction(page as unknown as Page, { type: "screenshot" }); + expect(mouse.click).not.toHaveBeenCalled(); + expect(keyboard.type).not.toHaveBeenCalled(); + }); + + it("unknown action type is skipped without throwing", async () => { + const { page, mouse } = makePage(); + await expect( + executeAction( + page as unknown as Page, + { type: "quantum_leap", x: 1 } as unknown as ComputerAction, + ), + ).resolves.toBeUndefined(); + expect(mouse.click).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/cua-client.test.ts b/src/__tests__/cua-client.test.ts new file mode 100644 index 0000000..2a4830a --- /dev/null +++ b/src/__tests__/cua-client.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { configure, resetConfig } from "../config"; +import { getOpenAIClient, resetOpenAIClient } from "../cua/client"; +import { ConfigurationError } from "../errors"; + +describe("cua/client/getOpenAIClient", () => { + const originalEnv = process.env.OPENAI_API_KEY; + + beforeEach(() => { + resetConfig(); + resetOpenAIClient(); + }); + + afterEach(() => { + if (originalEnv === undefined) { + delete process.env.OPENAI_API_KEY; + } else { + process.env.OPENAI_API_KEY = originalEnv; + } + }); + + it("throws ConfigurationError when gateway is not 'none'", () => { + configure({ ai: { gateway: "openrouter", mode: "cua" } }); + process.env.OPENAI_API_KEY = "sk-test"; + expect(() => getOpenAIClient()).toThrow(ConfigurationError); + expect(() => getOpenAIClient()).toThrow(/gateway: "none"/); + }); + + it("throws ConfigurationError when OPENAI_API_KEY is missing", () => { + configure({ ai: { mode: "cua" } }); + delete process.env.OPENAI_API_KEY; + expect(() => getOpenAIClient()).toThrow(ConfigurationError); + expect(() => getOpenAIClient()).toThrow(/OPENAI_API_KEY/); + }); + + it("returns a client when gateway='none' and key is set", () => { + configure({ ai: { mode: "cua", gateway: "none" } }); + process.env.OPENAI_API_KEY = "sk-test"; + const client = getOpenAIClient(); + expect(client).toBeDefined(); + // Singleton: second call returns the same instance. + expect(getOpenAIClient()).toBe(client); + }); +}); diff --git a/src/__tests__/cua-config.test.ts b/src/__tests__/cua-config.test.ts new file mode 100644 index 0000000..a254562 --- /dev/null +++ b/src/__tests__/cua-config.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { configure, getMode, getModelId, resetConfig, DEFAULT_MODELS } from "../config"; + +describe("cua config", () => { + beforeEach(() => { + resetConfig(); + }); + + it("getMode defaults to snapshot", () => { + expect(getMode()).toBe("snapshot"); + }); + + it("configure sets mode to cua", () => { + configure({ ai: { mode: "cua" } }); + expect(getMode()).toBe("cua"); + }); + + it("mode survives merges with other config", () => { + configure({ ai: { mode: "cua" } }); + configure({ uploadBasePath: "./tmp" }); + expect(getMode()).toBe("cua"); + }); + + it("default cua model is gpt-5.4", () => { + expect(getModelId("cua")).toBe("gpt-5.4"); + expect(DEFAULT_MODELS.cua).toBe("gpt-5.4"); + }); + + it("user can override cua model id", () => { + configure({ ai: { models: { cua: "custom-cua-model" } } }); + expect(getModelId("cua")).toBe("custom-cua-model"); + }); +}); diff --git a/src/__tests__/cua-loop.test.ts b/src/__tests__/cua-loop.test.ts new file mode 100644 index 0000000..60132c3 --- /dev/null +++ b/src/__tests__/cua-loop.test.ts @@ -0,0 +1,176 @@ +import type { Page } from "@playwright/test"; +import type OpenAI from "openai"; +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { runCUALoop } from "../cua/loop"; +import { resetConfig } from "../config"; + +type ScriptedResponse = { + id: string; + output?: Array>; +}; + +function makePage() { + const screenshot = vi.fn().mockResolvedValue(Buffer.from("pngbytes")); + const mouse = { + click: vi.fn().mockResolvedValue(undefined), + dblclick: vi.fn().mockResolvedValue(undefined), + move: vi.fn().mockResolvedValue(undefined), + wheel: vi.fn().mockResolvedValue(undefined), + down: vi.fn().mockResolvedValue(undefined), + up: vi.fn().mockResolvedValue(undefined), + }; + const keyboard = { + type: vi.fn().mockResolvedValue(undefined), + press: vi.fn().mockResolvedValue(undefined), + }; + const waitForTimeout = vi.fn().mockResolvedValue(undefined); + const waitForLoadState = vi.fn().mockResolvedValue(undefined); + const evaluate = vi.fn().mockResolvedValue(undefined); + const viewportSize = vi.fn().mockReturnValue({ width: 1280, height: 720 }); + const page = { + screenshot, + mouse, + keyboard, + waitForTimeout, + waitForLoadState, + evaluate, + viewportSize, + }; + return { page, mouse, keyboard, screenshot }; +} + +function makeMockClient(scriptedResponses: ScriptedResponse[]) { + let i = 0; + const create = vi.fn().mockImplementation(async () => { + const r = scriptedResponses[i]; + i += 1; + return r; + }); + return { client: { responses: { create } }, create }; +} + +describe("cua/loop/runCUALoop", () => { + beforeEach(() => { + resetConfig(); + }); + + it("executes actions, screenshots back, and terminates when no computer_call", async () => { + const { page, mouse, keyboard } = makePage(); + const { client, create } = makeMockClient([ + { + id: "resp_1", + output: [ + { + type: "computer_call", + call_id: "call_1", + actions: [{ type: "click", x: 100, y: 150 }], + }, + ], + }, + { + id: "resp_2", + output: [ + { + type: "computer_call", + call_id: "call_2", + actions: [{ type: "type", text: "hello" }], + }, + ], + }, + { + id: "resp_3", + output: [{ type: "message", content: [{ text: "All done." }] }], + }, + ]); + + const finalText = await runCUALoop({ + page: page as unknown as Page, + instruction: "click something and type hello", + maxSteps: 10, + client: client as unknown as OpenAI, + }); + + expect(mouse.click).toHaveBeenCalledWith(100, 150, { button: "left" }); + expect(keyboard.type).toHaveBeenCalledWith("hello"); + expect(finalText).toBe("All done."); + + // First call is the initial instruction; subsequent calls carry the screenshot back. + expect(create).toHaveBeenCalledTimes(3); + const firstArgs = create.mock.calls[0][0]; + expect(firstArgs.input).toEqual([ + { + type: "message", + role: "user", + content: [{ type: "input_text", text: "click something and type hello" }], + }, + ]); + expect(firstArgs.tools[0]).toEqual({ type: "computer" }); + + const secondArgs = create.mock.calls[1][0]; + expect(secondArgs.previous_response_id).toBe("resp_1"); + expect(secondArgs.input[0]).toMatchObject({ + type: "computer_call_output", + call_id: "call_1", + }); + expect(secondArgs.input[0].output.type).toBe("computer_screenshot"); + expect(secondArgs.input[0].output.image_url).toMatch(/^data:image\/png;base64,/); + }); + + it("respects maxSteps and exits if model never stops", async () => { + const { page } = makePage(); + const infiniteResponse = { + id: "resp_loop", + output: [ + { + type: "computer_call", + call_id: "c", + actions: [{ type: "wait" }], + }, + ], + }; + const { client, create } = makeMockClient([ + infiniteResponse, + infiniteResponse, + infiniteResponse, + infiniteResponse, + ]); + + await runCUALoop({ + page: page as unknown as Page, + instruction: "loop forever", + maxSteps: 3, + client: client as unknown as OpenAI, + }); + + // 1 initial + 3 screenshot turns = 4 calls. + expect(create).toHaveBeenCalledTimes(4); + }); + + it("fires onReasoning callback when response includes reasoning items", async () => { + const { page } = makePage(); + const { client } = makeMockClient([ + { + id: "r1", + output: [ + { type: "reasoning", summary: [{ text: "I see a login form." }] }, + { type: "computer_call", call_id: "c", actions: [{ type: "click", x: 1, y: 2 }] }, + ], + }, + { + id: "r2", + output: [{ type: "message", content: [{ text: "done" }] }], + }, + ]); + + const reasonings: string[] = []; + await runCUALoop({ + page: page as unknown as Page, + instruction: "click login", + maxSteps: 5, + onReasoning: (r) => reasonings.push(r), + client: client as unknown as OpenAI, + }); + + expect(reasonings).toContain("I see a login form."); + }); +}); diff --git a/src/config.ts b/src/config.ts index a3b8f88..ccd5f0b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,6 +11,14 @@ export type EmailProvider = { export type AIGateway = "vercel" | "openrouter" | "cloudflare" | "none"; +/** + * Execution mode for browser automation. + * - "snapshot" (default): ARIA accessibility snapshot + aria-ref locators (works with any gateway). + * - "cua": OpenAI Responses API with the built-in `computer` tool — visual, coordinate-based + * actions. Requires OPENAI_API_KEY and gateway: "none". + */ +export type AIMode = "snapshot" | "cua"; + export type ModelConfig = { /** Model for executing individual steps. Default: google/gemini-3-flash */ stepExecution?: string; @@ -26,6 +34,8 @@ export type ModelConfig = { assertionArbiter?: string; /** Model for data extraction, wait conditions, and lightweight tasks. Default: google/gemini-2.5-flash */ utility?: string; + /** Model for CUA mode (OpenAI Responses API + built-in `computer` tool). Default: gpt-5.4 */ + cua?: string; }; export const DEFAULT_MODELS: Required = { @@ -36,12 +46,14 @@ export const DEFAULT_MODELS: Required = { assertionSecondary: "google/gemini-3-flash", assertionArbiter: "google/gemini-3.1-pro-preview", utility: "google/gemini-2.5-flash", + cua: "gpt-5.4", }; type Config = { email?: EmailProvider; ai?: { gateway?: AIGateway; + mode?: AIMode; models?: ModelConfig; }; /** Base path for file uploads. Default: "./uploads" */ @@ -85,6 +97,14 @@ export function getModelId(key: keyof ModelConfig): string { return getConfig().ai?.models?.[key] ?? DEFAULT_MODELS[key]; } +/** + * Returns the configured execution mode ("snapshot" | "cua"). + * Defaults to "snapshot" so existing users see no behavior change. + */ +export function getMode(): AIMode { + return getConfig().ai?.mode ?? "snapshot"; +} + /** @internal Reset config to empty state. Used for testing only. */ export function resetConfig() { globalConfig = {}; diff --git a/src/cua/actions.ts b/src/cua/actions.ts new file mode 100644 index 0000000..0a9744f --- /dev/null +++ b/src/cua/actions.ts @@ -0,0 +1,147 @@ +import type { Page } from "@playwright/test"; +import { logger } from "../logger"; + +/** + * Shape of actions returned by OpenAI's Responses API `computer` tool. + * Keep this loose — the Responses API ships new action variants over time, and + * we prefer to log-and-skip unknowns rather than fail the whole step. + */ +export type ComputerAction = + | { type: "click"; x: number; y: number; button?: "left" | "right" | "middle"; keys?: string[] } + | { type: "double_click"; x: number; y: number; button?: "left" | "right" | "middle" } + | { type: "move"; x: number; y: number } + | { type: "scroll"; x: number; y: number; scrollX?: number; scrollY?: number } + | { type: "drag"; path: Array<[number, number] | { x: number; y: number }> } + | { type: "type"; text: string } + | { type: "keypress"; keys: string[] } + | { type: "screenshot" } + | { type: "wait" } + | { type: string; [k: string]: unknown }; + +/** + * Maps OpenAI CUA key names to Playwright key names. + * OpenAI uses uppercase words ("ENTER", "CTRL", "META"); Playwright expects + * casing like "Enter", "Control", "Meta". Anything not in this map falls + * through unchanged — single characters ("a", "1") already work in Playwright. + */ +export const KEY_NAME_MAP: Record = { + ENTER: "Enter", + RETURN: "Enter", + TAB: "Tab", + ESC: "Escape", + ESCAPE: "Escape", + SPACE: "Space", + BACKSPACE: "Backspace", + DELETE: "Delete", + SHIFT: "Shift", + CTRL: "Control", + CONTROL: "Control", + ALT: "Alt", + META: "Meta", + CMD: "Meta", + COMMAND: "Meta", + WIN: "Meta", + UP: "ArrowUp", + DOWN: "ArrowDown", + LEFT: "ArrowLeft", + RIGHT: "ArrowRight", + ARROWUP: "ArrowUp", + ARROWDOWN: "ArrowDown", + ARROWLEFT: "ArrowLeft", + ARROWRIGHT: "ArrowRight", + PAGEUP: "PageUp", + PAGEDOWN: "PageDown", + HOME: "Home", + END: "End", + INSERT: "Insert", +}; + +export function mapKey(key: string): string { + return KEY_NAME_MAP[key.toUpperCase()] ?? key; +} + +function normalizeDragPoint(p: [number, number] | { x: number; y: number }): { + x: number; + y: number; +} { + return Array.isArray(p) ? { x: p[0], y: p[1] } : p; +} + +/** + * Executes a single CUA action via Playwright's low-level mouse/keyboard APIs. + * Unknown action types are logged and skipped so a new OpenAI action variant + * doesn't crash an entire test run. + */ +export async function executeAction(page: Page, action: ComputerAction): Promise { + switch (action.type) { + case "click": { + const { + x, + y, + button = "left", + } = action as { x: number; y: number; button?: "left" | "right" | "middle" }; + await page.mouse.click(x, y, { button }); + return; + } + case "double_click": { + const { x, y } = action as { x: number; y: number }; + await page.mouse.dblclick(x, y); + return; + } + case "move": { + const { x, y } = action as { x: number; y: number }; + await page.mouse.move(x, y); + return; + } + case "scroll": { + const { + x, + y, + scrollX = 0, + scrollY = 0, + } = action as { + x: number; + y: number; + scrollX?: number; + scrollY?: number; + }; + await page.mouse.move(x, y); + await page.mouse.wheel(scrollX, scrollY); + return; + } + case "drag": { + const { path } = action as { + path: Array<[number, number] | { x: number; y: number }>; + }; + if (!path || path.length < 2) return; + const points = path.map(normalizeDragPoint); + await page.mouse.move(points[0].x, points[0].y); + await page.mouse.down(); + for (let i = 1; i < points.length; i++) { + await page.mouse.move(points[i].x, points[i].y); + } + await page.mouse.up(); + return; + } + case "type": { + const { text } = action as { text: string }; + await page.keyboard.type(text); + return; + } + case "keypress": { + const { keys } = action as { keys: string[] }; + if (!keys || keys.length === 0) return; + await page.keyboard.press(keys.map(mapKey).join("+")); + return; + } + case "screenshot": + // No-op: the loop captures a screenshot after every action batch anyway. + return; + case "wait": + await page.waitForTimeout(1000); + return; + default: + logger.warn(`[cua] Unknown action type "${action.type}" — skipping.`); + return; + } +} diff --git a/src/cua/client.ts b/src/cua/client.ts new file mode 100644 index 0000000..39aae0d --- /dev/null +++ b/src/cua/client.ts @@ -0,0 +1,38 @@ +import OpenAI from "openai"; +import { ConfigurationError } from "../errors"; +import { getConfig } from "../config"; + +let _client: OpenAI | null = null; + +/** + * Returns a lazy singleton OpenAI client for CUA mode. + * + * CUA requires direct OpenAI access (Responses API + built-in `computer` tool). + * Throws ConfigurationError if OPENAI_API_KEY is missing, or if the user has + * combined `mode: "cua"` with a non-"none" gateway (which would route through + * a proxy that does not expose the Responses API). + */ +export function getOpenAIClient(): OpenAI { + const gateway = getConfig().ai?.gateway ?? "none"; + if (gateway !== "none") { + throw new ConfigurationError( + `CUA mode requires gateway: "none" (got "${gateway}"). ` + + `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + + `Set configure({ ai: { mode: "cua", gateway: "none" } }) and provide OPENAI_API_KEY.`, + ); + } + if (!process.env.OPENAI_API_KEY) { + throw new ConfigurationError( + "OPENAI_API_KEY isn't set. CUA mode uses OpenAI's Responses API — add OPENAI_API_KEY to your environment.", + ); + } + if (!_client) { + _client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); + } + return _client; +} + +/** @internal Reset client singleton. Used for testing only. */ +export function resetOpenAIClient() { + _client = null; +} diff --git a/src/cua/index.ts b/src/cua/index.ts new file mode 100644 index 0000000..a1df263 --- /dev/null +++ b/src/cua/index.ts @@ -0,0 +1,4 @@ +export { runCUALoop, type RunCUALoopOptions } from "./loop"; +export { buildRunStepsPromptCUA, buildRunUserFlowPromptCUA } from "./prompts"; +export { executeAction, mapKey, KEY_NAME_MAP, type ComputerAction } from "./actions"; +export { getOpenAIClient, resetOpenAIClient } from "./client"; diff --git a/src/cua/loop.ts b/src/cua/loop.ts new file mode 100644 index 0000000..a259dee --- /dev/null +++ b/src/cua/loop.ts @@ -0,0 +1,229 @@ +import type { Page } from "@playwright/test"; +import type OpenAI from "openai"; +import { getModelId } from "../config"; +import { logger } from "../logger"; +import { waitForDOMStabilization } from "../utils"; +import { executeAction, type ComputerAction } from "./actions"; +import { getOpenAIClient } from "./client"; + +export type RunCUALoopOptions = { + page: Page; + /** Initial natural-language instruction sent to the model. */ + instruction: string; + /** Maximum number of computer_call turns before giving up. */ + maxSteps: number; + /** Abort the loop when this signal fires (maps to step/user-flow timeouts). */ + abortSignal?: AbortSignal; + /** Callback fired with any reasoning text surfaced in the model output. */ + onReasoning?: (reasoning: string) => void; + /** Optional override client (used by tests). */ + client?: OpenAI; +}; + +/** + * Minimal local types for the Responses-API CUA surface. The installed OpenAI + * SDK typings don't yet include the `computer` tool / `computer_call` item, so + * we describe just the fields we read. Extra/unknown fields pass through. + */ +type CUAOutputItem = { + type: string; + id?: string; + call_id?: string; + actions?: ComputerAction[]; + action?: ComputerAction; + summary?: Array<{ text?: string }>; + content?: Array<{ text?: string }>; + text?: string; +}; + +type CUAResponse = { + id: string; + output?: CUAOutputItem[]; + output_text?: string; +}; + +type OpenAIWithResponses = OpenAI & { + responses: { + create: (body: unknown, opts?: { signal?: AbortSignal }) => Promise; + }; +}; + +type OpenAIErrorLike = { + status?: number; + message?: string; + error?: unknown; + response?: { data?: unknown }; + body?: unknown; +}; + +/** + * CUA action-loop. + * + * Protocol (OpenAI Responses API): + * 1. Send initial instruction + the built-in `computer` tool. + * 2. Read response.output for a `computer_call` item — if absent, the model is done. + * 3. Execute each action in the call's `actions` array via Playwright. + * 4. Take a screenshot, send it back as `computer_call_output` with the same + * `call_id`, chaining via `previous_response_id`. + * 5. Loop until no more `computer_call` items (or maxSteps / abort). + */ +export async function runCUALoop({ + page, + instruction, + maxSteps, + abortSignal, + onReasoning, + client, +}: RunCUALoopOptions): Promise { + const openai = (client ?? getOpenAIClient()) as OpenAIWithResponses; + const model = getModelId("cua"); + + // Current (2026) API: gpt-5.4 uses the simpler `{ type: "computer" }` tool. + // The model infers display dimensions from the screenshots it receives, so + // no display_width/display_height/environment are sent in the tool spec. + // (The legacy `computer_use_preview` tool + `computer-use-preview` model is + // scheduled for shutdown on 2026-07-23.) + const tool = { type: "computer" }; + + const viewport = page.viewportSize() ?? { width: 1280, height: 720 }; + logger.debug( + `[cua] starting loop — model=${model} viewport=${viewport.width}x${viewport.height} maxSteps=${maxSteps}`, + ); + + const initialRequest = { + model, + tools: [tool], + input: [ + { + type: "message", + role: "user", + content: [{ type: "input_text", text: instruction }], + }, + ], + truncation: "auto", + }; + + let response: CUAResponse; + try { + response = await openai.responses.create(initialRequest, { signal: abortSignal }); + } catch (err: unknown) { + const e = err as OpenAIErrorLike; + logger.error( + `[cua] initial request failed: status=${e?.status ?? "?"} msg=${e?.message ?? err} ` + + `model=${model} tool=${JSON.stringify(tool)} ` + + `body=${JSON.stringify(e?.error ?? e?.response?.data ?? e?.body ?? {})}`, + ); + // A generic 400 with no `param` usually means the account lacks access to + // the CUA model or to the built-in `computer` tool on the Responses API. + if (e?.status === 400) { + logger.error( + `[cua] if no "param" detail is shown above, verify your OpenAI API key has access to "${model}" ` + + `and the built-in "computer" tool on the Responses API ` + + `(https://platform.openai.com/settings/organization/limits).`, + ); + } + throw err; + } + + for (let turn = 0; turn < maxSteps; turn++) { + if (abortSignal?.aborted) { + throw new Error("CUA loop aborted"); + } + + emitReasoning(response, onReasoning); + + const call = findComputerCall(response); + if (!call) { + logger.debug(`[cua] loop ended at turn=${turn} (no computer_call in output)`); + return extractFinalText(response); + } + + const actions = extractActions(call); + for (const action of actions) { + if (abortSignal?.aborted) throw new Error("CUA loop aborted"); + await executeAction(page, action); + } + + await waitForDOMStabilization(page).catch((err) => { + logger.debug(`[cua] waitForDOMStabilization failed (continuing): ${err}`); + }); + + const screenshotB64 = (await page.screenshot({ fullPage: false })).toString("base64"); + + response = await openai.responses.create( + { + model, + tools: [tool], + previous_response_id: response.id, + input: [ + { + type: "computer_call_output", + call_id: call.call_id, + output: { + type: "computer_screenshot", + image_url: `data:image/png;base64,${screenshotB64}`, + }, + }, + ], + truncation: "auto", + }, + { signal: abortSignal }, + ); + } + + logger.warn(`[cua] loop hit maxSteps=${maxSteps} without model stopping`); + return extractFinalText(response); +} + +/** + * Extracts any `message`/`output_text` content from the final response so + * callers (like `runUserFlow`) can feed it into the assertion-JSON parser. + * Returns "" if there's no text content. + */ +function extractFinalText(response: CUAResponse): string { + if (typeof response.output_text === "string" && response.output_text.length > 0) { + return response.output_text; + } + const output = response.output; + if (!Array.isArray(output)) return ""; + const parts: string[] = []; + for (const item of output) { + if (item.type === "message" && Array.isArray(item.content)) { + for (const c of item.content) { + if (typeof c?.text === "string") parts.push(c.text); + } + } else if (item.type === "output_text" && typeof item.text === "string") { + parts.push(item.text); + } + } + return parts.join("\n").trim(); +} + +function findComputerCall(response: CUAResponse): CUAOutputItem | null { + const output = response.output; + if (!Array.isArray(output)) return null; + return output.find((item) => item?.type === "computer_call") ?? null; +} + +/** + * A computer_call may carry either an `actions[]` array (newer shape) or a + * single `action` object (older shape). Normalize to an array. + */ +function extractActions(call: CUAOutputItem): ComputerAction[] { + if (Array.isArray(call.actions)) return call.actions; + if (call.action) return [call.action]; + return []; +} + +function emitReasoning(response: CUAResponse, onReasoning?: (r: string) => void) { + if (!onReasoning) return; + const output = response.output; + if (!Array.isArray(output)) return; + for (const item of output) { + if (item.type === "reasoning" && Array.isArray(item.summary)) { + for (const s of item.summary) { + if (typeof s?.text === "string") onReasoning(s.text); + } + } + } +} diff --git a/src/cua/prompts.ts b/src/cua/prompts.ts new file mode 100644 index 0000000..ba20196 --- /dev/null +++ b/src/cua/prompts.ts @@ -0,0 +1,118 @@ +import { RunStepsOptions, Step, UserFlowOptions } from "../types"; + +/** + * Build the instruction for a single step in CUA mode. + * + * Contract differs from the snapshot prompt: the model sees screenshots (not + * ARIA trees), has a single built-in `computer` tool, and issues coordinate-based + * actions. Keep the instruction concise — OpenAI's CUA model does its own visual + * reasoning, so we don't need to enumerate tools. + */ +export const buildRunStepsPromptCUA = ({ + auth, + userFlow, + step, + steps, + stepIndex, +}: Pick & { + step: Step; + stepIndex: number; +}): string => { + return ` +You are an expert QA agent testing a web application using OpenAI's computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. + + +${userFlow} + + +Execute **ONLY** the following step and stop immediately after it is done: + + +${step.description} + + + +Current Step Index: ${stepIndex + 1} out of ${steps.length} steps. + + +${ + stepIndex + 1 < steps.length + ? ` +(For context only — DO NOT execute.) Next step: "${steps[stepIndex + 1].description}" +` + : "" +} + +${ + step.data + ? ` +Use this data for the current step: ${JSON.stringify(step.data)} +` + : "" +} + +${ + auth + ? ` +If a login screen appears, use: +- Email: ${auth.email} +- Password: ${auth.password} +` + : "" +} + + +- Look at the current screenshot before acting. If the page is still loading, use the wait action. +- Perform only the current step. Stop as soon as the expected result is visible in the screenshot. +- If the step fails or produces a validation error, correct the input and retry once. +- Do not navigate to a new URL unless the step description explicitly says to. +- Keep individual action batches small so the screenshot loop can verify progress. + +`.trim(); +}; + +/** + * Build the instruction for a full user flow in CUA mode. + */ +export const buildRunUserFlowPromptCUA = ({ + userFlow, + steps, + assertion, +}: Pick): string => { + return ` +You are an expert QA agent testing a web application using OpenAI's computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. + + +${userFlow} + + +${ + steps + ? ` +Follow these steps in order: +${steps} +Stop once all steps are complete. +` + : "" +} + +${ + assertion + ? ` +${assertion} + + +When the flow is complete, evaluate the assertion and report: +- assertionPassed: boolean +- confidenceScore: 0-100 +- reasoning: short explanation` + : "" +} + + +- Inspect each screenshot before acting. +- Recover from transient errors (validation messages, slow loads) by retrying once. +- Stop as soon as the flow is complete — do not continue exploring the app. + +`.trim(); +}; diff --git a/src/index.ts b/src/index.ts index 820ff31..3bb3d56 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,7 +40,8 @@ import { replacePlaceholders, resolveEmailPlaceholders, } from "./data-cache"; -import { getConfig, getModelId } from "./config"; +import { getConfig, getMode, getModelId } from "./config"; +import { runCUALoop, buildRunStepsPromptCUA, buildRunUserFlowPromptCUA } from "./cua"; import { extractDataWithAI } from "./extract"; import { logger } from "./logger"; import { resolveModel } from "./models"; @@ -261,6 +262,76 @@ export const runSteps = async ({ } } + // CUA mode: use OpenAI Responses API + built-in `computer` tool instead of + // the ARIA-snapshot path. Coord-based actions aren't cacheable, so we skip + // the redis cache lookup and the Vercel AI SDK step. + if (getMode() === "cua") { + logger.debug(`Executing Step (CUA): ${step.description}`); + + let pageScreenshotBeforeApplyingAction = ""; + if (step.waitUntil) { + pageScreenshotBeforeApplyingAction = ( + await tabManager.active().screenshot({ fullPage: false }) + ).toString("base64"); + } + + try { + await maybeWithSpan( + { capability: "step_execution", step: "cua_loop" }, + () => + runCUALoop({ + page: tabManager.active(), + instruction: buildRunStepsPromptCUA({ + auth, + steps: processedSteps, + step, + userFlow, + stepIndex: i, + }), + maxSteps: STEP_EXECUTION_MAX_STEPS, + abortSignal: AbortSignal.timeout(STEP_EXECUTION_TIMEOUT), + onReasoning: onReasoning + ? (reasoning) => onReasoning({ id, reasoning }) + : undefined, + }), + ); + } catch (error: unknown) { + logger.error({ err: error }, `CUA step execution failed: ${step.description}`); + errorInStepExecution = error instanceof Error ? error.message : String(error); + stepThatFailed = step.description; + break; + } + + if (step.waitUntil) { + await waitForCondition({ + page: tabManager, + condition: step.waitUntil, + pageScreenshotBeforeApplyingAction, + previousSteps: processedSteps.slice(0, i), + currentStep: step, + nextStep: processedSteps[i + 1], + }); + } + + if (step.extract) { + const snapshot = await safeSnapshot(tabManager); + const url = tabManager.active().url(); + const extracted = await extractDataWithAI({ + snapshot, + url, + prompt: step.extract.prompt, + }); + const placeholderKey = `{{run.${step.extract.as}}}` as keyof typeof localValues; + (localValues as Record)[placeholderKey] = extracted; + logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); + } + + if (onStepEnd) { + onStepEnd({ id, description: step.description }); + } + continue; + } + // First check if the step is cached on redis const cachedStep = redis ? await redis.hgetall(`step:${userFlow}:${step.description}`) : {}; @@ -584,6 +655,47 @@ export const runUserFlow = async ({ }: UserFlowOptions) => { const abortController = new AbortController(); + // CUA mode: skip the Vercel AI SDK path entirely. Run the Responses API loop, + // then reuse the existing utility-model assertion parser on its final text. + if (getMode() === "cua") { + try { + const text = await maybeWithSpan( + { capability: "user_flow_execution", step: "cua_loop" }, + () => + runCUALoop({ + page, + instruction: buildRunUserFlowPromptCUA({ userFlow, steps, assertion }), + maxSteps: USER_FLOW_MAX_STEPS, + abortSignal: abortController.signal, + }), + ); + + if (assertion) { + const { output } = await generateText({ + model: resolveModel(getModelId("utility")), + prompt: `Convert the following text output into a valid JSON object with the specified properties:\n\n${text}`, + output: Output.object({ + schema: z.object({ + assertionPassed: z.boolean().describe("Indicates whether the assertion passed or not."), + confidenceScore: z + .number() + .describe("Confidence score of the assertion, between 0 and 100."), + reasoning: z + .string() + .describe("Brief explanation of the reasoning behind the assertion."), + }), + }), + }); + return output; + } + + return text; + } catch (error: unknown) { + logger.error({ err: error }, "Error during CUA user flow execution"); + return; + } + } + const model = effort === "low" ? resolveModel(getModelId("userFlowLow")) From 23fa025d3e8a292de9f3090bacd6d710d8c85694 Mon Sep 17 00:00:00 2001 From: aryanmishra55254 Date: Fri, 24 Apr 2026 16:54:41 +0530 Subject: [PATCH 05/33] fix: patch tar vulnerabilities via npm overrides - Override tar to ^7.5.0 to ensure latest patched version - Fixes CVE-2026-23745, CVE-2026-24842, CVE-2026-26960, CVE-2026-29786, CVE-2026-31802 - Resolves hardlink/symlink path traversal vulnerabilities in node-tar --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index b1c2405..6e616b9 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,9 @@ "node": ">=18.0.0" }, "packageManager": "pnpm@10.33.0", + "overrides": { + "tar": "^7.5.0" + }, "publishConfig": { "access": "public" } From 47bd6681d9801d24ec51ea3485a269b156d25d66 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 25 Apr 2026 17:07:34 +0530 Subject: [PATCH 06/33] Support browser navigate tool in CUA + lock CUA to gpt-5.4 --- pnpm-lock.yaml | 19 +++++++++++ src/__tests__/cua-config.test.ts | 9 ++++-- src/config.ts | 12 ++++++- src/cua/actions.ts | 6 ++++ src/cua/loop.ts | 54 +++++++++++++++++++++++++++++--- 5 files changed, 91 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee05715..db9c717 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,9 @@ importers: ioredis: specifier: ^5.10.1 version: 5.10.1 + openai: + specifier: ^6.34.0 + version: 6.34.0(zod@4.3.6) pino: specifier: ^10.3.1 version: 10.3.1 @@ -1798,6 +1801,18 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + openai@6.34.0: + resolution: {integrity: sha512-yEr2jdGf4tVFYG6ohmr3pF6VJuveP0EA/sS8TBx+4Eq5NT10alu5zg2dmxMXMgqpihRDQlFGpRt2XwsGj+Fyxw==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4135,6 +4150,10 @@ snapshots: dependencies: wrappy: 1.0.2 + openai@6.34.0(zod@4.3.6): + optionalDependencies: + zod: 4.3.6 + optionator@0.9.4: dependencies: deep-is: 0.1.4 diff --git a/src/__tests__/cua-config.test.ts b/src/__tests__/cua-config.test.ts index a254562..cd6867f 100644 --- a/src/__tests__/cua-config.test.ts +++ b/src/__tests__/cua-config.test.ts @@ -26,8 +26,11 @@ describe("cua config", () => { expect(DEFAULT_MODELS.cua).toBe("gpt-5.4"); }); - it("user can override cua model id", () => { - configure({ ai: { models: { cua: "custom-cua-model" } } }); - expect(getModelId("cua")).toBe("custom-cua-model"); + it("configure throws when user tries to override cua model", () => { + expect(() => + configure({ ai: { models: { cua: "custom-cua-model" } } }), + ).toThrow(/cua.*not user-configurable/); + // Default still wins. + expect(getModelId("cua")).toBe("gpt-5.4"); }); }); diff --git a/src/config.ts b/src/config.ts index ccd5f0b..c73959c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -34,7 +34,11 @@ export type ModelConfig = { assertionArbiter?: string; /** Model for data extraction, wait conditions, and lightweight tasks. Default: google/gemini-2.5-flash */ utility?: string; - /** Model for CUA mode (OpenAI Responses API + built-in `computer` tool). Default: gpt-5.4 */ + /** + * Model for CUA mode (OpenAI Responses API + built-in `computer` tool). + * Locked to "gpt-5.4" — passing this field to `configure()` currently throws. + * Override may be re-enabled in a future release. + */ cua?: string; }; @@ -77,6 +81,12 @@ let globalConfig: Config = {}; * ``` */ export function configure(config: Config) { + if (config.ai?.models?.cua !== undefined) { + throw new Error( + `[passmark] ai.models.cua is not user-configurable — CUA mode is locked to "${DEFAULT_MODELS.cua}". ` + + `Remove the "cua" field from configure({ ai: { models } }).`, + ); + } globalConfig = { ...globalConfig, ...config }; } diff --git a/src/cua/actions.ts b/src/cua/actions.ts index 0a9744f..1b41509 100644 --- a/src/cua/actions.ts +++ b/src/cua/actions.ts @@ -16,6 +16,7 @@ export type ComputerAction = | { type: "keypress"; keys: string[] } | { type: "screenshot" } | { type: "wait" } + | { type: "goto"; url: string } | { type: string; [k: string]: unknown }; /** @@ -140,6 +141,11 @@ export async function executeAction(page: Page, action: ComputerAction): Promise case "wait": await page.waitForTimeout(1000); return; + case "goto": { + const { url } = action as { url: string }; + await page.goto(url, { waitUntil: "domcontentloaded" }); + return; + } default: logger.warn(`[cua] Unknown action type "${action.type}" — skipping.`); return; diff --git a/src/cua/loop.ts b/src/cua/loop.ts index a259dee..102e8b3 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -110,16 +110,16 @@ export async function runCUALoop({ const e = err as OpenAIErrorLike; logger.error( `[cua] initial request failed: status=${e?.status ?? "?"} msg=${e?.message ?? err} ` + - `model=${model} tool=${JSON.stringify(tool)} ` + - `body=${JSON.stringify(e?.error ?? e?.response?.data ?? e?.body ?? {})}`, + `model=${model} tool=${JSON.stringify(tool)} ` + + `body=${JSON.stringify(e?.error ?? e?.response?.data ?? e?.body ?? {})}`, ); // A generic 400 with no `param` usually means the account lacks access to // the CUA model or to the built-in `computer` tool on the Responses API. if (e?.status === 400) { logger.error( `[cua] if no "param" detail is shown above, verify your OpenAI API key has access to "${model}" ` + - `and the built-in "computer" tool on the Responses API ` + - `(https://platform.openai.com/settings/organization/limits).`, + `and the built-in "computer" tool on the Responses API ` + + `(https://platform.openai.com/settings/organization/limits).`, ); } throw err; @@ -138,7 +138,7 @@ export async function runCUALoop({ return extractFinalText(response); } - const actions = extractActions(call); + const actions = rewriteAddressBarNavigation(extractActions(call)); for (const action of actions) { if (abortSignal?.aborted) throw new Error("CUA loop aborted"); await executeAction(page, action); @@ -215,6 +215,50 @@ function extractActions(call: CUAOutputItem): ComputerAction[] { return []; } +/** + * The CUA model often "navigates" by simulating the browser's address-bar + * shortcut: keypress(Ctrl/Cmd+L) → type(url) → keypress(Enter). Playwright + * drives the page directly and has no browser chrome, so those keypresses + * are no-ops and navigation never happens. Detect that 3-action pattern and + * collapse it into a single `goto` that uses page.goto() under the hood. + */ +function rewriteAddressBarNavigation(actions: ComputerAction[]): ComputerAction[] { + const result: ComputerAction[] = []; + for (let i = 0; i < actions.length; i++) { + const a = actions[i]; + const b = actions[i + 1]; + const c = actions[i + 2]; + if (isAddressBarFocus(a) && isUrlType(b) && isEnter(c)) { + const url = (b as { text: string }).text.trim(); + result.push({ type: "goto", url }); + logger.debug(`[cua] rewrote address-bar navigation pattern → goto ${url}`); + i += 2; + continue; + } + result.push(a); + } + return result; +} + +function isAddressBarFocus(action: ComputerAction | undefined): boolean { + if (!action || action.type !== "keypress") return false; + const keys = ((action as { keys?: string[] }).keys ?? []).map((k) => k.toUpperCase()); + if (keys.length !== 2 || !keys.includes("L")) return false; + return keys.some((k) => k === "CTRL" || k === "CONTROL" || k === "META" || k === "CMD" || k === "COMMAND"); +} + +function isUrlType(action: ComputerAction | undefined): boolean { + if (!action || action.type !== "type") return false; + const text = (action as { text?: string }).text; + return typeof text === "string" && /^https?:\/\//i.test(text.trim()); +} + +function isEnter(action: ComputerAction | undefined): boolean { + if (!action || action.type !== "keypress") return false; + const keys = ((action as { keys?: string[] }).keys ?? []).map((k) => k.toUpperCase()); + return keys.length === 1 && (keys[0] === "ENTER" || keys[0] === "RETURN"); +} + function emitReasoning(response: CUAResponse, onReasoning?: (r: string) => void) { if (!onReasoning) return; const output = response.output; From 7ee0db812f54568f5be25ebdd4695d75be87506b Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 25 Apr 2026 17:36:50 +0530 Subject: [PATCH 07/33] switch to gpt-5.5 for CUA and update prompt --- src/__tests__/cua-config.test.ts | 8 ++--- src/config.ts | 4 +-- src/cua/loop.ts | 1 + src/cua/prompts.ts | 53 +++++++++++++++----------------- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/__tests__/cua-config.test.ts b/src/__tests__/cua-config.test.ts index cd6867f..bd80de7 100644 --- a/src/__tests__/cua-config.test.ts +++ b/src/__tests__/cua-config.test.ts @@ -21,9 +21,9 @@ describe("cua config", () => { expect(getMode()).toBe("cua"); }); - it("default cua model is gpt-5.4", () => { - expect(getModelId("cua")).toBe("gpt-5.4"); - expect(DEFAULT_MODELS.cua).toBe("gpt-5.4"); + it("default cua model is gpt-5.5", () => { + expect(getModelId("cua")).toBe("gpt-5.5"); + expect(DEFAULT_MODELS.cua).toBe("gpt-5.5"); }); it("configure throws when user tries to override cua model", () => { @@ -31,6 +31,6 @@ describe("cua config", () => { configure({ ai: { models: { cua: "custom-cua-model" } } }), ).toThrow(/cua.*not user-configurable/); // Default still wins. - expect(getModelId("cua")).toBe("gpt-5.4"); + expect(getModelId("cua")).toBe("gpt-5.5"); }); }); diff --git a/src/config.ts b/src/config.ts index c73959c..fb59766 100644 --- a/src/config.ts +++ b/src/config.ts @@ -50,7 +50,7 @@ export const DEFAULT_MODELS: Required = { assertionSecondary: "google/gemini-3-flash", assertionArbiter: "google/gemini-3.1-pro-preview", utility: "google/gemini-2.5-flash", - cua: "gpt-5.4", + cua: "gpt-5.5", }; type Config = { @@ -84,7 +84,7 @@ export function configure(config: Config) { if (config.ai?.models?.cua !== undefined) { throw new Error( `[passmark] ai.models.cua is not user-configurable — CUA mode is locked to "${DEFAULT_MODELS.cua}". ` + - `Remove the "cua" field from configure({ ai: { models } }).`, + `Remove the "cua" field from configure({ ai: { models } }).`, ); } globalConfig = { ...globalConfig, ...config }; diff --git a/src/cua/loop.ts b/src/cua/loop.ts index 102e8b3..f03a9b0 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -92,6 +92,7 @@ export async function runCUALoop({ const initialRequest = { model, + reasoning: { effort: "medium" }, tools: [tool], input: [ { diff --git a/src/cua/prompts.ts b/src/cua/prompts.ts index ba20196..a266b03 100644 --- a/src/cua/prompts.ts +++ b/src/cua/prompts.ts @@ -19,7 +19,7 @@ export const buildRunStepsPromptCUA = ({ stepIndex: number; }): string => { return ` -You are an expert QA agent testing a web application using OpenAI's computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. +You are an expert QA agent testing a web application using computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. ${userFlow} @@ -35,38 +35,37 @@ ${step.description} Current Step Index: ${stepIndex + 1} out of ${steps.length} steps. -${ - stepIndex + 1 < steps.length - ? ` +${stepIndex + 1 < steps.length + ? ` (For context only — DO NOT execute.) Next step: "${steps[stepIndex + 1].description}" ` - : "" -} + : "" + } -${ - step.data - ? ` +${step.data + ? ` Use this data for the current step: ${JSON.stringify(step.data)} ` - : "" -} + : "" + } -${ - auth - ? ` +${auth + ? ` If a login screen appears, use: - Email: ${auth.email} - Password: ${auth.password} ` - : "" -} + : "" + } - Look at the current screenshot before acting. If the page is still loading, use the wait action. - Perform only the current step. Stop as soon as the expected result is visible in the screenshot. -- If the step fails or produces a validation error, correct the input and retry once. +- If the step fails or produces a validation error, correct the input and retry. - Do not navigate to a new URL unless the step description explicitly says to. - Keep individual action batches small so the screenshot loop can verify progress. +- If you see any unexpected pop-ups or modals, try to close them before proceeding. +- After you execute the step, analyze the returned screenshot. The step execution is considered successful only if the latest screenshot reflects the expected state after performing the step. If it doesn't, you must take a fresh screenshot and retry executing the step until the expected state is achieved. `.trim(); }; @@ -80,25 +79,23 @@ export const buildRunUserFlowPromptCUA = ({ assertion, }: Pick): string => { return ` -You are an expert QA agent testing a web application using OpenAI's computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. +You are an expert QA agent testing a web application using computer-use capabilities. You see the browser as screenshots and act by clicking, typing, scrolling, etc. ${userFlow} -${ - steps - ? ` +${steps + ? ` Follow these steps in order: ${steps} Stop once all steps are complete. ` - : "" -} + : "" + } -${ - assertion - ? ` +${assertion + ? ` ${assertion} @@ -106,8 +103,8 @@ When the flow is complete, evaluate the assertion and report: - assertionPassed: boolean - confidenceScore: 0-100 - reasoning: short explanation` - : "" -} + : "" + } - Inspect each screenshot before acting. From 4ea9a7dbf3827b9219f2abaac0373e01493c7076 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 25 Apr 2026 17:46:00 +0530 Subject: [PATCH 08/33] remove package-lock.json and update readme --- .env.example | 2 +- CHANGELOG.md | 4 +- README.md | 8 +- TROUBLESHOOTING.md | 3 +- package-lock.json | 8068 -------------------------------------------- src/config.ts | 2 +- src/cua/loop.ts | 2 +- 7 files changed, 10 insertions(+), 8079 deletions(-) delete mode 100644 package-lock.json diff --git a/.env.example b/.env.example index ac8a7e1..765ae7f 100644 --- a/.env.example +++ b/.env.example @@ -42,7 +42,7 @@ GOOGLE_GENERATIVE_AI_API_KEY=AIza... # Required only if ai.mode is set to "cua" in configure(). # CUA requires direct OpenAI access (gateway: "none") and an API key with -# access to the CUA model (default: gpt-5.4) and the built-in `computer` +# access to the CUA model (default: gpt-5.5) and the built-in `computer` # tool on the Responses API. # OPENAI_API_KEY=sk-... diff --git a/CHANGELOG.md b/CHANGELOG.md index 204684b..5dbea15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `maxRetries` option to `AssertionOptions` (default: `1`) to control how many times a failed assertion is retried with a fresh page snapshot and screenshot. Setting it to `0` disables retries. - `onRetry` callback to `AssertionOptions` that fires before each retry, receiving the retry index and the full `AssertionResult` from the previous attempt for debugging flaky assertions. -- **CUA mode** (`configure({ ai: { mode: "cua" } })`): execute `runSteps` and `runUserFlow` through OpenAI's Responses API with the built-in `computer` tool. Screenshot-driven, coordinate-based actions via Playwright's `page.mouse` / `page.keyboard`. Default mode remains `"snapshot"` so existing tests are unaffected. Requires `OPENAI_API_KEY` and `gateway: "none"`; Redis step caching is skipped in this mode because coordinate actions aren't portable across viewport sizes. -- `cua` model slot in `ModelConfig` (default: `gpt-5.4`). +- **CUA mode** (`configure({ ai: { mode: "cua" } })`): execute `runSteps` and `runUserFlow` through OpenAI's Responses API with the built-in `computer` tool. Screenshot-driven, coordinate-based actions via Playwright's `page.mouse` / `page.keyboard`. Requires `OPENAI_API_KEY` and `gateway: "none"`; Redis step caching is skipped in this mode because coordinate actions aren't portable across viewport sizes. +- `cua` model slot in `ModelConfig` (default: `gpt-5.5`). For now, you cannot override the CUA model. - `getMode()` helper and `AIMode` type exported from `src/config.ts`. ## [1.0.0] - 2026-03-27 diff --git a/README.md b/README.md index 0f69950..e126b73 100644 --- a/README.md +++ b/README.md @@ -114,15 +114,15 @@ configure({ }); ``` -Set `OPENAI_API_KEY` in your `.env`. Because CUA sees only the page screenshot (there is no browser address bar in the screenshot), use Playwright's `page.goto()` to land on the starting URL before calling `runSteps()`: +Set `OPENAI_API_KEY` in your `.env`. Then you can write tests like this: ```typescript test("Shopping cart tests", async ({ page }) => { - await page.goto("https://demo.vercel.store"); await runSteps({ page, userFlow: "Add product to cart", steps: [ + { description: "Navigate to https://demo.vercel.store" }, { description: "Click Acme Circles T-Shirt" }, { description: "Select color", data: { value: "White" } }, { description: "Add to cart", waitUntil: "My Cart is visible" }, @@ -135,7 +135,7 @@ test("Shopping cart tests", async ({ page }) => { Notes: -- CUA mode uses OpenAI's `gpt-5.4` + built-in `computer` tool. Override with `configure({ ai: { models: { cua: "..." } } })`. +- CUA mode uses OpenAI's `gpt-5.5` + built-in `computer` tool. Override with `configure({ ai: { models: { cua: "..." } } })`. - Redis step caching is skipped in CUA mode because coordinate actions aren't portable across viewport sizes. - `gateway: "vercel" | "openrouter" | "cloudflare"` is not compatible with CUA — the Responses-API `computer` tool is only exposed on direct OpenAI access. - Account requirements: your OpenAI API key must have access to the CUA model and the built-in `computer` tool on the Responses API. @@ -251,7 +251,7 @@ All models are configurable via `configure({ ai: { models: { ... } } })`: | `assertionSecondary` | `google/gemini-3-flash` | Secondary assertion model (Gemini) | | `assertionArbiter` | `google/gemini-3.1-pro-preview` | Arbiter for assertion disagreements | | `utility` | `google/gemini-2.5-flash` | Data extraction, wait conditions | -| `cua` | `gpt-5.4` | CUA mode — OpenAI Responses API with the built-in `computer` tool | +| `cua` | `gpt-5.5` | CUA mode — OpenAI Responses API with the built-in `computer` tool | ## Caching diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 7cb0bb8..04fec66 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -101,8 +101,7 @@ Fix: - **"CUA mode requires gateway: 'none'"** — CUA doesn't work through Vercel / OpenRouter / Cloudflare gateways (the Responses-API `computer` tool is only available on direct OpenAI access). Use `configure({ ai: { mode: "cua", gateway: "none" } })`. - **"OPENAI_API_KEY isn't set"** — add `OPENAI_API_KEY` to your environment / `.env`. - **Generic 400 with `param: null` in the error body** — your OpenAI API key likely doesn't have access to the CUA model or the built-in `computer` tool on the Responses API. Verify access at https://platform.openai.com/settings/organization/limits. -- **"Tool 'computer_use_preview' is not supported with gpt-5.4"** — you're on an old build. In the current API, `gpt-5.4` uses the new simpler tool shape `{ type: "computer" }`, not the legacy `computer_use_preview`. Rebuild from `main`. -- **Model can't complete a "Navigate to URL" step** — CUA has no browser chrome / address bar in its screenshot view, so it cannot type a URL. Use Playwright's `await page.goto(url)` before calling `runSteps()`. +- **"Tool 'computer_use_preview' is not supported with gpt-5.5"** — you're on an old build. In the current API, `gpt-5.5` uses the new simpler tool shape `{ type: "computer" }`, not the legacy `computer_use_preview`. Rebuild from `main`. ### 8) Enable debug logs diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 58deff4..0000000 --- a/package-lock.json +++ /dev/null @@ -1,8068 +0,0 @@ -{ - "name": "passmark", - "version": "1.0.8", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "passmark", - "version": "1.0.8", - "license": "FSL-1.1-Apache-2.0", - "dependencies": { - "@ai-sdk/anthropic": "^3.0.69", - "@ai-sdk/google": "^3.0.63", - "@ai-sdk/google-vertex": "^4.0.105", - "@ai-sdk/openai": "^3.0.52", - "@faker-js/faker": "^10.1.0", - "@openrouter/ai-sdk-provider": "^2.5.1", - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/exporter-trace-otlp-http": "^0.207.0", - "@opentelemetry/resources": "^2.2.0", - "@opentelemetry/sdk-trace-node": "^2.2.0", - "@opentelemetry/semantic-conventions": "^1.37.0", - "acorn": "^8.15.0", - "ai": "^6.0.161", - "axiom": "^0.22.2", - "ioredis": "^5.10.1", - "openai": "^6.34.0", - "pino": "^10.3.1", - "pino-pretty": "^13.1.3", - "shortid": "^2.2.17", - "uuid": "^13.0.0", - "zod": "^4.1.12" - }, - "devDependencies": { - "@eslint/js": "^10.0.1", - "@types/ioredis": "^4.28.10", - "@types/node": "^22.13.10", - "@types/shortid": "^2.2.0", - "@typescript-eslint/eslint-plugin": "^8.57.2", - "@typescript-eslint/parser": "^8.57.2", - "@vitest/coverage-v8": "^4.1.2", - "eslint": "^10.1.0", - "prettier": "^3.8.1", - "typescript": "^5.9.2", - "typescript-eslint": "^8.57.2", - "vitest": "^4.1.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@playwright/test": "^1.59.0", - "playwright-core": "^1.59.0" - } - }, - "node_modules/@ai-sdk/anthropic": { - "version": "3.0.71", - "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.71.tgz", - "integrity": "sha512-bUWOzrzR0gJKJO/PLGMR4uH2dqEgqGhrsCV+sSpk4KtOEnUQlfjZI/F7BFlqSvVpFbjdgYRRLysAeEZpJ6S1lg==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/gateway": { - "version": "3.0.104", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.104.tgz", - "integrity": "sha512-ZKX5n74io8VIRlhIMSLWVlvT3sXC8Z7cZ9GHuWBWZDVi96+62AIsWuLGvMfcBA1STYuSoDrp6rIziZmvrTq0TA==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23", - "@vercel/oidc": "3.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/google": { - "version": "3.0.64", - "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.64.tgz", - "integrity": "sha512-CbR82EgGPNrj/6q0HtclwuCqe0/pDShyv3nWDP/A9DroujzWXnLMlUJVrgPOsg4b40zQCwwVs2XSKCxvt/4QaA==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/google-vertex": { - "version": "4.0.112", - "resolved": "https://registry.npmjs.org/@ai-sdk/google-vertex/-/google-vertex-4.0.112.tgz", - "integrity": "sha512-cSfHCkM+9ZrFtQWIN1WlV93JPD+isGSdFxKj7u1L9m2aLVZajlXdcE41GL9hMt7ld7bZYE4NnZ+4VLxBAHE+Eg==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/anthropic": "3.0.71", - "@ai-sdk/google": "3.0.64", - "@ai-sdk/openai-compatible": "2.0.41", - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23", - "google-auth-library": "^10.5.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/openai": { - "version": "3.0.53", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.53.tgz", - "integrity": "sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/openai-compatible": { - "version": "2.0.41", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai-compatible/-/openai-compatible-2.0.41.tgz", - "integrity": "sha512-kNAGINk71AlOXx10Dq/PXw4t/9XjdK8uxfpVElRwtSFMdeSiLVt58p9TPx4/FJD+hxZuVhvxYj9r42osxWq79g==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/provider": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", - "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.23.tgz", - "integrity": "sha512-z8GlDaCmRSDlqkMF2f4/RFgWxdarvIbyuk+m6WXT1LYgsnGiXRJGTD2Z1+SDl3LqtFuRtGX1aghYvQLoHL/9pg==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@standard-schema/spec": "^1.1.0", - "eventsource-parser": "^3.0.6" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "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==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "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==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@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/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.5", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", - "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.5", - "debug": "^4.3.1", - "minimatch": "^10.2.4" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.5.tgz", - "integrity": "sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", - "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/js": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", - "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "eslint": "^10.0.0" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", - "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.1.tgz", - "integrity": "sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.2.1", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@faker-js/faker": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-10.4.0.tgz", - "integrity": "sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/fakerjs" - } - ], - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0", - "npm": ">=10" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", - "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/proto-loader": "^0.8.0", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", - "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", - "license": "Apache-2.0", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.5.3", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@ioredis/commands": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", - "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", - "license": "MIT" - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@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/@next/env": { - "version": "15.5.15", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.15.tgz", - "integrity": "sha512-vcmyu5/MyFzN7CdqRHO3uHO44p/QPCZkuTUXroeUmhNP8bL5PHFEhik22JUazt+CDDoD6EpBYRCaS2pISL+/hg==", - "license": "MIT" - }, - "node_modules/@openrouter/ai-sdk-provider": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@openrouter/ai-sdk-provider/-/ai-sdk-provider-2.8.0.tgz", - "integrity": "sha512-oDDW/0KMqz4suHVloB9sNv0YyKLGNYf1FTevXH6adDkid5dsmbbcYuiEsbIhpZSZtHa6o5AVjK1jEAfePOLxww==", - "license": "Apache-2.0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "ai": "^6.0.0", - "zod": "^3.25.0 || ^4.0.0" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.207.0.tgz", - "integrity": "sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/auto-instrumentations-node": { - "version": "0.60.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.60.1.tgz", - "integrity": "sha512-oMBVXiun0qWhj693Y24Ie+75q45YXHRFeH9vX/XBWKRNJIM/02ufjmNvmOdoHY0EPxU9rBmWCW82Uidf54iSPA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/instrumentation-amqplib": "^0.49.0", - "@opentelemetry/instrumentation-aws-lambda": "^0.53.0", - "@opentelemetry/instrumentation-aws-sdk": "^0.54.0", - "@opentelemetry/instrumentation-bunyan": "^0.48.0", - "@opentelemetry/instrumentation-cassandra-driver": "^0.48.0", - "@opentelemetry/instrumentation-connect": "^0.46.0", - "@opentelemetry/instrumentation-cucumber": "^0.17.0", - "@opentelemetry/instrumentation-dataloader": "^0.19.0", - "@opentelemetry/instrumentation-dns": "^0.46.0", - "@opentelemetry/instrumentation-express": "^0.51.0", - "@opentelemetry/instrumentation-fastify": "^0.47.0", - "@opentelemetry/instrumentation-fs": "^0.22.0", - "@opentelemetry/instrumentation-generic-pool": "^0.46.0", - "@opentelemetry/instrumentation-graphql": "^0.50.0", - "@opentelemetry/instrumentation-grpc": "^0.202.0", - "@opentelemetry/instrumentation-hapi": "^0.49.0", - "@opentelemetry/instrumentation-http": "^0.202.0", - "@opentelemetry/instrumentation-ioredis": "^0.50.0", - "@opentelemetry/instrumentation-kafkajs": "^0.11.0", - "@opentelemetry/instrumentation-knex": "^0.47.0", - "@opentelemetry/instrumentation-koa": "^0.50.1", - "@opentelemetry/instrumentation-lru-memoizer": "^0.47.0", - "@opentelemetry/instrumentation-memcached": "^0.46.0", - "@opentelemetry/instrumentation-mongodb": "^0.55.1", - "@opentelemetry/instrumentation-mongoose": "^0.49.0", - "@opentelemetry/instrumentation-mysql": "^0.48.0", - "@opentelemetry/instrumentation-mysql2": "^0.48.0", - "@opentelemetry/instrumentation-nestjs-core": "^0.48.0", - "@opentelemetry/instrumentation-net": "^0.46.1", - "@opentelemetry/instrumentation-oracledb": "^0.28.0", - "@opentelemetry/instrumentation-pg": "^0.54.0", - "@opentelemetry/instrumentation-pino": "^0.49.0", - "@opentelemetry/instrumentation-redis": "^0.49.1", - "@opentelemetry/instrumentation-redis-4": "^0.49.0", - "@opentelemetry/instrumentation-restify": "^0.48.1", - "@opentelemetry/instrumentation-router": "^0.47.0", - "@opentelemetry/instrumentation-runtime-node": "^0.16.0", - "@opentelemetry/instrumentation-socket.io": "^0.49.0", - "@opentelemetry/instrumentation-tedious": "^0.21.0", - "@opentelemetry/instrumentation-undici": "^0.13.1", - "@opentelemetry/instrumentation-winston": "^0.47.0", - "@opentelemetry/resource-detector-alibaba-cloud": "^0.31.2", - "@opentelemetry/resource-detector-aws": "^2.2.0", - "@opentelemetry/resource-detector-azure": "^0.9.0", - "@opentelemetry/resource-detector-container": "^0.7.2", - "@opentelemetry/resource-detector-gcp": "^0.36.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/sdk-node": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.4.1", - "@opentelemetry/core": "^2.0.0" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.7.0.tgz", - "integrity": "sha512-MWXggArM+Y11mPS8VOrqxOj+YMGQSRuvhM91eSBX4xFpJa05mpkeVvM8pPux5ElkEjV5RMgrkisrlP/R83SpBQ==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", - "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-grpc/-/exporter-logs-otlp-grpc-0.202.0.tgz", - "integrity": "sha512-Y84L8Yja/A2qjGEzC/To0yrMUXHrtwJzHtZ2za1/ulZplRe5QFsLNyHixIS42ZYUKuNyWMDgOFhnN2Pz5uThtg==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/sdk-logs": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.202.0.tgz", - "integrity": "sha512-mJWLkmoG+3r+SsYQC+sbWoy1rjowJhMhFvFULeIPTxSI+EZzKPya0+NZ3+vhhgx2UTybGQlye3FBtCH3o6Rejg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/sdk-logs": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-logs-otlp-proto/-/exporter-logs-otlp-proto-0.202.0.tgz", - "integrity": "sha512-qYwbmNWPkP7AbzX8o4DRu5bb/a0TWYNcpZc1NEAOhuV7pgBpAUPEClxRWPN94ulIia+PfQjzFGMaRwmLGmNP6g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-grpc/-/exporter-metrics-otlp-grpc-0.202.0.tgz", - "integrity": "sha512-/dq/rf4KCkTYoP+NyPXTE+5wjvfhAHSqK62vRsJ/IalG61VPQvwaL18yWcavbI+44ImQwtMeZxfIJSox7oQL0w==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-metrics": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-http/-/exporter-metrics-otlp-http-0.202.0.tgz", - "integrity": "sha512-ooYcrf/m9ZuVGpQnER7WRH+JZbDPD389HG7VS/EnvIEF5WpNYEqf+NdmtaAcs51d81QrytTYAubc5bVWi//28w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-metrics": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-metrics-otlp-proto/-/exporter-metrics-otlp-proto-0.202.0.tgz", - "integrity": "sha512-X0RpPpPjyCAmIq9tySZm0Hk3Ltw8KWsqeNq5I7gS9AR9RzbVHb/l+eiMI1CqSRvW9R47HXcUu/epmEzY8ebFAg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-metrics": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-metrics-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-prometheus": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.202.0.tgz", - "integrity": "sha512-6RvQqZHAPFiwL1OKRJe4ta6SgJx/g8or41B+OovVVEie3HeCDhDGL9S1VJNkBozUz6wTY8a47fQwdMrCOUdMhQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-metrics": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-prometheus/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.202.0.tgz", - "integrity": "sha512-d5wLdbNA3ahpSeD0I34vbDFMTh4vPsXemH0bKDXLeCVULCAjOJXuZmEiuRammiDgVvvX7CAb/IGLDz8d2QHvoA==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.207.0.tgz", - "integrity": "sha512-HSRBzXHIC7C8UfPQdu15zEEoBGv0yWkhEwxqgPCHVUKUQ9NLHVGXkVrf65Uaj7UwmAkC1gQfkuVYvLlD//AnUQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/otlp-exporter-base": "0.207.0", - "@opentelemetry/otlp-transformer": "0.207.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.202.0.tgz", - "integrity": "sha512-z3vzdMclCETGIn8uUBgpz7w651ftCiH2qh3cewhBk+rF0EYPNQ3mJvyxktLnKIBZ/ci0zUknAzzYC7LIIZmggQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-zipkin": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-2.0.1.tgz", - "integrity": "sha512-a9eeyHIipfdxzCfc2XPrE+/TI3wmrZUDFtG2RRXHSbZZULAny7SyybSvaDvS77a7iib5MPiAvluwVvbGTsHxsw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.202.0.tgz", - "integrity": "sha512-Uz3BxZWPgDwgHM2+vCKEQRh0R8WKrd/q6Tus1vThRClhlPO39Dyz7mDrOr6KuqGXAlBQ1e5Tnymzri4RMZNaWA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "import-in-the-middle": "^1.8.1", - "require-in-the-middle": "^7.1.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.49.0.tgz", - "integrity": "sha512-OCGkE+1JoUN+gOzs3u0GSa7GV//KX6NMKzaPchedae7ZwFVyyBQ8VECJngHgW3k/FLABFnq9Oiym2WZGiWugVQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-aws-lambda": { - "version": "0.53.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.53.1.tgz", - "integrity": "sha512-canWSwigcvxq2mIrrxAdj6Cf21ysoxpRoe1T4UGINlKuyvrFiYAKLVZlPqVgP2Dwh9w/5+6yGBouoDhO/dQ0Kg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/aws-lambda": "8.10.150" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-aws-sdk": { - "version": "0.54.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.54.0.tgz", - "integrity": "sha512-4XnXfpACX8fpOnt/D8d/1AFg3uOwBTG9TopQBuikDZJYUrLUSdT7UiotCFqAM/Z6hQJh72Jy3591C/OrmKct7A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/propagation-utils": "^0.31.2", - "@opentelemetry/semantic-conventions": "^1.31.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-bunyan": { - "version": "0.48.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.48.0.tgz", - "integrity": "sha512-Q6ay5CXIKuyejadPoLboz+jKumB3Zuxyk35ycFh9vfIeww3+mNRyMVj6KxHRS0Imbv9zhNbP3uyrUpvEMMyHuw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "^0.202.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@types/bunyan": "1.8.11" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-bunyan/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/instrumentation-cassandra-driver": { - "version": "0.48.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.48.0.tgz", - "integrity": "sha512-0dcX8Kx0S6ZAOknrbA+BBh1j5lg5F20W18m5VYoGUxkuLIUbWkQA3uaqeTfqbOwmnBmb1upDPUWPR+g5N12B4Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.46.0.tgz", - "integrity": "sha512-YNq/7M1JXnWRkpKPC9dbYZA36cg547gY0p1bijW7vuZJ9t5f3alo6w8TWtZwV/hOFtBGHDXVhKVfp2Mh6zVHjQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/connect": "3.4.38" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-cucumber": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.17.1.tgz", - "integrity": "sha512-s/18qxBzjEWcJ8BIPJx5oP6GCB7huOaQai3lpJRXe9AcRTOUn6Jzp6oOeY52GE2uvTebo9/3CurM8So2J96fag==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.19.0.tgz", - "integrity": "sha512-zIVRnRs3zDZCqStQcpIdRx3Dz9WXFSVj9qimqI7CRuKao9qnrZYUVQHvvVlLZX3JAg+nDC6JRS95zvbq50hj4A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-dns": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.46.0.tgz", - "integrity": "sha512-m8u72x2fSIjhP1ITJX9Ims3eR4Qn8ze+QWy9NHYO01JlmiMamoc9TfIOd4dyOtxVja4tjnkWceKQdlEH9F9BoA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.51.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.51.1.tgz", - "integrity": "sha512-cKmzev7RolYGedQ82hVUoH+74BP4E0xmhUCEagOxmW3aKilXYx01KwsNN6wnx3IXR7u2nlYugQsEsLLA4d829A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fastify": { - "version": "0.47.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.47.1.tgz", - "integrity": "sha512-zTVFju7I67wA7Y2ZJ9Gb5u3zqiXIx5Zcaa2KSapal6VZ6gS8OkoC3t35M/6iazfBIPd9e1uCsonbm8jz8v+x1A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.22.0.tgz", - "integrity": "sha512-ktQVFD6pd8eAIW6t2DtDuXj2lxq+wnQ8WUkJLNZzl3rEE2TZEiHg7wIkWVoxl4Cz4pJ2YZJbdU2fHAizuDebDw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.46.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.46.1.tgz", - "integrity": "sha512-4rH/7nqxY2rnAodfP5nHMpwC6aFJUGRq9PZ44L5nUf+dxNyeuSPkuvxUr1tOf+qduqkhs2sZDP8/53n9/YmNzQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.50.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.50.0.tgz", - "integrity": "sha512-Nn3vBS5T0Dv4+9WF1dGR0Lgsxuz6ztQmTsxoHvesm6YAAXiHffnwsxBEJUKEJcjxfXzjO1SVuLDkv1bAeQ3NFw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-grpc": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.202.0.tgz", - "integrity": "sha512-dWvefHNAyAfaHVmxQ/ySLQSI2hGKLgK1sBtvae4w9xruqU08bBMtvmVeGMA/5whfiUDU8ftp1/84U4Zoe5N56A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "0.202.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.49.0.tgz", - "integrity": "sha512-d4BcCjbW7Pfg4FpbAAF0cK/ue3dN02WMw0uO2G792KzDjxj05MtZm3eBTz672j3ejV9hM0HvPPhUHUsIC0H6Gw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.202.0.tgz", - "integrity": "sha512-oX+jyY2KBg4/nVH3vZhSWDbhywkHgE0fq3YinhUBx0jv+YUWC2UKA7qLkxr/CSzfKsFi/Km0NKV+llH17yYGKw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/instrumentation": "0.202.0", - "@opentelemetry/semantic-conventions": "^1.29.0", - "forwarded-parse": "2.1.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.50.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.50.1.tgz", - "integrity": "sha512-HKrWKOM23qNwqNjWfzkw7mePversmcH5ac6T1dUdiRyJVYaLr4qfydyYkgKIGWHOF2TKvQGobXo3CjvxABQWVw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.38.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.11.0.tgz", - "integrity": "sha512-+i9VqVEPNObB1tkwcLV6zAafnve72h2Iwo48E11M/kVXMNXlgGhiYckYCmzba8c2u5XD/V98XZDrCIyO8CLCNA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.30.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.47.0.tgz", - "integrity": "sha512-OjqjnzXD5+FXVGkOznbRAz9yByb4UWzIUhXjuHvOQ50IUY8mv3rM2Gj6Ar7m5JsENiS5DtAy2Vfwk4e9zNC0ng==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.33.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.50.2.tgz", - "integrity": "sha512-+XTWg7a+u6lu4bm6HN0ItirTF0bBFUJlayqe+iVE87Cwpha7W47DV0aoNL8AzGPczlF1UQVVO0kvcfI8bnrkHw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.47.0.tgz", - "integrity": "sha512-UJ2UlCAIF+N4zNkiHdMr4O0caN0K6YboAso3/zaFdG1QiPR2zqZcbWAGFBikZ9HSByU+NwbxTXDzlpkcDZIqWg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-memcached": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.46.0.tgz", - "integrity": "sha512-FFDcOVJUxZQqbg57gVskZGXRfEsZXwOvCaPv6/qIZRw5glLXPTulpnfG/s8NAltsj2buXSvS4eKFo+0HKH0apw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/memcached": "^2.2.6" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.55.1.tgz", - "integrity": "sha512-Wb13YixWm8nB27ZSQW3h070UWkivoh6bjeyDUY6lLimSUulALr+YHBn0t71U1aTcUeaZv3IBNaPRimFXhz6gBA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.49.0.tgz", - "integrity": "sha512-nF+43QFe8IoW20TmTJZdxZhnVZGEglODUvzAo3fRmaBFAkwUXRGzRgABS255PCjIbScEaRRDCXc6EAsSkwRNPg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.48.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.48.1.tgz", - "integrity": "sha512-wP5+wIfQXmnKY4riKlx+1PiHpMSkG8Zu2cMXkiX6u84HqAWY62+N/Wv3fx9FU+/DU+fz3BdQQbo0EpVWziqqvg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/mysql": "2.15.27" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.48.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.48.1.tgz", - "integrity": "sha512-deJbaCC595WYhqDoXR5UfRx0bPmYyr1WhiFv6BjHRndMEUStHYYnsF6+mjpa3f0nebVj8Nv8eDcke4iTs7AfBw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@opentelemetry/sql-common": "^0.41.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-nestjs-core": { - "version": "0.48.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.48.1.tgz", - "integrity": "sha512-rH0IUQRf9wjxEkiPfltM17DVqgSe/rgeIlg1CKRDAhuxWkbXlcHwdOnBfngGKhJNGOlGUo6HzZesavPAlmm3Fw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.30.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-net": { - "version": "0.46.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.46.1.tgz", - "integrity": "sha512-r7Buqem+odrTTPlWfT7EqS24QnDAL4U+c4e38RzcRtdZF00Z34oqEpge7TZcQLo0vEASWbHQ/WjWNR7ZYKFKBA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-oracledb": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-oracledb/-/instrumentation-oracledb-0.28.0.tgz", - "integrity": "sha512-VObbQRd3g8nDLLOeGjm5l6TnB9dtEaJoedLfLwMGrlD6lkai+hdfalYh6FOF5dce+dJouZdW6NUUAaBj4f4KcA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/oracledb": "6.5.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.54.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.54.1.tgz", - "integrity": "sha512-vy2WbrB76iRpJccGCC7HNICVm+f5zg20dYBuB4r1X7TaXYsi1txrjvemOEH0h9lTpm2vVFoheHsVoClxleXvvQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@opentelemetry/sql-common": "^0.41.0", - "@types/pg": "8.15.4", - "@types/pg-pool": "2.0.6" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pino": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.49.1.tgz", - "integrity": "sha512-QTD4HQA0fhtu4Hvw9iIlnroDiQju8nmEmnTQrS3xrb6g9AsdBMYnXXyzNBlLpSvtqwfPvgAxfY4DY1IYtnNwDg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "^0.202.0", - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pino/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.49.1.tgz", - "integrity": "sha512-Ds5Ke9qE9kTlDThqLSJJntkIvuMQCBPiFKwHntocb/3q/9q5D47BNwawO5Mj9sVMV6zkld5M5Pb9Av39iieuOg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.37.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis-4": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.49.0.tgz", - "integrity": "sha512-i+Wsl7M2LXEDA2yXouNJ3fttSzzb5AhlehvSBVRIFuinY51XrrKSH66biO0eox+pYQMwAlPxJ778XcMQffN78A==", - "deprecated": "Use \"@opentelemetry/instrumentation-redis\", which (as of v0.50.0) includes support for instrumenting redis v4.", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/redis-common": "^0.37.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis-4/node_modules/@opentelemetry/redis-common": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.37.0.tgz", - "integrity": "sha512-tJwgE6jt32bLs/9J6jhQRKU2EZnsD8qaO13aoFyXwF6s4LhpT7YFHf3Z03MqdILk6BA2BFUhoyh7k9fj9i032A==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis/node_modules/@opentelemetry/redis-common": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.37.0.tgz", - "integrity": "sha512-tJwgE6jt32bLs/9J6jhQRKU2EZnsD8qaO13aoFyXwF6s4LhpT7YFHf3Z03MqdILk6BA2BFUhoyh7k9fj9i032A==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - } - }, - "node_modules/@opentelemetry/instrumentation-restify": { - "version": "0.48.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.48.2.tgz", - "integrity": "sha512-V+Bac9zMkQI7p1BsJV/jqg175nBs5aIpeh5HRHxrvlnDaH7TDlHDpax2i+sSrTHjSqxF/jeaIDDjuCW5C5WKbg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-router": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.47.0.tgz", - "integrity": "sha512-U0zA1LTDqtTWyd5e4SdoqQA/8QUOhc4LDv9U7b+8FMFTty95OF84apUdatl09Dzc51XeWPWIV7VutmSCd/zsUg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-runtime-node": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-runtime-node/-/instrumentation-runtime-node-0.16.0.tgz", - "integrity": "sha512-Q/GB9LsKLrRCEIPLAQTDQvydnLmLXBSRkYkWzwKzY/LCkOs+Cl8YiJG08p6D4CaJ6lvP0iG4kwPHk1ydNbdehg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-socket.io": { - "version": "0.49.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.49.0.tgz", - "integrity": "sha512-DpMtNBEcaLCcbP1WVBPCSgRiBs31igTQkal1gUm40VL/XAv5GUqRAUnvHZrQh3yPipOqzV65pdb0jJXdps/tug==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.21.1.tgz", - "integrity": "sha512-RDQyesAIJ3JHw8w5vthJjrzI3jTm/l6aeEQzIZ6cMG5hcW7ySPSyaxWbtmmp0FHPkdoGwc3Li+UQfV77+xLA1Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.202.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/tedious": "^4.0.14" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-undici": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.13.2.tgz", - "integrity": "sha512-rO8CNuHnVN13rKrXayvtuXMXwPQkem3H0r/UWZhyNGQeHlqlQgpgtu5mR9dzSuv9kLRrxZb/WjK+sGOP5kwetg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.7.0" - } - }, - "node_modules/@opentelemetry/instrumentation-winston": { - "version": "0.47.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.47.0.tgz", - "integrity": "sha512-r+GqnZU/aFldQyB5QdOlxsMlH9KZ4+zJfnYplz3lbC9f9ozAIlVAeoshvWTtbv7Oxp2NnK64EfnNP1pClaGEqA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "^0.202.0", - "@opentelemetry/instrumentation": "^0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-winston/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.207.0.tgz", - "integrity": "sha512-4RQluMVVGMrHok/3SVeSJ6EnRNkA2MINcX88sh+d/7DjGUrewW/WT88IsMEci0wUM+5ykTpPPNbEOoW+jwHnbw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/otlp-transformer": "0.207.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.202.0.tgz", - "integrity": "sha512-yIEHVxFA5dmYif7lZbbB66qulLLhrklj6mI2X3cuGW5hYPyUErztEmbroM+6teu/XobBi9bLHid2VT4NIaRuGg==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.207.0.tgz", - "integrity": "sha512-+6DRZLqM02uTIY5GASMZWUwr52sLfNiEe20+OEaZKhztCs3+2LxoTjb6JxFRd9q1qNqckXKYlUKjbH/AhG8/ZA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.207.0", - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/sdk-logs": "0.207.0", - "@opentelemetry/sdk-metrics": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/propagation-utils": { - "version": "0.31.18", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.31.18.tgz", - "integrity": "sha512-gIMtbHW+UvzOlnD/20e/zbYoDPRQch9kcevwniyO9GrdhSphaIQwoR6jFi4NvFjQpIoHGAwpNA7BcfRBgwAxPQ==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/propagator-b3": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-2.0.1.tgz", - "integrity": "sha512-Hc09CaQ8Tf5AGLmf449H726uRoBNGPBL4bjr7AnnUpzWMvhdn61F78z9qb6IqB737TffBsokGAK1XykFEZ1igw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/propagator-jaeger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-2.0.1.tgz", - "integrity": "sha512-7PMdPBmGVH2eQNb/AtSJizQNgeNTfh6jQFqys6lfhd6P4r+m/nTh3gKPPpaCXVdRQ+z93vfKk+4UGty390283w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/redis-common": { - "version": "0.38.3", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.38.3.tgz", - "integrity": "sha512-VCghU1JYs/4gP6Gqf/xro9MEsZ7LrMv2uONVsaESKL38ZOB9BqnI98FfS23wjMnHlpuE+TTaWSoAVNpTwYXzjw==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - } - }, - "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { - "version": "0.31.11", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.31.11.tgz", - "integrity": "sha512-R/asn6dAOWMfkLeEwqHCUz0cNbb9oiHVyd11iwlypeT/p9bR1lCX5juu5g/trOwxo62dbuFcDbBdKCJd3O2Edg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/resource-detector-aws": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-2.15.0.tgz", - "integrity": "sha512-+aiEkI+JA94XVIJtltt3XKYbLSaHRqHFdvGOwulBpfNKtEIWDEkKm3qfTl7Q0q9gY9621oXMU1sT5MM7koCnyA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/resource-detector-azure": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-azure/-/resource-detector-azure-0.9.0.tgz", - "integrity": "sha512-5wJwAAW2vhbqIhgaRisU1y0F5mUco59F/dKgmnnnT6YNbxjrbdUZYxKF5Wl7deJoACVdL5wi/3N97GCXPEwwCQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/resource-detector-container": { - "version": "0.7.11", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.7.11.tgz", - "integrity": "sha512-XUxnGuANa/EdxagipWMXKYFC7KURwed9/V0+NtYjFmwWHzV9/J4IYVGTK8cWDpyUvAQf/vE4sMa3rnS025ivXQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/resource-detector-gcp": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.36.0.tgz", - "integrity": "sha512-mWnEcg4tA+IDPrkETWo42psEsDN20dzYZSm4ZH8m8uiQALnNksVmf5C3An0GUEj5zrrxMasjSuv4zEH1gI40XQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^2.0.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "gcp-metadata": "^6.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.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", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources/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" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.207.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.207.0.tgz", - "integrity": "sha512-4MEQmn04y+WFe6cyzdrXf58hZxilvY59lzZj2AccuHW/+BxLn/rGVN/Irsi/F0qfBOpMOrrCLKTExoSL2zoQmg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.207.0", - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.2.0.tgz", - "integrity": "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.202.0.tgz", - "integrity": "sha512-SF9vXWVd9I5CZ69mW3GfwfLI2SHgyvEqntcg0en5y8kRp5+2PPoa3Mkgj0WzFLrbSgTw4PsXn7c7H6eSdrtV0w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/exporter-logs-otlp-grpc": "0.202.0", - "@opentelemetry/exporter-logs-otlp-http": "0.202.0", - "@opentelemetry/exporter-logs-otlp-proto": "0.202.0", - "@opentelemetry/exporter-metrics-otlp-grpc": "0.202.0", - "@opentelemetry/exporter-metrics-otlp-http": "0.202.0", - "@opentelemetry/exporter-metrics-otlp-proto": "0.202.0", - "@opentelemetry/exporter-prometheus": "0.202.0", - "@opentelemetry/exporter-trace-otlp-grpc": "0.202.0", - "@opentelemetry/exporter-trace-otlp-http": "0.202.0", - "@opentelemetry/exporter-trace-otlp-proto": "0.202.0", - "@opentelemetry/exporter-zipkin": "2.0.1", - "@opentelemetry/instrumentation": "0.202.0", - "@opentelemetry/propagator-b3": "2.0.1", - "@opentelemetry/propagator-jaeger": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "@opentelemetry/sdk-trace-node": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/context-async-hooks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.0.1.tgz", - "integrity": "sha512-XuY23lSI3d4PEqKA+7SLtAgwqIfc6E/E9eAQWLN1vlpC53ybO3o6jW4BsXo1xvz9lYyyWItfQDDLzezER01mCw==", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.202.0.tgz", - "integrity": "sha512-/hKE8DaFCJuaQqE1IxpgkcjOolUIwgi3TgHElPVKGdGRBSmJMTmN/cr6vWa55pCJIXPyhKvcMrbrya7DZ3VmzA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.0.1.tgz", - "integrity": "sha512-UhdbPF19pMpBtCWYP5lHbTogLWx9N0EBxtdagvkn5YtsAnCBZzL7SjktG+ZmupRgifsHMjwUaCCaVmqGfSADmA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/context-async-hooks": "2.0.1", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", - "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.7.0.tgz", - "integrity": "sha512-RrFHOXw0IYp/OThew6QORdybnnLitUAUMCJKcQNBYS0hDkCYarO2vTkVxfrGxCIqd5XHSMvbCpBd/T8ZMw8oSg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/context-async-hooks": "2.7.0", - "@opentelemetry/core": "2.7.0", - "@opentelemetry/sdk-trace-base": "2.7.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-node/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" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-node/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", - "@opentelemetry/resources": "2.7.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.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/@opentelemetry/sql-common": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.41.2.tgz", - "integrity": "sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", - "license": "MIT" - }, - "node_modules/@playwright/test": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", - "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "playwright": "1.59.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", - "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-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinclair/typebox": { - "version": "0.34.49", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", - "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", - "license": "MIT" - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@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/aws-lambda": { - "version": "8.10.150", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.150.tgz", - "integrity": "sha512-AX+AbjH/rH5ezX1fbK8onC/a+HyQHo7QGmvoxAE42n22OsciAxvZoZNEr22tbXs8WfP1nIsBjKDpgPm3HjOZbA==", - "license": "MIT" - }, - "node_modules/@types/bunyan": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.11.tgz", - "integrity": "sha512-758fRH7umIMk5qt5ELmRMff4mLDlN+xyYzC+dkPTdKwbSkJFvz6xwyScrytPU0QIBbRRwbiE8/BIg8bpajerNQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ioredis": { - "version": "4.28.10", - "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", - "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/memcached": { - "version": "2.2.10", - "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.10.tgz", - "integrity": "sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/mysql": { - "version": "2.15.27", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.27.tgz", - "integrity": "sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "22.19.17", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", - "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/oracledb": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@types/oracledb/-/oracledb-6.5.2.tgz", - "integrity": "sha512-kK1eBS/Adeyis+3OlBDMeQQuasIDLUYXsi2T15ccNJ0iyUpQ4xDF7svFu3+bGVrI0CMBUclPciz+lsQR3JX3TQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/pg": { - "version": "8.15.4", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.15.4.tgz", - "integrity": "sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/pg-pool": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", - "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", - "license": "MIT", - "dependencies": { - "@types/pg": "*" - } - }, - "node_modules/@types/shortid": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-2.2.0.tgz", - "integrity": "sha512-jBG2FgBxcaSf0h662YloTGA32M8UtNbnTPekUr/eCmWXq0JWQXgNEQ/P5Gf05Cv66QZtE1Ttr83I1AJBPdzCBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/tedious": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", - "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.0.tgz", - "integrity": "sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.59.0", - "@typescript-eslint/type-utils": "8.59.0", - "@typescript-eslint/utils": "8.59.0", - "@typescript-eslint/visitor-keys": "8.59.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.59.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.0.tgz", - "integrity": "sha512-TI1XGwKbDpo9tRW8UDIXCOeLk55qe9ZFGs8MTKU6/M08HWTw52DD/IYhfQtOEhEdPhLMT26Ka/x7p70nd3dzDg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.59.0", - "@typescript-eslint/types": "8.59.0", - "@typescript-eslint/typescript-estree": "8.59.0", - "@typescript-eslint/visitor-keys": "8.59.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.0.tgz", - "integrity": "sha512-Lw5ITrR5s5TbC19YSvlr63ZfLaJoU6vtKTHyB0GQOpX0W7d5/Ir6vUahWi/8Sps/nOukZQ0IB3SmlxZnjaKVnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.59.0", - "@typescript-eslint/types": "^8.59.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.0.tgz", - "integrity": "sha512-UzR16Ut8IpA3Mc4DbgAShlPPkVm8xXMWafXxB0BocaVRHs8ZGakAxGRskF7FId3sdk9lgGD73GSFaWmWFDE4dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.0", - "@typescript-eslint/visitor-keys": "8.59.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/tsconfig-utils": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.0.tgz", - "integrity": "sha512-91Sbl3s4Kb3SybliIY6muFBmHVv+pYXfybC4Oolp3dvk8BvIE3wOPc+403CWIT7mJNkfQRGtdqghzs2+Z91Tqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.0.tgz", - "integrity": "sha512-3TRiZaQSltGqGeNrJzzr1+8YcEobKH9rHnqIp/1psfKFmhRQDNMGP5hBufanYTGznwShzVLs3Mz+gDN7HkWfXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.0", - "@typescript-eslint/typescript-estree": "8.59.0", - "@typescript-eslint/utils": "8.59.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.0.tgz", - "integrity": "sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.0.tgz", - "integrity": "sha512-O9Re9P1BmBLFJyikRbQpLku/QA3/AueZNO9WePLBwQrvkixTmDe8u76B6CYUAITRl/rHawggEqUGn5QIkVRLMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.59.0", - "@typescript-eslint/tsconfig-utils": "8.59.0", - "@typescript-eslint/types": "8.59.0", - "@typescript-eslint/visitor-keys": "8.59.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.0.tgz", - "integrity": "sha512-I1R/K7V07XsMJ12Oaxg/O9GfrysGTmCRhvZJBv0RE0NcULMzjqVpR5kRRQjHsz3J/bElU7HwCO7zkqL+MSUz+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.59.0", - "@typescript-eslint/types": "8.59.0", - "@typescript-eslint/typescript-estree": "8.59.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.0.tgz", - "integrity": "sha512-/uejZt4dSere1bx12WLlPfv8GktzcaDtuJ7s42/HEZ5zGj9oxRaD4bj7qwSunXkf+pbAhFt2zjpHYUiT5lHf0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.59.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vercel/oidc": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.2.0.tgz", - "integrity": "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==", - "license": "Apache-2.0", - "engines": { - "node": ">= 20" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz", - "integrity": "sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.5", - "ast-v8-to-istanbul": "^1.0.0", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.2", - "obug": "^2.1.1", - "std-env": "^4.0.0-rc.1", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.1.5", - "vitest": "4.1.5" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", - "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.5", - "@vitest/utils": "4.1.5", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", - "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.1.5", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", - "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", - "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.5", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", - "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.5", - "@vitest/utils": "4.1.5", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", - "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", - "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.5", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "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", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ai": { - "version": "6.0.168", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.168.tgz", - "integrity": "sha512-2HqCJuO+1V2aV7vfYs5LFEUfxbkGX+5oa54q/gCCTL7KLTdbxcCu5D7TdLA5kwsrs3Szgjah9q6D9tpjHM3hUQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@ai-sdk/gateway": "3.0.104", - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.23", - "@opentelemetry/api": "1.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/ai/node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "1.0.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": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/axiom": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/axiom/-/axiom-0.22.2.tgz", - "integrity": "sha512-OlOudN3KM86YpOlOf5vuJHAVbYd5Xe9jnENIB30AvvNCFkxtAmUFW3OLC+svjjeurULRdjoKKRiFsUjBNlt6pA==", - "license": "MIT", - "dependencies": { - "@next/env": "^15.4.2", - "@opentelemetry/auto-instrumentations-node": "^0.60.1", - "@opentelemetry/context-async-hooks": "^2.0.1", - "@opentelemetry/exporter-trace-otlp-http": "^0.202.0", - "@opentelemetry/resources": "^2.0.1", - "@opentelemetry/sdk-trace-node": "^2.0.1", - "@opentelemetry/semantic-conventions": "^1.37.0", - "@sinclair/typebox": "^0.34.37", - "c12": "^2.0.4", - "commander": "^14.0.0", - "defu": "^6.1.4", - "handlebars": "^4.7.8", - "nanoid": "^5.1.5" - }, - "bin": { - "axiom": "dist/bin.js" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "zod": "^3.25.0 || ^4.0.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/api-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.202.0.tgz", - "integrity": "sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz", - "integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.202.0.tgz", - "integrity": "sha512-/hKE8DaFCJuaQqE1IxpgkcjOolUIwgi3TgHElPVKGdGRBSmJMTmN/cr6vWa55pCJIXPyhKvcMrbrya7DZ3VmzA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-exporter-base": "0.202.0", - "@opentelemetry/otlp-transformer": "0.202.0", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.202.0.tgz", - "integrity": "sha512-nMEOzel+pUFYuBJg2znGmHJWbmvMbdX5/RhoKNKowguMbURhz0fwik5tUKplLcUtl8wKPL1y9zPnPxeBn65N0Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/otlp-transformer": "0.202.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.202.0.tgz", - "integrity": "sha512-5XO77QFzs9WkexvJQL9ksxL8oVFb/dfi9NWQSq7Sv0Efr9x3N+nb1iklP1TeVgxqJ7m1xWiC/Uv3wupiQGevMw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/sdk-logs": "0.202.0", - "@opentelemetry/sdk-metrics": "2.0.1", - "@opentelemetry/sdk-trace-base": "2.0.1", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/resources": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz", - "integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/sdk-logs": { - "version": "0.202.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.202.0.tgz", - "integrity": "sha512-pv8QiQLQzk4X909YKm0lnW4hpuQg4zHwJ4XBd5bZiXcd9urvrJNoNVKnxGHPiDVX/GiLFvr5DMYsDBQbZCypRQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.202.0", - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/sdk-metrics": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.0.1.tgz", - "integrity": "sha512-wf8OaJoSnujMAHWR3g+/hGvNcsC16rf9s1So4JlMiFaFHiE4HpIA3oUh+uWZQ7CNuK8gVW/pQSkgoa5HkkOl0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/axiom/node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz", - "integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.0.1", - "@opentelemetry/resources": "2.0.1", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/axiom/node_modules/c12": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/c12/-/c12-2.0.4.tgz", - "integrity": "sha512-3DbbhnFt0fKJHxU4tEUPmD1ahWE4PWPMomqfYsTJdrhpmEnRKJi3qSC4rO5U6E6zN1+pjBY7+z8fUmNRMaVKLw==", - "license": "MIT", - "dependencies": { - "chokidar": "^4.0.3", - "confbox": "^0.1.8", - "defu": "^6.1.4", - "dotenv": "^16.4.7", - "giget": "^1.2.4", - "jiti": "^2.4.2", - "mlly": "^1.7.4", - "ohash": "^2.0.4", - "pathe": "^2.0.3", - "perfect-debounce": "^1.0.0", - "pkg-types": "^1.3.1", - "rc9": "^2.1.2" - }, - "peerDependencies": { - "magicast": "^0.3.5" - }, - "peerDependenciesMeta": { - "magicast": { - "optional": true - } - } - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/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" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/citty": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", - "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", - "license": "MIT", - "dependencies": { - "consola": "^3.2.3" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "license": "MIT" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "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" - } - }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "license": "MIT" - }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "license": "MIT" - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/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/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", - "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.5", - "@eslint/config-helpers": "^0.5.5", - "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.2", - "eslint-visitor-keys": "^5.0.1", - "espree": "^11.2.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.2.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", - "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", - "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.16.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", - "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/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-copy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz", - "integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/forwarded-parse": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", - "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", - "license": "MIT" - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gaxios": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", - "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/gaxios/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/gcp-metadata": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", - "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^6.1.1", - "google-logging-utils": "^0.0.2", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/giget": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.5.tgz", - "integrity": "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==", - "license": "MIT", - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.0", - "defu": "^6.1.4", - "node-fetch-native": "^1.6.6", - "nypm": "^0.5.4", - "pathe": "^2.0.3", - "tar": "^6.2.1" - }, - "bin": { - "giget": "dist/cli.mjs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/google-auth-library": { - "version": "10.6.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", - "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/google-auth-library/node_modules/gaxios": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", - "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/google-auth-library/node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/google-auth-library/node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/google-auth-library/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/google-logging-utils": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", - "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/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", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", - "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "license": "MIT" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-in-the-middle": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", - "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.14.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/ioredis": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.1.tgz", - "integrity": "sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==", - "license": "MIT", - "dependencies": { - "@ioredis/commands": "1.5.1", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "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/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "license": "MIT" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "license": "MIT" - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "license": "MIT" - }, - "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/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mlly": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", - "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", - "license": "MIT", - "dependencies": { - "acorn": "^8.16.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.3" - } - }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", - "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.9.tgz", - "integrity": "sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/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-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch-native": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", - "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "license": "MIT" - }, - "node_modules/nypm": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.5.4.tgz", - "integrity": "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==", - "license": "MIT", - "dependencies": { - "citty": "^0.1.6", - "consola": "^3.4.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "tinyexec": "^0.3.2", - "ufo": "^1.5.4" - }, - "bin": { - "nypm": "dist/cli.mjs" - }, - "engines": { - "node": "^14.16.0 || >=16.10.0" - } - }, - "node_modules/nypm/node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "license": "MIT" - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openai": { - "version": "6.34.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.34.0.tgz", - "integrity": "sha512-yEr2jdGf4tVFYG6ohmr3pF6VJuveP0EA/sS8TBx+4Eq5NT10alu5zg2dmxMXMgqpihRDQlFGpRt2XwsGj+Fyxw==", - "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, - "node_modules/perfect-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", - "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pino": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", - "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", - "license": "MIT", - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^4.0.0", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pump": "^3.0.0", - "secure-json-parse": "^4.0.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^5.0.2" - }, - "bin": { - "pino-pretty": "bin.js" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "license": "MIT" - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/playwright": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", - "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.59.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.59.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", - "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/protobufjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", - "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, - "node_modules/rc9": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", - "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", - "license": "MIT", - "dependencies": { - "defu": "^6.1.4", - "destr": "^2.0.3" - } - }, - "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" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "license": "MIT", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-in-the-middle": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", - "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3", - "resolve": "^1.22.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@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/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/secure-json-parse": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", - "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shortid": { - "version": "2.2.17", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", - "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8" - } - }, - "node_modules/shortid/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/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/sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "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" - } - }, - "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==", - "devOptional": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/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/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", - "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/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/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/thread-stream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", - "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", - "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/ts-api-utils": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", - "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.0.tgz", - "integrity": "sha512-BU3ONW9X+v90EcCH9ZS6LMackcVtxRLlI3XrYyqZIwVSHIk7Qf7bFw1z0M9Q0IUxhTMZCf8piY9hTYaNEIASrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", - "@typescript-eslint/typescript-estree": "8.59.0", - "@typescript-eslint/utils": "8.59.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "license": "MIT" - }, - "node_modules/uglify-js": { - "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": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", - "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/vite": { - "version": "8.0.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", - "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.10", - "rolldown": "1.0.0-rc.17", - "tinyglobby": "^0.2.16" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/vitest": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", - "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@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", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^4.0.0-rc.1", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.1.0", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.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" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/coverage-istanbul": { - "optional": true - }, - "@vitest/coverage-v8": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "vite": { - "optional": false - } - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/src/config.ts b/src/config.ts index fb59766..40da346 100644 --- a/src/config.ts +++ b/src/config.ts @@ -36,7 +36,7 @@ export type ModelConfig = { utility?: string; /** * Model for CUA mode (OpenAI Responses API + built-in `computer` tool). - * Locked to "gpt-5.4" — passing this field to `configure()` currently throws. + * Locked to "gpt-5.5" — passing this field to `configure()` currently throws. * Override may be re-enabled in a future release. */ cua?: string; diff --git a/src/cua/loop.ts b/src/cua/loop.ts index f03a9b0..2a6cbe3 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -78,7 +78,7 @@ export async function runCUALoop({ const openai = (client ?? getOpenAIClient()) as OpenAIWithResponses; const model = getModelId("cua"); - // Current (2026) API: gpt-5.4 uses the simpler `{ type: "computer" }` tool. + // Current (2026) API: gpt-5.5 uses the simpler `{ type: "computer" }` tool. // The model infers display dimensions from the screenshots it receives, so // no display_width/display_height/environment are sent in the tool spec. // (The legacy `computer_use_preview` tool + `computer-use-preview` model is From f5261a1a45d050f4d23c9aff5561edc0111bab8b Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 25 Apr 2026 17:47:43 +0530 Subject: [PATCH 09/33] 1.0.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dfae803..bfc69ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.8", + "version": "1.0.9", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From c700c9c962ee4a2eebe45af1b3cc16a6fc2cb53b Mon Sep 17 00:00:00 2001 From: Ipseeta Date: Sat, 25 Apr 2026 20:35:26 +0530 Subject: [PATCH 10/33] feat: support per-step and per-call AI overrides in runSteps/runUserFlow --- README.md | 25 ++++++- src/__tests__/cua-client.test.ts | 24 ++++--- src/__tests__/cua-config.test.ts | 62 ++++++++++++++++- src/__tests__/cua-loop.test.ts | 24 +++++++ src/__tests__/integration/run-steps.test.ts | 75 ++++++++++++++++++++- src/config.ts | 70 +++++++++++++++++-- src/cua/client.ts | 18 +++-- src/cua/loop.ts | 12 +++- src/index.ts | 31 ++++++--- src/models.ts | 11 ++- src/types.ts | 18 +++++ 11 files changed, 330 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e126b73..db8141f 100644 --- a/README.md +++ b/README.md @@ -135,11 +135,34 @@ test("Shopping cart tests", async ({ page }) => { Notes: -- CUA mode uses OpenAI's `gpt-5.5` + built-in `computer` tool. Override with `configure({ ai: { models: { cua: "..." } } })`. +- CUA mode uses OpenAI's `gpt-5.5` + built-in `computer` tool. The CUA model is currently locked and not user-configurable. - Redis step caching is skipped in CUA mode because coordinate actions aren't portable across viewport sizes. - `gateway: "vercel" | "openrouter" | "cloudflare"` is not compatible with CUA — the Responses-API `computer` tool is only exposed on direct OpenAI access. - Account requirements: your OpenAI API key must have access to the CUA model and the built-in `computer` tool on the Responses API. +#### Per-step overrides (hybrid runs) + +The same `ai` shape accepted by `configure()` can also be passed at the `runSteps`/`runUserFlow` call level **and** on individual `Step`s. This lets you mix snapshot steps (cheap, cacheable, OpenRouter/Vercel/etc.) with CUA steps (visual, direct OpenAI) in a single run. Precedence: `step.ai` ▶ call-level `ai` ▶ global `configure()`. + +```typescript +configure({ ai: { gateway: "openrouter" } }); // most steps go through OpenRouter + +await runSteps({ + page, test, expect, + userFlow: "Buy product on sale", + steps: [ + { description: "Navigate to /products" }, // OpenRouter snapshot + { + description: "Drag the price slider to $40", + ai: { mode: "cua", gateway: "none" }, // CUA for this step only + }, + { description: "Click Add to cart" }, // back to OpenRouter snapshot + ], +}); +``` + +Set `OPENAI_API_KEY` whenever any step opts into `mode: "cua"`. CUA steps still require `gateway: "none"`; mixing CUA with a non-`none` gateway throws at the per-step level for the same reason it does globally. + ## Features - **Core Execution** — `runSteps()` and `runUserFlow()` for flexible test orchestration in natural language, with smart caching and auto-healing diff --git a/src/__tests__/cua-client.test.ts b/src/__tests__/cua-client.test.ts index 2a4830a..a595473 100644 --- a/src/__tests__/cua-client.test.ts +++ b/src/__tests__/cua-client.test.ts @@ -19,26 +19,32 @@ describe("cua/client/getOpenAIClient", () => { } }); - it("throws ConfigurationError when gateway is not 'none'", () => { - configure({ ai: { gateway: "openrouter", mode: "cua" } }); + it("throws ConfigurationError when gateway argument is not 'none'", () => { process.env.OPENAI_API_KEY = "sk-test"; - expect(() => getOpenAIClient()).toThrow(ConfigurationError); - expect(() => getOpenAIClient()).toThrow(/gateway: "none"/); + expect(() => getOpenAIClient("openrouter")).toThrow(ConfigurationError); + expect(() => getOpenAIClient("openrouter")).toThrow(/gateway: "none"/); }); it("throws ConfigurationError when OPENAI_API_KEY is missing", () => { - configure({ ai: { mode: "cua" } }); delete process.env.OPENAI_API_KEY; expect(() => getOpenAIClient()).toThrow(ConfigurationError); expect(() => getOpenAIClient()).toThrow(/OPENAI_API_KEY/); }); - it("returns a client when gateway='none' and key is set", () => { - configure({ ai: { mode: "cua", gateway: "none" } }); + it("returns a client when gateway is 'none' and key is set", () => { process.env.OPENAI_API_KEY = "sk-test"; - const client = getOpenAIClient(); + const client = getOpenAIClient("none"); expect(client).toBeDefined(); // Singleton: second call returns the same instance. - expect(getOpenAIClient()).toBe(client); + expect(getOpenAIClient("none")).toBe(client); + }); + + it("succeeds with gateway='none' even when global gateway is non-none (hybrid case)", () => { + // Per-step override path: global says openrouter, but a CUA step resolves + // its gateway to 'none' and passes that explicitly. + configure({ ai: { gateway: "openrouter" } }); + process.env.OPENAI_API_KEY = "sk-test"; + const client = getOpenAIClient("none"); + expect(client).toBeDefined(); }); }); diff --git a/src/__tests__/cua-config.test.ts b/src/__tests__/cua-config.test.ts index bd80de7..83027f1 100644 --- a/src/__tests__/cua-config.test.ts +++ b/src/__tests__/cua-config.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach } from "vitest"; -import { configure, getMode, getModelId, resetConfig, DEFAULT_MODELS } from "../config"; +import { configure, getMode, getModelId, resetConfig, resolveAI, DEFAULT_MODELS } from "../config"; describe("cua config", () => { beforeEach(() => { @@ -34,3 +34,63 @@ describe("cua config", () => { expect(getModelId("cua")).toBe("gpt-5.5"); }); }); + +describe("resolveAI", () => { + beforeEach(() => { + resetConfig(); + }); + + it("returns global mode/gateway with no overrides", () => { + configure({ ai: { mode: "cua", gateway: "none" } }); + const r = resolveAI(); + expect(r.mode).toBe("cua"); + expect(r.gateway).toBe("none"); + }); + + it("falls back to defaults when nothing is configured", () => { + const r = resolveAI(); + expect(r.mode).toBe("snapshot"); + expect(r.gateway).toBe("none"); + }); + + it("override flips mode without touching global", () => { + configure({ ai: { gateway: "openrouter" } }); + const r = resolveAI({ mode: "cua", gateway: "none" }); + expect(r.mode).toBe("cua"); + expect(r.gateway).toBe("none"); + // Global is untouched. + expect(getMode()).toBe("snapshot"); + }); + + it("step override beats call override beats global", () => { + configure({ ai: { mode: "snapshot", gateway: "openrouter" } }); + const callLevel = { mode: "snapshot" as const, gateway: "vercel" as const }; + const stepLevel = { mode: "cua" as const, gateway: "none" as const }; + const r = resolveAI(callLevel, stepLevel); + expect(r.mode).toBe("cua"); + expect(r.gateway).toBe("none"); + }); + + it("layer-aware getModelId picks step > call > global > default", () => { + configure({ ai: { models: { stepExecution: "global/model" } } }); + const callLevel = { models: { stepExecution: "call/model" } }; + const stepLevel = { models: { stepExecution: "step/model" } }; + expect(resolveAI().getModelId("stepExecution")).toBe("global/model"); + expect(resolveAI(callLevel).getModelId("stepExecution")).toBe("call/model"); + expect(resolveAI(callLevel, stepLevel).getModelId("stepExecution")).toBe("step/model"); + // Falls through to DEFAULT_MODELS for keys nobody set. + expect(resolveAI().getModelId("utility")).toBe(DEFAULT_MODELS.utility); + }); + + it("throws when an override sets models.cua (lock applies per-layer)", () => { + expect(() => + resolveAI({ models: { cua: "custom-cua" } }), + ).toThrow(/cua.*not user-configurable/); + }); + + it("undefined override layers are ignored", () => { + configure({ ai: { mode: "cua" } }); + const r = resolveAI(undefined, undefined); + expect(r.mode).toBe("cua"); + }); +}); diff --git a/src/__tests__/cua-loop.test.ts b/src/__tests__/cua-loop.test.ts index 60132c3..19270fd 100644 --- a/src/__tests__/cua-loop.test.ts +++ b/src/__tests__/cua-loop.test.ts @@ -146,6 +146,30 @@ describe("cua/loop/runCUALoop", () => { expect(create).toHaveBeenCalledTimes(4); }); + it("uses provided model override instead of getModelId('cua')", async () => { + const { page } = makePage(); + const { client, create } = makeMockClient([ + { + id: "r1", + output: [{ type: "message", content: [{ text: "done" }] }], + }, + ]); + + // Sentinel — unique fake string just to prove the override flows into the + // request body. Not a real model name. + const sentinel = "fake-model-sentinel-for-override-test"; + await runCUALoop({ + page: page as unknown as Page, + instruction: "noop", + maxSteps: 1, + client: client as unknown as OpenAI, + model: sentinel, + }); + + const firstArgs = create.mock.calls[0][0]; + expect(firstArgs.model).toBe(sentinel); + }); + it("fires onReasoning callback when response includes reasoning items", async () => { const { page } = makePage(); const { client } = makeMockClient([ diff --git a/src/__tests__/integration/run-steps.test.ts b/src/__tests__/integration/run-steps.test.ts index c3edc40..f45a7a9 100644 --- a/src/__tests__/integration/run-steps.test.ts +++ b/src/__tests__/integration/run-steps.test.ts @@ -87,10 +87,18 @@ vi.mock("../../utils/secure-script-runner", () => ({ runSecureScript: vi.fn().mockResolvedValue(undefined), })); +// Mock the CUA module so runSteps' "mode: cua" branch is observable. +vi.mock("../../cua", () => ({ + runCUALoop: vi.fn().mockResolvedValue("cua-result"), + buildRunStepsPromptCUA: vi.fn().mockReturnValue("cua-prompt"), + buildRunUserFlowPromptCUA: vi.fn().mockReturnValue("cua-userflow-prompt"), +})); + import { runSteps } from "../../index"; -import { resetConfig } from "../../config"; +import { configure, resetConfig } from "../../config"; import { redis } from "../../redis"; import { generateText } from "ai"; +import { runCUALoop } from "../../cua"; import type { Page } from "@playwright/test"; import type { Step } from "../../types"; @@ -288,6 +296,71 @@ describe("runSteps", () => { ]); }); + it("routes per-step ai overrides — hybrid snapshot + CUA in one runSteps call", async () => { + const page = createMockPage(); + + // Global default: openrouter snapshot mode. Steps 1 and 3 should follow this + // (and hit generateText). Step 2 overrides to CUA + gateway:none and should + // hit runCUALoop instead. + configure({ ai: { gateway: "openrouter", mode: "snapshot" } }); + + const steps: Step[] = [ + { description: "Open product page" }, + { description: "Drag the price slider", ai: { mode: "cua", gateway: "none" } }, + { description: "Click add to cart" }, + ]; + + await runSteps({ + page, + userFlow: "hybrid flow", + steps, + }); + + expect(generateText).toHaveBeenCalledTimes(2); + expect(runCUALoop).toHaveBeenCalledTimes(1); + const cuaArgs = vi.mocked(runCUALoop).mock.calls[0][0]; + expect(cuaArgs.gateway).toBe("none"); + expect(cuaArgs.model).toBe("gpt-5.5"); + }); + + it("call-level ai option applies to all steps without per-step override", async () => { + const page = createMockPage(); + + const steps: Step[] = [ + { description: "Step A" }, + { description: "Step B" }, + ]; + + await runSteps({ + page, + userFlow: "all cua flow", + steps, + ai: { mode: "cua", gateway: "none" }, + }); + + expect(runCUALoop).toHaveBeenCalledTimes(2); + expect(generateText).not.toHaveBeenCalled(); + }); + + it("step.ai beats runSteps.ai (step override wins)", async () => { + const page = createMockPage(); + + const steps: Step[] = [ + { description: "Snapshot step", ai: { mode: "snapshot" } }, + { description: "CUA step (inherits call-level)" }, + ]; + + await runSteps({ + page, + userFlow: "mixed override flow", + steps, + ai: { mode: "cua", gateway: "none" }, + }); + + expect(generateText).toHaveBeenCalledTimes(1); + expect(runCUALoop).toHaveBeenCalledTimes(1); + }); + it("bypasses cache for individual step when step.bypassCache is true", async () => { const page = createMockPage(); diff --git a/src/config.ts b/src/config.ts index 40da346..82c6974 100644 --- a/src/config.ts +++ b/src/config.ts @@ -53,13 +53,21 @@ export const DEFAULT_MODELS: Required = { cua: "gpt-5.5", }; +/** + * Per-call / per-step override of the global `ai` config. Same shape as + * `Config["ai"]`, all fields optional. Used by `runSteps`, individual `Step`s, + * and `runUserFlow` to switch mode/gateway/models for part of a run without + * touching `configure()`. + */ +export type AIOverride = { + gateway?: AIGateway; + mode?: AIMode; + models?: ModelConfig; +}; + type Config = { email?: EmailProvider; - ai?: { - gateway?: AIGateway; - mode?: AIMode; - models?: ModelConfig; - }; + ai?: AIOverride; /** Base path for file uploads. Default: "./uploads" */ uploadBasePath?: string; }; @@ -115,6 +123,58 @@ export function getMode(): AIMode { return getConfig().ai?.mode ?? "snapshot"; } +/** + * Effective AI config for a single step / call after merging overrides with + * the global config. `getModelId` looks up a model with the same precedence + * as the layer search. + */ +export type ResolvedAI = { + mode: AIMode; + gateway: AIGateway; + getModelId: (key: keyof ModelConfig) => string; +}; + +const CUA_LOCK_MESSAGE = + `[passmark] ai.models.cua is not user-configurable — CUA mode is locked to "${DEFAULT_MODELS.cua}". ` + + `Remove the "cua" field from your ai config.`; + +/** + * Merge AI overrides into the global config. Later args win. + * + * Precedence (right-to-left): the last override wins, then earlier overrides, + * then the global `configure()` value, then `DEFAULT_MODELS`. + * + * Example: `resolveAI(callLevelAi, stepAi)` → step beats call beats global. + * + * Throws if any override sets `models.cua` (CUA model is locked, same rule + * `configure()` enforces). + */ +export function resolveAI(...overrides: (AIOverride | undefined)[]): ResolvedAI { + for (const layer of overrides) { + if (layer?.models?.cua !== undefined) { + throw new Error(CUA_LOCK_MESSAGE); + } + } + const layers: (AIOverride | undefined)[] = [getConfig().ai, ...overrides]; + const lastDefined = (key: K): AIOverride[K] => { + for (let i = layers.length - 1; i >= 0; i--) { + const v = layers[i]?.[key]; + if (v !== undefined) return v; + } + return undefined; + }; + const mode = (lastDefined("mode") as AIMode | undefined) ?? "snapshot"; + const gateway = (lastDefined("gateway") as AIGateway | undefined) ?? "none"; + const getModelIdForKey = (key: keyof ModelConfig): string => { + for (let i = layers.length - 1; i >= 0; i--) { + const v = layers[i]?.models?.[key]; + if (v !== undefined) return v; + } + return DEFAULT_MODELS[key]; + }; + return { mode, gateway, getModelId: getModelIdForKey }; +} + /** @internal Reset config to empty state. Used for testing only. */ export function resetConfig() { globalConfig = {}; diff --git a/src/cua/client.ts b/src/cua/client.ts index 39aae0d..7b63d13 100644 --- a/src/cua/client.ts +++ b/src/cua/client.ts @@ -1,6 +1,6 @@ import OpenAI from "openai"; import { ConfigurationError } from "../errors"; -import { getConfig } from "../config"; +import type { AIGateway } from "../config"; let _client: OpenAI | null = null; @@ -8,17 +8,21 @@ let _client: OpenAI | null = null; * Returns a lazy singleton OpenAI client for CUA mode. * * CUA requires direct OpenAI access (Responses API + built-in `computer` tool). - * Throws ConfigurationError if OPENAI_API_KEY is missing, or if the user has - * combined `mode: "cua"` with a non-"none" gateway (which would route through - * a proxy that does not expose the Responses API). + * Throws ConfigurationError if OPENAI_API_KEY is missing, or if the resolved + * gateway for this call is not "none" (a non-"none" gateway routes through a + * proxy that does not expose the Responses API). + * + * @param gateway - The resolved gateway for this call (defaults to "none"). + * Pass the per-step / per-call resolved gateway, not the global one — this + * is what enables hybrid runs where the global gateway is `openrouter` but + * one step opts into CUA with `gateway: "none"`. */ -export function getOpenAIClient(): OpenAI { - const gateway = getConfig().ai?.gateway ?? "none"; +export function getOpenAIClient(gateway: AIGateway = "none"): OpenAI { if (gateway !== "none") { throw new ConfigurationError( `CUA mode requires gateway: "none" (got "${gateway}"). ` + `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + - `Set configure({ ai: { mode: "cua", gateway: "none" } }) and provide OPENAI_API_KEY.`, + `Set ai: { mode: "cua", gateway: "none" } (per-step or via configure()) and provide OPENAI_API_KEY.`, ); } if (!process.env.OPENAI_API_KEY) { diff --git a/src/cua/loop.ts b/src/cua/loop.ts index 2a6cbe3..0fd5d58 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -1,6 +1,6 @@ import type { Page } from "@playwright/test"; import type OpenAI from "openai"; -import { getModelId } from "../config"; +import { type AIGateway, getModelId } from "../config"; import { logger } from "../logger"; import { waitForDOMStabilization } from "../utils"; import { executeAction, type ComputerAction } from "./actions"; @@ -18,6 +18,10 @@ export type RunCUALoopOptions = { onReasoning?: (reasoning: string) => void; /** Optional override client (used by tests). */ client?: OpenAI; + /** Resolved CUA model id. Defaults to `getModelId("cua")` when omitted. */ + model?: string; + /** Resolved gateway for this call. Defaults to "none". */ + gateway?: AIGateway; }; /** @@ -74,9 +78,11 @@ export async function runCUALoop({ abortSignal, onReasoning, client, + model: modelOverride, + gateway, }: RunCUALoopOptions): Promise { - const openai = (client ?? getOpenAIClient()) as OpenAIWithResponses; - const model = getModelId("cua"); + const openai = (client ?? getOpenAIClient(gateway ?? "none")) as OpenAIWithResponses; + const model = modelOverride ?? getModelId("cua"); // Current (2026) API: gpt-5.5 uses the simpler `{ type: "computer" }` tool. // The model infers display dimensions from the screenshots it receives, so diff --git a/src/index.ts b/src/index.ts index 3bb3d56..d5f3471 100644 --- a/src/index.ts +++ b/src/index.ts @@ -40,7 +40,7 @@ import { replacePlaceholders, resolveEmailPlaceholders, } from "./data-cache"; -import { getConfig, getMode, getModelId } from "./config"; +import { resolveAI } from "./config"; import { runCUALoop, buildRunStepsPromptCUA, buildRunUserFlowPromptCUA } from "./cua"; import { extractDataWithAI } from "./extract"; import { logger } from "./logger"; @@ -103,6 +103,7 @@ export const runSteps = async ({ projectId, executionId, failAssertionsSilently, + ai: callLevelAi, }: RunStepsOptions) => { executionId = executionId || process.env.executionId; @@ -175,6 +176,9 @@ export const runSteps = async ({ const step = await resolveEmailPlaceholders(currentStep, dynamicEmail); const id = shortid.generate(); + // Resolve effective AI config for this step. Step > runSteps call > global. + const effectiveAi = resolveAI(callLevelAi, step.ai); + if (onStepStart) { onStepStart({ id, description: step.description }); } @@ -265,7 +269,7 @@ export const runSteps = async ({ // CUA mode: use OpenAI Responses API + built-in `computer` tool instead of // the ARIA-snapshot path. Coord-based actions aren't cacheable, so we skip // the redis cache lookup and the Vercel AI SDK step. - if (getMode() === "cua") { + if (effectiveAi.mode === "cua") { logger.debug(`Executing Step (CUA): ${step.description}`); let pageScreenshotBeforeApplyingAction = ""; @@ -293,6 +297,8 @@ export const runSteps = async ({ onReasoning: onReasoning ? (reasoning) => onReasoning({ id, reasoning }) : undefined, + model: effectiveAi.getModelId("cua"), + gateway: effectiveAi.gateway, }), ); } catch (error: unknown) { @@ -455,9 +461,10 @@ export const runSteps = async ({ ); } - const model = resolveModel(getModelId("stepExecution")); + const stepModelId = effectiveAi.getModelId("stepExecution"); + const model = resolveModel(stepModelId, effectiveAi.gateway); logger.debug( - `Using model: ${getModelId("stepExecution")} for step execution / gateway: ${getConfig().ai?.gateway ?? "none"}`, + `Using model: ${stepModelId} for step execution / gateway: ${effectiveAi.gateway}`, ); try { @@ -652,12 +659,14 @@ export const runUserFlow = async ({ assertion, effort = "low", thinkingBudget = THINKING_BUDGET_DEFAULT, + ai: callLevelAi, }: UserFlowOptions) => { const abortController = new AbortController(); + const effectiveAi = resolveAI(callLevelAi); // CUA mode: skip the Vercel AI SDK path entirely. Run the Responses API loop, // then reuse the existing utility-model assertion parser on its final text. - if (getMode() === "cua") { + if (effectiveAi.mode === "cua") { try { const text = await maybeWithSpan( { capability: "user_flow_execution", step: "cua_loop" }, @@ -667,12 +676,14 @@ export const runUserFlow = async ({ instruction: buildRunUserFlowPromptCUA({ userFlow, steps, assertion }), maxSteps: USER_FLOW_MAX_STEPS, abortSignal: abortController.signal, + model: effectiveAi.getModelId("cua"), + gateway: effectiveAi.gateway, }), ); if (assertion) { const { output } = await generateText({ - model: resolveModel(getModelId("utility")), + model: resolveModel(effectiveAi.getModelId("utility"), effectiveAi.gateway), prompt: `Convert the following text output into a valid JSON object with the specified properties:\n\n${text}`, output: Output.object({ schema: z.object({ @@ -698,8 +709,8 @@ export const runUserFlow = async ({ const model = effort === "low" - ? resolveModel(getModelId("userFlowLow")) - : resolveModel(getModelId("userFlowHigh")); + ? resolveModel(effectiveAi.getModelId("userFlowLow"), effectiveAi.gateway) + : resolveModel(effectiveAi.getModelId("userFlowHigh"), effectiveAi.gateway); const { tools } = getAItools(page, { abortController, @@ -751,7 +762,7 @@ export const runUserFlow = async ({ if (assertion) { const { output } = await generateText({ - model: resolveModel(getModelId("utility")), + model: resolveModel(effectiveAi.getModelId("utility"), effectiveAi.gateway), prompt: `Convert the following text output into a valid JSON object with the specified properties:\n\n${text}`, output: Output.object({ schema: z.object({ @@ -816,7 +827,7 @@ export const executeWithAutoHealing = async (config: { }; export { configure } from "./config"; -export type { EmailProvider } from "./config"; +export type { EmailProvider, AIOverride, AIGateway, AIMode, ModelConfig } from "./config"; export { emailsinkProvider } from "./providers/emailsink"; export { extractEmailContent, generateEmail } from "./email"; diff --git a/src/models.ts b/src/models.ts index afc6fff..f326ea6 100644 --- a/src/models.ts +++ b/src/models.ts @@ -4,7 +4,7 @@ import { createGoogleGenerativeAI } from "@ai-sdk/google"; import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { gateway, type LanguageModel } from "ai"; import { wrapAISDKModel } from "axiom/ai"; -import { getConfig } from "./config"; +import { type AIGateway, getConfig } from "./config"; import { axiomEnabled } from "./instrumentation"; function wrapModel(model: LanguageModel): LanguageModel { @@ -163,9 +163,14 @@ function resolveOpenRouterModelId(modelId: string): string { * like Gemini's thought_signature pass through unchanged. * When gateway is "none" (default), creates a direct provider instance with alias resolution. * All paths wrap the model with wrapAISDKModel for tracing when Axiom is enabled. + * + * @param modelId - Canonical model id, e.g. "google/gemini-3-flash". + * @param gatewayOverride - Optional resolved gateway for this call. When omitted, + * falls back to the global `configure()` value. Pass this when a per-step or + * per-call `ai` override changes the gateway for a single resolution. */ -export function resolveModel(modelId: string): LanguageModel { - const gatewayConfig = getConfig().ai?.gateway ?? "none"; +export function resolveModel(modelId: string, gatewayOverride?: AIGateway): LanguageModel { + const gatewayConfig = gatewayOverride ?? getConfig().ai?.gateway ?? "none"; if (gatewayConfig === "vercel") { if (!process.env.AI_GATEWAY_API_KEY) { diff --git a/src/types.ts b/src/types.ts index abd4597..e4ff76e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,6 +8,7 @@ import { PlaywrightWorkerOptions, TestType, } from "@playwright/test"; +import type { AIOverride } from "./config"; import type { TabManager } from "./utils/tab-manager"; export type PageInput = Page | TabManager; @@ -32,6 +33,11 @@ export type UserFlowOptions = { password: string; }; model?: LanguageModel; + /** + * Override the AI mode/gateway/models for this user-flow run only. + * Falls back to the global `configure()` values when omitted. + */ + ai?: AIOverride; }; /** @@ -57,6 +63,12 @@ export type Step = { extract?: ExtractionConfig; /** Switch the active page before this step runs. 'main' = original tab, 'latest' = most recently opened, or numeric index. */ switchToTab?: "main" | "latest" | number; + /** + * Override the AI mode/gateway/models for just this step. Lets you mix + * snapshot and CUA steps in the same `runSteps` call. Beats both the + * `runSteps` call-level `ai` and the global `configure()` value. + */ + ai?: AIOverride; }; export type AssertionOptions = { @@ -116,6 +128,12 @@ export type RunStepsOptions = { * Required when using {{global.*}} placeholders. */ executionId?: string; + /** + * Default AI override applied to every step in this call. Individual + * `step.ai` overrides take precedence over this; this takes precedence + * over the global `configure()` value. + */ + ai?: AIOverride; } & ( | { assertions: Omit[]; From 7f431dc0d33c2f1510b875165198ef50300c5301 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Sat, 25 Apr 2026 23:08:37 +0530 Subject: [PATCH 11/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e126b73..7fc5bb6 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ test("Shopping cart tests", async ({ page }) => { Notes: -- CUA mode uses OpenAI's `gpt-5.5` + built-in `computer` tool. Override with `configure({ ai: { models: { cua: "..." } } })`. +- CUA mode uses OpenAI's `gpt-5.5` + built-in `computer` tool. - Redis step caching is skipped in CUA mode because coordinate actions aren't portable across viewport sizes. - `gateway: "vercel" | "openrouter" | "cloudflare"` is not compatible with CUA — the Responses-API `computer` tool is only exposed on direct OpenAI access. - Account requirements: your OpenAI API key must have access to the CUA model and the built-in `computer` tool on the Responses API. From e10b6e4151cb2a20fa4f251323c929557c35fe47 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 16:04:06 +0530 Subject: [PATCH 12/33] remove dead code --- src/__tests__/cua-loop.test.ts | 24 --------------------- src/__tests__/integration/run-steps.test.ts | 3 --- src/cua/loop.ts | 12 +++-------- src/index.ts | 4 ---- 4 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/__tests__/cua-loop.test.ts b/src/__tests__/cua-loop.test.ts index 19270fd..60132c3 100644 --- a/src/__tests__/cua-loop.test.ts +++ b/src/__tests__/cua-loop.test.ts @@ -146,30 +146,6 @@ describe("cua/loop/runCUALoop", () => { expect(create).toHaveBeenCalledTimes(4); }); - it("uses provided model override instead of getModelId('cua')", async () => { - const { page } = makePage(); - const { client, create } = makeMockClient([ - { - id: "r1", - output: [{ type: "message", content: [{ text: "done" }] }], - }, - ]); - - // Sentinel — unique fake string just to prove the override flows into the - // request body. Not a real model name. - const sentinel = "fake-model-sentinel-for-override-test"; - await runCUALoop({ - page: page as unknown as Page, - instruction: "noop", - maxSteps: 1, - client: client as unknown as OpenAI, - model: sentinel, - }); - - const firstArgs = create.mock.calls[0][0]; - expect(firstArgs.model).toBe(sentinel); - }); - it("fires onReasoning callback when response includes reasoning items", async () => { const { page } = makePage(); const { client } = makeMockClient([ diff --git a/src/__tests__/integration/run-steps.test.ts b/src/__tests__/integration/run-steps.test.ts index f45a7a9..e764417 100644 --- a/src/__tests__/integration/run-steps.test.ts +++ b/src/__tests__/integration/run-steps.test.ts @@ -318,9 +318,6 @@ describe("runSteps", () => { expect(generateText).toHaveBeenCalledTimes(2); expect(runCUALoop).toHaveBeenCalledTimes(1); - const cuaArgs = vi.mocked(runCUALoop).mock.calls[0][0]; - expect(cuaArgs.gateway).toBe("none"); - expect(cuaArgs.model).toBe("gpt-5.5"); }); it("call-level ai option applies to all steps without per-step override", async () => { diff --git a/src/cua/loop.ts b/src/cua/loop.ts index 0fd5d58..2a6cbe3 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -1,6 +1,6 @@ import type { Page } from "@playwright/test"; import type OpenAI from "openai"; -import { type AIGateway, getModelId } from "../config"; +import { getModelId } from "../config"; import { logger } from "../logger"; import { waitForDOMStabilization } from "../utils"; import { executeAction, type ComputerAction } from "./actions"; @@ -18,10 +18,6 @@ export type RunCUALoopOptions = { onReasoning?: (reasoning: string) => void; /** Optional override client (used by tests). */ client?: OpenAI; - /** Resolved CUA model id. Defaults to `getModelId("cua")` when omitted. */ - model?: string; - /** Resolved gateway for this call. Defaults to "none". */ - gateway?: AIGateway; }; /** @@ -78,11 +74,9 @@ export async function runCUALoop({ abortSignal, onReasoning, client, - model: modelOverride, - gateway, }: RunCUALoopOptions): Promise { - const openai = (client ?? getOpenAIClient(gateway ?? "none")) as OpenAIWithResponses; - const model = modelOverride ?? getModelId("cua"); + const openai = (client ?? getOpenAIClient()) as OpenAIWithResponses; + const model = getModelId("cua"); // Current (2026) API: gpt-5.5 uses the simpler `{ type: "computer" }` tool. // The model infers display dimensions from the screenshots it receives, so diff --git a/src/index.ts b/src/index.ts index d5f3471..6b43401 100644 --- a/src/index.ts +++ b/src/index.ts @@ -297,8 +297,6 @@ export const runSteps = async ({ onReasoning: onReasoning ? (reasoning) => onReasoning({ id, reasoning }) : undefined, - model: effectiveAi.getModelId("cua"), - gateway: effectiveAi.gateway, }), ); } catch (error: unknown) { @@ -676,8 +674,6 @@ export const runUserFlow = async ({ instruction: buildRunUserFlowPromptCUA({ userFlow, steps, assertion }), maxSteps: USER_FLOW_MAX_STEPS, abortSignal: abortController.signal, - model: effectiveAi.getModelId("cua"), - gateway: effectiveAi.gateway, }), ); From 4e05800974f482305e44795577ae29169d22ed0c Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 16:24:00 +0530 Subject: [PATCH 13/33] restore cua client logic --- src/__tests__/cua-client.test.ts | 24 ++++-------------------- src/cua/client.ts | 23 ++++++++++------------- 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/src/__tests__/cua-client.test.ts b/src/__tests__/cua-client.test.ts index a595473..ed5f010 100644 --- a/src/__tests__/cua-client.test.ts +++ b/src/__tests__/cua-client.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { configure, resetConfig } from "../config"; +import { resetConfig } from "../config"; import { getOpenAIClient, resetOpenAIClient } from "../cua/client"; import { ConfigurationError } from "../errors"; @@ -19,32 +19,16 @@ describe("cua/client/getOpenAIClient", () => { } }); - it("throws ConfigurationError when gateway argument is not 'none'", () => { - process.env.OPENAI_API_KEY = "sk-test"; - expect(() => getOpenAIClient("openrouter")).toThrow(ConfigurationError); - expect(() => getOpenAIClient("openrouter")).toThrow(/gateway: "none"/); - }); - it("throws ConfigurationError when OPENAI_API_KEY is missing", () => { delete process.env.OPENAI_API_KEY; expect(() => getOpenAIClient()).toThrow(ConfigurationError); expect(() => getOpenAIClient()).toThrow(/OPENAI_API_KEY/); }); - it("returns a client when gateway is 'none' and key is set", () => { - process.env.OPENAI_API_KEY = "sk-test"; - const client = getOpenAIClient("none"); - expect(client).toBeDefined(); - // Singleton: second call returns the same instance. - expect(getOpenAIClient("none")).toBe(client); - }); - - it("succeeds with gateway='none' even when global gateway is non-none (hybrid case)", () => { - // Per-step override path: global says openrouter, but a CUA step resolves - // its gateway to 'none' and passes that explicitly. - configure({ ai: { gateway: "openrouter" } }); + it("returns a client when key is set, and is a singleton", () => { process.env.OPENAI_API_KEY = "sk-test"; - const client = getOpenAIClient("none"); + const client = getOpenAIClient(); expect(client).toBeDefined(); + expect(getOpenAIClient()).toBe(client); }); }); diff --git a/src/cua/client.ts b/src/cua/client.ts index 7b63d13..f1c716c 100644 --- a/src/cua/client.ts +++ b/src/cua/client.ts @@ -1,30 +1,27 @@ import OpenAI from "openai"; import { ConfigurationError } from "../errors"; -import type { AIGateway } from "../config"; +import { getConfig } from "../config"; let _client: OpenAI | null = null; /** * Returns a lazy singleton OpenAI client for CUA mode. * - * CUA requires direct OpenAI access (Responses API + built-in `computer` tool). - * Throws ConfigurationError if OPENAI_API_KEY is missing, or if the resolved - * gateway for this call is not "none" (a non-"none" gateway routes through a - * proxy that does not expose the Responses API). - * - * @param gateway - The resolved gateway for this call (defaults to "none"). - * Pass the per-step / per-call resolved gateway, not the global one — this - * is what enables hybrid runs where the global gateway is `openrouter` but - * one step opts into CUA with `gateway: "none"`. + * CUA always hits OpenAI directly (Responses API + built-in `computer` tool); + * it cannot be routed through a gateway. Throws ConfigurationError if + * OPENAI_API_KEY is missing. */ -export function getOpenAIClient(gateway: AIGateway = "none"): OpenAI { +export function getOpenAIClient(): OpenAI { + const gateway = getConfig().ai?.gateway ?? "none"; if (gateway !== "none") { throw new ConfigurationError( `CUA mode requires gateway: "none" (got "${gateway}"). ` + - `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + - `Set ai: { mode: "cua", gateway: "none" } (per-step or via configure()) and provide OPENAI_API_KEY.`, + `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + + `Set configure({ ai: { mode: "cua", gateway: "none" } }) and provide OPENAI_API_KEY.` + + `Set ai: { mode: "cua", gateway: "none" } (per-step or via configure()) and provide OPENAI_API_KEY.`, ); } + if (!process.env.OPENAI_API_KEY) { throw new ConfigurationError( "OPENAI_API_KEY isn't set. CUA mode uses OpenAI's Responses API — add OPENAI_API_KEY to your environment.", From 65e387f4180e33cd35473f92324912ab7c531cf2 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 16:59:00 +0530 Subject: [PATCH 14/33] revert back to previous approach --- src/__tests__/cua-client.test.ts | 24 +++++++++++++++++---- src/__tests__/integration/run-steps.test.ts | 2 ++ src/cua/client.ts | 23 +++++++++++--------- src/cua/loop.ts | 7 ++++-- src/index.ts | 2 ++ 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/__tests__/cua-client.test.ts b/src/__tests__/cua-client.test.ts index ed5f010..a595473 100644 --- a/src/__tests__/cua-client.test.ts +++ b/src/__tests__/cua-client.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { resetConfig } from "../config"; +import { configure, resetConfig } from "../config"; import { getOpenAIClient, resetOpenAIClient } from "../cua/client"; import { ConfigurationError } from "../errors"; @@ -19,16 +19,32 @@ describe("cua/client/getOpenAIClient", () => { } }); + it("throws ConfigurationError when gateway argument is not 'none'", () => { + process.env.OPENAI_API_KEY = "sk-test"; + expect(() => getOpenAIClient("openrouter")).toThrow(ConfigurationError); + expect(() => getOpenAIClient("openrouter")).toThrow(/gateway: "none"/); + }); + it("throws ConfigurationError when OPENAI_API_KEY is missing", () => { delete process.env.OPENAI_API_KEY; expect(() => getOpenAIClient()).toThrow(ConfigurationError); expect(() => getOpenAIClient()).toThrow(/OPENAI_API_KEY/); }); - it("returns a client when key is set, and is a singleton", () => { + it("returns a client when gateway is 'none' and key is set", () => { + process.env.OPENAI_API_KEY = "sk-test"; + const client = getOpenAIClient("none"); + expect(client).toBeDefined(); + // Singleton: second call returns the same instance. + expect(getOpenAIClient("none")).toBe(client); + }); + + it("succeeds with gateway='none' even when global gateway is non-none (hybrid case)", () => { + // Per-step override path: global says openrouter, but a CUA step resolves + // its gateway to 'none' and passes that explicitly. + configure({ ai: { gateway: "openrouter" } }); process.env.OPENAI_API_KEY = "sk-test"; - const client = getOpenAIClient(); + const client = getOpenAIClient("none"); expect(client).toBeDefined(); - expect(getOpenAIClient()).toBe(client); }); }); diff --git a/src/__tests__/integration/run-steps.test.ts b/src/__tests__/integration/run-steps.test.ts index e764417..8151f8e 100644 --- a/src/__tests__/integration/run-steps.test.ts +++ b/src/__tests__/integration/run-steps.test.ts @@ -318,6 +318,8 @@ describe("runSteps", () => { expect(generateText).toHaveBeenCalledTimes(2); expect(runCUALoop).toHaveBeenCalledTimes(1); + const cuaArgs = vi.mocked(runCUALoop).mock.calls[0][0]; + expect(cuaArgs.gateway).toBe("none"); }); it("call-level ai option applies to all steps without per-step override", async () => { diff --git a/src/cua/client.ts b/src/cua/client.ts index f1c716c..7b63d13 100644 --- a/src/cua/client.ts +++ b/src/cua/client.ts @@ -1,27 +1,30 @@ import OpenAI from "openai"; import { ConfigurationError } from "../errors"; -import { getConfig } from "../config"; +import type { AIGateway } from "../config"; let _client: OpenAI | null = null; /** * Returns a lazy singleton OpenAI client for CUA mode. * - * CUA always hits OpenAI directly (Responses API + built-in `computer` tool); - * it cannot be routed through a gateway. Throws ConfigurationError if - * OPENAI_API_KEY is missing. + * CUA requires direct OpenAI access (Responses API + built-in `computer` tool). + * Throws ConfigurationError if OPENAI_API_KEY is missing, or if the resolved + * gateway for this call is not "none" (a non-"none" gateway routes through a + * proxy that does not expose the Responses API). + * + * @param gateway - The resolved gateway for this call (defaults to "none"). + * Pass the per-step / per-call resolved gateway, not the global one — this + * is what enables hybrid runs where the global gateway is `openrouter` but + * one step opts into CUA with `gateway: "none"`. */ -export function getOpenAIClient(): OpenAI { - const gateway = getConfig().ai?.gateway ?? "none"; +export function getOpenAIClient(gateway: AIGateway = "none"): OpenAI { if (gateway !== "none") { throw new ConfigurationError( `CUA mode requires gateway: "none" (got "${gateway}"). ` + - `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + - `Set configure({ ai: { mode: "cua", gateway: "none" } }) and provide OPENAI_API_KEY.` + - `Set ai: { mode: "cua", gateway: "none" } (per-step or via configure()) and provide OPENAI_API_KEY.`, + `The OpenAI Responses API computer tool is only available on direct OpenAI access. ` + + `Set ai: { mode: "cua", gateway: "none" } (per-step or via configure()) and provide OPENAI_API_KEY.`, ); } - if (!process.env.OPENAI_API_KEY) { throw new ConfigurationError( "OPENAI_API_KEY isn't set. CUA mode uses OpenAI's Responses API — add OPENAI_API_KEY to your environment.", diff --git a/src/cua/loop.ts b/src/cua/loop.ts index 2a6cbe3..463d2a2 100644 --- a/src/cua/loop.ts +++ b/src/cua/loop.ts @@ -1,6 +1,6 @@ import type { Page } from "@playwright/test"; import type OpenAI from "openai"; -import { getModelId } from "../config"; +import { type AIGateway, getModelId } from "../config"; import { logger } from "../logger"; import { waitForDOMStabilization } from "../utils"; import { executeAction, type ComputerAction } from "./actions"; @@ -18,6 +18,8 @@ export type RunCUALoopOptions = { onReasoning?: (reasoning: string) => void; /** Optional override client (used by tests). */ client?: OpenAI; + /** Resolved per-call gateway. Must be "none" for CUA. Defaults to "none". */ + gateway?: AIGateway; }; /** @@ -74,8 +76,9 @@ export async function runCUALoop({ abortSignal, onReasoning, client, + gateway, }: RunCUALoopOptions): Promise { - const openai = (client ?? getOpenAIClient()) as OpenAIWithResponses; + const openai = (client ?? getOpenAIClient(gateway ?? "none")) as OpenAIWithResponses; const model = getModelId("cua"); // Current (2026) API: gpt-5.5 uses the simpler `{ type: "computer" }` tool. diff --git a/src/index.ts b/src/index.ts index 6b43401..b05dbd7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -297,6 +297,7 @@ export const runSteps = async ({ onReasoning: onReasoning ? (reasoning) => onReasoning({ id, reasoning }) : undefined, + gateway: effectiveAi.gateway, }), ); } catch (error: unknown) { @@ -674,6 +675,7 @@ export const runUserFlow = async ({ instruction: buildRunUserFlowPromptCUA({ userFlow, steps, assertion }), maxSteps: USER_FLOW_MAX_STEPS, abortSignal: abortController.signal, + gateway: effectiveAi.gateway, }), ); From c9db56cb997c5c05cb91207557c750bdefd60bab Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 17:04:54 +0530 Subject: [PATCH 15/33] remove re-export of unneeded stuff from src/index.ts --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index b05dbd7..c069c9e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -825,7 +825,7 @@ export const executeWithAutoHealing = async (config: { }; export { configure } from "./config"; -export type { EmailProvider, AIOverride, AIGateway, AIMode, ModelConfig } from "./config"; +export type { EmailProvider } from "./config"; export { emailsinkProvider } from "./providers/emailsink"; export { extractEmailContent, generateEmail } from "./email"; From 7a78360b275062b57a35e5b699d03c4885443c76 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 17:07:54 +0530 Subject: [PATCH 16/33] 1.0.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bfc69ce..da9ac81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.9", + "version": "1.0.10", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From 9c32142a785cf764b02476080f6186570922350d Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 27 Apr 2026 21:56:15 +0530 Subject: [PATCH 17/33] fix an issue with waitForDOMStabilization which would crash tests if page reloads --- src/utils/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/utils/index.ts b/src/utils/index.ts index 10e431b..a637ec1 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -135,6 +135,16 @@ export async function waitForDOMStabilization( await resolvePage(input).evaluate( ({ idleTime, timeout }) => { return new Promise((resolve) => { + // document.body can be null mid-navigation (new document created, + // not parsed yet). MutationObserver.observe() would throw a + // TypeError on a null target — skip stabilization in that case; + // the caller's next step will trigger its own waits. + // @ts-expect-error document exists in browser context via page.evaluate + if (!document.body) { + resolve(); + return; + } + let timeoutId: ReturnType; // eslint-disable-next-line prefer-const let overallTimeoutId: ReturnType; From f0fba3e58e2b6ead4980185245bc57a405b4bec5 Mon Sep 17 00:00:00 2001 From: Shoaib Ansari Date: Sat, 2 May 2026 12:57:17 +0530 Subject: [PATCH 18/33] fix: support both absolute and relative paths in browser_upload_file Previously the browser_upload_file tool had a schema/implementation mismatch: the schema claimed to accept absolute paths but the implementation always prefixed with uploadBasePath, causing absolute paths like /tmp/file.png to become invalid (./uploads//tmp/file.png). - Extract resolveUploadPath() helper that detects absolute paths (Unix / or Windows C:\) and uses them as-is - Update Zod schema description to document both absolute/relative path support - Remove misleading inline comment - Add unit tests for all path resolution cases Closes #45 --- src/__tests__/upload-file.test.ts | 35 +++++++++++++++++++++++++++++++ src/tools.ts | 16 +++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 src/__tests__/upload-file.test.ts diff --git a/src/__tests__/upload-file.test.ts b/src/__tests__/upload-file.test.ts new file mode 100644 index 0000000..9382bb5 --- /dev/null +++ b/src/__tests__/upload-file.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "vitest"; +import { resolveUploadPath } from "../tools"; + +describe("resolveUploadPath", () => { + it("returns absolute Unix paths as-is", () => { + expect(resolveUploadPath("/tmp/file.png", "./uploads")).toBe("/tmp/file.png"); + expect(resolveUploadPath("/var/log/test.pdf", "./uploads")).toBe("/var/log/test.pdf"); + }); + + it("returns Windows absolute paths as-is", () => { + expect(resolveUploadPath("C:\\Users\\test\\file.png", "./uploads")).toBe("C:\\Users\\test\\file.png"); + expect(resolveUploadPath("D:\\data\\document.pdf", "./uploads")).toBe("D:\\data\\document.pdf"); + }); + + it("prefixes relative paths with uploadBasePath", () => { + expect(resolveUploadPath("file.png", "./uploads")).toBe("./uploads/file.png"); + expect(resolveUploadPath("document.pdf", "./uploads")).toBe("./uploads/document.pdf"); + }); + + it("uses custom uploadBasePath for relative paths", () => { + expect(resolveUploadPath("file.png", "/custom/uploads")).toBe("/custom/uploads/file.png"); + expect(resolveUploadPath("test.txt", "uploads")).toBe("uploads/test.txt"); + }); + + it("handles mixed arrays correctly", () => { + const paths = ["/tmp/a.png", "b.pdf", "C:\\data\\c.jpg"]; + const resolved = paths.map((p) => resolveUploadPath(p, "./uploads")); + expect(resolved).toEqual(["/tmp/a.png", "./uploads/b.pdf", "C:\\data\\c.jpg"]); + }); + + it("handles relative paths with subdirectories", () => { + expect(resolveUploadPath("folder/file.png", "./uploads")).toBe("./uploads/folder/file.png"); + expect(resolveUploadPath("uploads/test/document.pdf", "./uploads")).toBe("./uploads/uploads/test/document.pdf"); + }); +}); diff --git a/src/tools.ts b/src/tools.ts index 19d0bc6..3dbcddf 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -16,6 +16,12 @@ import { } from "@playwright/test"; import type { TabManager } from "./utils/tab-manager"; +export function resolveUploadPath(filePath: string, uploadBasePath: string): string { + return filePath.startsWith("/") || filePath.match(/^[A-Za-z]:/) + ? filePath + : `${uploadBasePath}/${filePath}`; +} + type ToolSettings = { abortController?: AbortController; currentStep?: { description: string; data?: Record }; @@ -559,7 +565,11 @@ class PlaywrightTools { public uploadFileSchema = z.object({ ref: z.string().describe('The ref of the "button" that triggers a FileChooser to upload files'), elementDescription: z.string().describe("A description of the element, used for debugging"), - filePaths: z.array(z.string()).describe("Array of absolute file paths to upload"), + filePaths: z + .array(z.string()) + .describe( + "Array of file paths to upload. Can be absolute paths (e.g., '/tmp/file.png') or relative paths (e.g., 'document.pdf' which will be resolved against uploadBasePath)", + ), reasoning: z.string().describe("A quick one-line reasoning behind this action"), doesActionAdvanceUsTowardsGoal: z .boolean() @@ -570,13 +580,13 @@ class PlaywrightTools { public async uploadFile({ ref, elementDescription, - filePaths, // This is not a full path. It accepts a string filename which should be available in `uploads` directory + filePaths, }: z.infer) { const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); // We expect to find these files in the `./uploads` directory if no base path is configured const uploadBasePath = getConfig().uploadBasePath || "./uploads"; - const prefixedFilePaths = filePaths.map((filePath) => `${uploadBasePath}/${filePath}`); + const prefixedFilePaths = filePaths.map((filePath) => resolveUploadPath(filePath, uploadBasePath)); // File uploads are not cached for now as it needs a two step process // We can solve this later by introducing multi-action caching if needed From b7d64342f5f95a2b35b1fdc748300129e7b56b77 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 6 May 2026 12:42:24 +0530 Subject: [PATCH 19/33] bump axiom and gracefully abort when browser_stop tool call executes --- package.json | 2 +- pnpm-lock.yaml | 963 ++++++++++++++++++++++++++++++++----------------- src/index.ts | 6 +- src/tools.ts | 8 +- 4 files changed, 637 insertions(+), 342 deletions(-) diff --git a/package.json b/package.json index 1f6b213..8cdb325 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@opentelemetry/semantic-conventions": "^1.37.0", "acorn": "^8.15.0", "ai": "^6.0.161", - "axiom": "^0.22.2", + "axiom": "^0.46.1", "ioredis": "^5.10.1", "openai": "^6.34.0", "pino": "^10.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index db9c717..e012bdb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -51,8 +51,8 @@ importers: specifier: ^6.0.161 version: 6.0.161(zod@4.3.6) axiom: - specifier: ^0.22.2 - version: 0.22.2(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(zod@4.3.6) + specifier: ^0.46.1 + version: 0.46.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@types/node@22.19.15)(magicast@0.5.2)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0))(zod@4.3.6) ioredis: specifier: ^5.10.1 version: 5.10.1 @@ -98,7 +98,7 @@ importers: version: 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: ^4.1.2 - version: 4.1.2(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1))) + version: 4.1.2(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0))) eslint: specifier: ^10.1.0 version: 10.1.0(jiti@2.6.1) @@ -113,7 +113,7 @@ importers: version: 8.57.2(eslint@10.1.0(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^4.1.2 - version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1)) + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)) packages: @@ -196,14 +196,161 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] - '@emnapi/runtime@1.9.1': - resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} @@ -289,9 +436,6 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@next/env@15.5.14': resolution: {integrity: sha512-aXeirLYuASxEgi4X4WhfXsShCFxWDfNn/8ZeC5YXAS2BB4A8FJi1kwwGL6nvMVboE7fZCzmJPNdMvVHc8JpaiA==} @@ -854,9 +998,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.122.0': - resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -895,97 +1036,130 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@rolldown/binding-android-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-android-arm-eabi@4.60.3': + resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.3': + resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-darwin-arm64@4.60.3': + resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.12': - resolution: {integrity: sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-darwin-x64@4.60.3': + resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': - resolution: {integrity: sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-freebsd-arm64@4.60.3': + resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.3': + resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': - resolution: {integrity: sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-arm-musleabihf@4.60.3': + resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.3': + resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-arm64-musl@4.60.3': + resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-loong64-gnu@4.60.3': + resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.3': + resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.3': + resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} cpu: [ppc64] os: [linux] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-ppc64-musl@4.60.3': + resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.3': + resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.3': + resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.3': + resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} cpu: [s390x] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': - resolution: {integrity: sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-x64-gnu@4.60.3': + resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': - resolution: {integrity: sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-linux-x64-musl@4.60.3': + resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} cpu: [x64] os: [linux] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': - resolution: {integrity: sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-openbsd-x64@4.60.3': + resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.3': + resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': - resolution: {integrity: sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-win32-arm64-msvc@4.60.3': + resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': - resolution: {integrity: sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rollup/rollup-win32-ia32-msvc@4.60.3': + resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.3': + resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.12': - resolution: {integrity: sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==} + '@rollup/rollup-win32-x64-msvc@4.60.3': + resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + cpu: [x64] + os: [win32] '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} @@ -993,9 +1167,6 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@types/aws-lambda@8.10.150': resolution: {integrity: sha512-AX+AbjH/rH5ezX1fbK8onC/a+HyQHo7QGmvoxAE42n22OsciAxvZoZNEr22tbXs8WfP1nIsBjKDpgPm3HjOZbA==} @@ -1195,8 +1366,8 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - axiom@0.22.2: - resolution: {integrity: sha512-OlOudN3KM86YpOlOf5vuJHAVbYd5Xe9jnENIB30AvvNCFkxtAmUFW3OLC+svjjeurULRdjoKKRiFsUjBNlt6pA==} + axiom@0.46.1: + resolution: {integrity: sha512-yt3sS8C9rbl0DemLPhPGwJB6iPCx/Fc/a1v6YPUTXg86WaDPaQflNTweZMQB6pmpDzHJmSYTDuF32AlQ5byLpA==} hasBin: true peerDependencies: '@opentelemetry/api': ^1.9.0 @@ -1219,10 +1390,14 @@ packages: buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - c12@2.0.4: - resolution: {integrity: sha512-3DbbhnFt0fKJHxU4tEUPmD1ahWE4PWPMomqfYsTJdrhpmEnRKJi3qSC4rO5U6E6zN1+pjBY7+z8fUmNRMaVKLw==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: - magicast: ^0.3.5 + magicast: '*' peerDependenciesMeta: magicast: optional: true @@ -1231,16 +1406,9 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -1267,12 +1435,8 @@ packages: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1300,8 +1464,20 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} @@ -1314,8 +1490,8 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} ecdsa-sig-formatter@1.0.11: @@ -1330,6 +1506,11 @@ packages: es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1391,6 +1572,9 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -1444,10 +1628,6 @@ packages: forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1481,14 +1661,17 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - giget@1.2.5: - resolution: {integrity: sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==} + giget@3.2.0: + resolution: {integrity: sha512-GvHTWcykIR/fP8cj8dMpuMMkvaeJfPvYnhq0oW+chSeIr+ldX21ifU2Ms6KBoyKZQZmVaUAAhQ2EZ68KJF8a7A==} hasBin: true glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + google-auth-library@10.6.2: resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} engines: {node: '>=18'} @@ -1547,6 +1730,11 @@ packages: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1559,10 +1747,19 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1720,26 +1917,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - mlly@1.8.2: - resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} - module-details-from-path@1.0.4: resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} @@ -1751,8 +1928,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@5.1.7: - resolution: {integrity: sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==} + nanoid@5.1.11: + resolution: {integrity: sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==} engines: {node: ^18 || >=20} hasBin: true @@ -1767,9 +1944,6 @@ packages: engines: {node: '>=10.5.0'} deprecated: Use your platform's native DOMException instead - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -1783,11 +1957,6 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - nypm@0.5.4: - resolution: {integrity: sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==} - engines: {node: ^14.16.0 || >=16.10.0} - hasBin: true - obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} @@ -1801,6 +1970,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + openai@6.34.0: resolution: {integrity: sha512-yEr2jdGf4tVFYG6ohmr3pF6VJuveP0EA/sS8TBx+4Eq5NT10alu5zg2dmxMXMgqpihRDQlFGpRt2XwsGj+Fyxw==} hasBin: true @@ -1839,8 +2012,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} @@ -1874,8 +2047,8 @@ packages: resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} playwright-core@1.59.1: resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} @@ -1933,12 +2106,12 @@ packages: quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} @@ -1965,11 +2138,15 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rolldown@1.0.0-rc.12: - resolution: {integrity: sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==} - engines: {node: ^20.19.0 || >=22.12.0} + rollup@4.60.3: + resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2043,11 +2220,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - thread-stream@4.0.0: resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} engines: {node: '>=20'} @@ -2055,9 +2227,6 @@ packages: tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.4: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} @@ -2079,8 +2248,15 @@ packages: peerDependencies: typescript: '>=4.8.4' - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -2098,9 +2274,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -2118,18 +2291,26 @@ packages: uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - vite@8.0.3: - resolution: {integrity: sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==} + vite-tsconfig-paths@5.1.4: + resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@7.3.2: + resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 + lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -2140,14 +2321,12 @@ packages: peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -2232,6 +2411,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -2240,9 +2423,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -2341,20 +2521,82 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 + '@esbuild/aix-ppc64@0.27.7': optional: true - '@emnapi/runtime@1.9.1': - dependencies: - tslib: 2.8.1 + '@esbuild/android-arm64@0.27.7': optional: true - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.1.0(jiti@2.6.1))': @@ -2429,13 +2671,6 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': {} - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.9.1 - '@tybys/wasm-util': 0.10.1 - optional: true - '@next/env@15.5.14': {} '@openrouter/ai-sdk-provider@2.5.1(ai@6.0.161(zod@4.3.6))(zod@4.3.6)': @@ -3219,8 +3454,6 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) - '@oxc-project/types@0.122.0': {} - '@pinojs/redact@0.4.0': {} '@playwright/test@1.59.1': @@ -3250,64 +3483,85 @@ snapshots: '@protobufjs/utf8@1.1.0': {} - '@rolldown/binding-android-arm64@1.0.0-rc.12': + '@rollup/rollup-android-arm-eabi@4.60.3': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.12': + '@rollup/rollup-android-arm64@4.60.3': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.12': + '@rollup/rollup-darwin-arm64@4.60.3': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.12': + '@rollup/rollup-darwin-x64@4.60.3': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12': + '@rollup/rollup-freebsd-arm64@4.60.3': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12': + '@rollup/rollup-freebsd-x64@4.60.3': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.12': + '@rollup/rollup-linux-arm-gnueabihf@4.60.3': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12': + '@rollup/rollup-linux-arm-musleabihf@4.60.3': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12': + '@rollup/rollup-linux-arm64-gnu@4.60.3': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.12': + '@rollup/rollup-linux-arm64-musl@4.60.3': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.12': + '@rollup/rollup-linux-loong64-gnu@4.60.3': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.12': + '@rollup/rollup-linux-loong64-musl@4.60.3': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.12': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 + '@rollup/rollup-linux-ppc64-gnu@4.60.3': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12': + '@rollup/rollup-linux-ppc64-musl@4.60.3': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.12': + '@rollup/rollup-linux-riscv64-gnu@4.60.3': optional: true - '@rolldown/pluginutils@1.0.0-rc.12': {} + '@rollup/rollup-linux-riscv64-musl@4.60.3': + optional: true - '@sinclair/typebox@0.34.48': {} + '@rollup/rollup-linux-s390x-gnu@4.60.3': + optional: true - '@standard-schema/spec@1.1.0': {} + '@rollup/rollup-linux-x64-gnu@4.60.3': + optional: true - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 + '@rollup/rollup-linux-x64-musl@4.60.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.3': optional: true + '@rollup/rollup-win32-x64-gnu@4.60.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.3': + optional: true + + '@sinclair/typebox@0.34.48': {} + + '@standard-schema/spec@1.1.0': {} + '@types/aws-lambda@8.10.150': {} '@types/bunyan@1.8.11': @@ -3460,7 +3714,7 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@vitest/coverage-v8@4.1.2(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1)))': + '@vitest/coverage-v8@4.1.2(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.2 @@ -3472,7 +3726,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1)) + vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)) '@vitest/expect@4.1.2': dependencies: @@ -3483,13 +3737,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.2(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1))': + '@vitest/mocker@4.1.2(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0))': dependencies: '@vitest/spy': 4.1.2 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.0.3(@types/node@22.19.15)(jiti@2.6.1) + vite: 7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0) '@vitest/pretty-format@4.1.2': dependencies: @@ -3558,7 +3812,7 @@ snapshots: atomic-sleep@1.0.0: {} - axiom@0.22.2(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(zod@4.3.6): + axiom@0.46.1(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@types/node@22.19.15)(magicast@0.5.2)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0))(zod@4.3.6): dependencies: '@next/env': 15.5.14 '@opentelemetry/api': 1.9.1 @@ -3569,17 +3823,31 @@ snapshots: '@opentelemetry/sdk-trace-node': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.40.0 '@sinclair/typebox': 0.34.48 - c12: 2.0.4 + c12: 3.3.4(magicast@0.5.2) commander: 14.0.3 - defu: 6.1.4 + defu: 6.1.7 handlebars: 4.7.9 - nanoid: 5.1.7 + nanoid: 5.1.11 + open: 10.2.0 + vite-tsconfig-paths: 5.1.4(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)) + vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)) zod: 4.3.6 transitivePeerDependencies: + - '@edge-runtime/vm' - '@opentelemetry/core' + - '@types/node' + - '@vitest/browser-playwright' + - '@vitest/browser-preview' + - '@vitest/browser-webdriverio' + - '@vitest/ui' - encoding + - happy-dom + - jsdom - magicast + - msw - supports-color + - typescript + - vite balanced-match@4.0.4: {} @@ -3593,32 +3861,32 @@ snapshots: buffer-equal-constant-time@1.0.1: {} - c12@2.0.4: + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + c12@3.3.4(magicast@0.5.2): dependencies: - chokidar: 4.0.3 - confbox: 0.1.8 - defu: 6.1.4 - dotenv: 16.6.1 - giget: 1.2.5 + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.4.2 + exsolve: 1.0.8 + giget: 3.2.0 jiti: 2.6.1 - mlly: 1.8.2 ohash: 2.0.11 pathe: 2.0.3 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - rc9: 2.1.2 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 + optionalDependencies: + magicast: 0.5.2 chai@6.2.2: {} - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chownr@2.0.0: {} - - citty@0.1.6: + chokidar@5.0.0: dependencies: - consola: 3.4.2 + readdirp: 5.0.0 cjs-module-lexer@1.4.3: {} @@ -3640,9 +3908,7 @@ snapshots: commander@14.0.3: {} - confbox@0.1.8: {} - - consola@3.4.2: {} + confbox@0.2.4: {} convert-source-map@2.0.0: {} @@ -3662,15 +3928,25 @@ snapshots: deep-is@0.1.4: {} - defu@6.1.4: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-lazy-prop@3.0.0: {} + + defu@6.1.7: {} denque@2.1.0: {} destr@2.0.5: {} - detect-libc@2.1.2: {} + detect-libc@2.1.2: + optional: true - dotenv@16.6.1: {} + dotenv@17.4.2: {} ecdsa-sig-formatter@1.0.11: dependencies: @@ -3684,6 +3960,35 @@ snapshots: es-module-lexer@2.0.0: {} + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -3762,6 +4067,8 @@ snapshots: expect-type@1.3.0: {} + exsolve@1.0.8: {} + extend@3.0.2: {} fast-copy@4.0.2: {} @@ -3805,10 +4112,6 @@ snapshots: forwarded-parse@2.1.2: {} - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - fsevents@2.3.2: optional: true @@ -3855,20 +4158,14 @@ snapshots: get-caller-file@2.0.5: {} - giget@1.2.5: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - defu: 6.1.4 - node-fetch-native: 1.6.7 - nypm: 0.5.4 - pathe: 2.0.3 - tar: 6.2.1 + giget@3.2.0: {} glob-parent@6.0.2: dependencies: is-glob: 4.0.3 + globrex@0.1.2: {} + google-auth-library@10.6.2: dependencies: base64-js: 1.5.1 @@ -3941,6 +4238,8 @@ snapshots: dependencies: hasown: 2.0.2 + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -3949,8 +4248,16 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-stream@2.0.1: {} + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -4052,6 +4359,7 @@ snapshots: lightningcss-linux-x64-musl: 1.32.0 lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + optional: true locate-path@6.0.0: dependencies: @@ -4085,33 +4393,13 @@ snapshots: minimist@1.2.8: {} - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - - mkdirp@1.0.4: {} - - mlly@1.8.2: - dependencies: - acorn: 8.16.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - module-details-from-path@1.0.4: {} ms@2.1.3: {} nanoid@3.3.11: {} - nanoid@5.1.7: {} + nanoid@5.1.11: {} natural-compare@1.4.0: {} @@ -4119,8 +4407,6 @@ snapshots: node-domexception@1.0.0: {} - node-fetch-native@1.6.7: {} - node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -4131,15 +4417,6 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - nypm@0.5.4: - dependencies: - citty: 0.1.6 - consola: 3.4.2 - pathe: 2.0.3 - pkg-types: 1.3.1 - tinyexec: 0.3.2 - ufo: 1.6.3 - obug@2.1.1: {} ohash@2.0.11: {} @@ -4150,6 +4427,13 @@ snapshots: dependencies: wrappy: 1.0.2 + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + openai@6.34.0(zod@4.3.6): optionalDependencies: zod: 4.3.6 @@ -4179,7 +4463,7 @@ snapshots: pathe@2.0.3: {} - perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} pg-int8@1.0.1: {} @@ -4233,10 +4517,10 @@ snapshots: sonic-boom: 4.2.1 thread-stream: 4.0.0 - pkg-types@1.3.1: + pkg-types@2.3.1: dependencies: - confbox: 0.1.8 - mlly: 1.8.2 + confbox: 0.2.4 + exsolve: 1.0.8 pathe: 2.0.3 playwright-core@1.59.1: {} @@ -4293,12 +4577,12 @@ snapshots: quick-format-unescaped@4.0.4: {} - rc9@2.1.2: + rc9@3.0.1: dependencies: - defu: 6.1.4 + defu: 6.1.7 destr: 2.0.5 - readdirp@4.1.2: {} + readdirp@5.0.0: {} real-require@0.2.0: {} @@ -4324,26 +4608,38 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rolldown@1.0.0-rc.12: + rollup@4.60.3: dependencies: - '@oxc-project/types': 0.122.0 - '@rolldown/pluginutils': 1.0.0-rc.12 + '@types/estree': 1.0.8 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.12 - '@rolldown/binding-darwin-x64': 1.0.0-rc.12 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.12 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.12 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.12 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.12 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.12 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.12 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.12 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.12 + '@rollup/rollup-android-arm-eabi': 4.60.3 + '@rollup/rollup-android-arm64': 4.60.3 + '@rollup/rollup-darwin-arm64': 4.60.3 + '@rollup/rollup-darwin-x64': 4.60.3 + '@rollup/rollup-freebsd-arm64': 4.60.3 + '@rollup/rollup-freebsd-x64': 4.60.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 + '@rollup/rollup-linux-arm-musleabihf': 4.60.3 + '@rollup/rollup-linux-arm64-gnu': 4.60.3 + '@rollup/rollup-linux-arm64-musl': 4.60.3 + '@rollup/rollup-linux-loong64-gnu': 4.60.3 + '@rollup/rollup-linux-loong64-musl': 4.60.3 + '@rollup/rollup-linux-ppc64-gnu': 4.60.3 + '@rollup/rollup-linux-ppc64-musl': 4.60.3 + '@rollup/rollup-linux-riscv64-gnu': 4.60.3 + '@rollup/rollup-linux-riscv64-musl': 4.60.3 + '@rollup/rollup-linux-s390x-gnu': 4.60.3 + '@rollup/rollup-linux-x64-gnu': 4.60.3 + '@rollup/rollup-linux-x64-musl': 4.60.3 + '@rollup/rollup-openbsd-x64': 4.60.3 + '@rollup/rollup-openharmony-arm64': 4.60.3 + '@rollup/rollup-win32-arm64-msvc': 4.60.3 + '@rollup/rollup-win32-ia32-msvc': 4.60.3 + '@rollup/rollup-win32-x64-gnu': 4.60.3 + '@rollup/rollup-win32-x64-msvc': 4.60.3 + fsevents: 2.3.3 + + run-applescript@7.1.0: {} safe-buffer@5.2.1: {} @@ -4399,23 +4695,12 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - thread-stream@4.0.0: dependencies: real-require: 0.2.0 tinybench@2.9.0: {} - tinyexec@0.3.2: {} - tinyexec@1.0.4: {} tinyglobby@0.2.15: @@ -4431,8 +4716,9 @@ snapshots: dependencies: typescript: 5.9.3 - tslib@2.8.1: - optional: true + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 type-check@0.4.0: dependencies: @@ -4451,8 +4737,6 @@ snapshots: typescript@5.9.3: {} - ufo@1.6.3: {} - uglify-js@3.19.3: optional: true @@ -4466,22 +4750,35 @@ snapshots: uuid@9.0.1: {} - vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)): dependencies: - lightningcss: 1.32.0 + debug: 4.4.3 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.3) + optionalDependencies: + vite: 7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0) + transitivePeerDependencies: + - supports-color + - typescript + + vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0): + dependencies: + esbuild: 0.27.7 + fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.8 - rolldown: 1.0.0-rc.12 + rollup: 4.60.3 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 22.19.15 fsevents: 2.3.3 jiti: 2.6.1 + lightningcss: 1.32.0 - vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1)): + vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.15)(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)): dependencies: '@vitest/expect': 4.1.2 - '@vitest/mocker': 4.1.2(vite@8.0.3(@types/node@22.19.15)(jiti@2.6.1)) + '@vitest/mocker': 4.1.2(vite@7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0)) '@vitest/pretty-format': 4.1.2 '@vitest/runner': 4.1.2 '@vitest/snapshot': 4.1.2 @@ -4498,7 +4795,7 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.1.0 - vite: 8.0.3(@types/node@22.19.15)(jiti@2.6.1) + vite: 7.3.2(@types/node@22.19.15)(jiti@2.6.1)(lightningcss@1.32.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -4536,12 +4833,14 @@ snapshots: wrappy@1.0.2: {} + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + xtend@4.0.2: {} y18n@5.0.8: {} - yallist@4.0.0: {} - yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/src/index.ts b/src/index.ts index c069c9e..95fdc25 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,7 @@ import { PlaywrightWorkerOptions, TestType, } from "@playwright/test"; -import { generateText, Output, stepCountIs } from "ai"; +import { generateText, hasToolCall, Output, stepCountIs } from "ai"; import { withSpan } from "axiom/ai"; import shortid from "shortid"; import { axiomEnabled } from "./instrumentation"; @@ -501,7 +501,7 @@ export const runSteps = async ({ }); }); }, - stopWhen: stepCountIs(STEP_EXECUTION_MAX_STEPS), + stopWhen: [stepCountIs(STEP_EXECUTION_MAX_STEPS), hasToolCall("browser_stop")], abortSignal: AbortSignal.timeout(STEP_EXECUTION_TIMEOUT), toolChoice: "auto", prompt: buildRunStepsPrompt({ @@ -735,7 +735,7 @@ export const runUserFlow = async ({ }, }, }, - stopWhen: stepCountIs(USER_FLOW_MAX_STEPS), + stopWhen: [stepCountIs(USER_FLOW_MAX_STEPS), hasToolCall("browser_stop")], abortSignal: abortController.signal, prepareStep: async ({ messages }) => { // Remove older messages to keep the context window small diff --git a/src/tools.ts b/src/tools.ts index 19d0bc6..f900522 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -476,13 +476,9 @@ class PlaywrightTools { reasoning: z.string().describe("A quick one-line reasoning behind this action"), }); public async stop(_: z.infer) { - const DELAY = STOP_DELAY; // 3 seconds // brief sleep to ensure any ongoing navigation or actions are complete - // In future we could add graceful stop logic here - await new Promise((resolve) => setTimeout(resolve, DELAY)); - if (this.abortController) { - this.abortController.abort(); - } + // before the agent loop terminates via the `hasToolCall("browser_stop")` stop condition + await new Promise((resolve) => setTimeout(resolve, STOP_DELAY)); return { success: true, message: "Execution stopped" }; } From 6d863133089500c218b0d534f8f28032bbecba47 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 6 May 2026 12:42:34 +0530 Subject: [PATCH 20/33] 1.0.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cdb325..23c847b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.10", + "version": "1.0.11", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From d36a00c350949e75f3a30d61828ee05cf1b02956 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 6 May 2026 16:26:48 +0530 Subject: [PATCH 21/33] Make telemetry (via axiom) and Redis configurable via configure() function --- README.md | 21 ++++++++--- TROUBLESHOOTING.md | 4 +-- src/__tests__/assertion.test.ts | 5 ++- src/__tests__/data-cache.test.ts | 2 +- src/__tests__/integration/run-steps.test.ts | 27 +++++++------- src/config.ts | 32 +++++++++++++++++ src/data-cache.ts | 5 ++- src/index.ts | 12 ++++--- src/instrumentation.ts | 40 ++++++++++++++++++--- src/models.ts | 4 +-- src/redis.ts | 40 ++++++++++++++++----- src/tools.ts | 12 ++++--- 12 files changed, 160 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index db8141f..e646689 100644 --- a/README.md +++ b/README.md @@ -248,7 +248,7 @@ configure({ | Variable | Required | Default | Description | |----------|----------|---------|-------------| -| `REDIS_URL` | No | - | Redis connection URL for step caching and global state | +| `REDIS_URL` | No | - | Redis connection URL for step caching and global state. Can also be set via `configure({ redis: { url } })`, which takes precedence. | | `ANTHROPIC_API_KEY` | Yes | - | Anthropic API key for Claude models | | `GOOGLE_GENERATIVE_AI_API_KEY` | Yes | - | Google API key for Gemini models | | `AI_GATEWAY_API_KEY` | If gateway=vercel | - | Vercel AI Gateway API key | @@ -257,8 +257,8 @@ configure({ | `CLOUDFLARE_AI_GATEWAY` | If gateway=cloudflare | - | Cloudflare AI Gateway name (slug) | | `CLOUDFLARE_AI_GATEWAY_API_KEY` | If gateway=cloudflare and the gateway is authenticated | - | Cloudflare AI Gateway token (sent as `cf-aig-authorization`) | | `OPENAI_API_KEY` | If mode=cua | - | OpenAI API key (required for CUA mode; must have Responses-API `computer` tool access) | -| `AXIOM_TOKEN` | No | - | Axiom token for OpenTelemetry tracing | -| `AXIOM_DATASET` | No | - | Axiom dataset for trace storage | +| `AXIOM_TOKEN` | No | - | Axiom token for OpenTelemetry tracing. Can also be set via `configure({ telemetry: { axiomToken } })`, which takes precedence. | +| `AXIOM_DATASET` | No | - | Axiom dataset for trace storage. Can also be set via `configure({ telemetry: { axiomDataset } })`, which takes precedence. | | `PASSMARK_LOG_LEVEL` | No | `info` | Log level: `debug`, `info`, `warn`, `error`, `silent` | ## Model Configuration @@ -280,6 +280,8 @@ All models are configurable via `configure({ ai: { models: { ... } } })`: Passmark caches successful step actions in Redis. On subsequent runs, cached steps execute directly without AI calls, dramatically reducing latency and cost. +Provide the connection via `configure({ redis: { url } })` or the `REDIS_URL` env var (configure value wins). Without either, caching, `{{global.*}}` placeholders, and project data are disabled. + - Steps are cached by `userFlow` + `step.description` - Set `bypassCache: true` on individual steps or the entire run to force AI execution - Cache is automatically bypassed on Playwright retries @@ -287,9 +289,18 @@ Passmark caches successful step actions in Redis. On subsequent runs, cached ste ## Telemetry -Telemetry is opt-in. Set `AXIOM_TOKEN` and `AXIOM_DATASET` to enable OpenTelemetry tracing via Axiom. All AI calls are wrapped with `withSpan` for observability. +Telemetry is opt-in. Either set the `AXIOM_TOKEN` and `AXIOM_DATASET` env vars, or pass them through `configure()`: + +```typescript +configure({ + telemetry: { + axiomToken: process.env.MY_AXIOM_TOKEN, + axiomDataset: "passmark-traces", + }, +}); +``` -Without these env vars, telemetry is a no-op. +`configure()` values take precedence over env vars. Without either, telemetry is a no-op. All AI calls are wrapped with `withSpan` for observability. Configure Axiom to get a rich dashboard like this: diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 04fec66..e8bc6f4 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -7,7 +7,7 @@ This guide helps you diagnose and fix the common problems contributors hit when - Node.js >= 18 - Install dependencies: `pnpm install` (or `npm install`) - Install Playwright browsers: `npx playwright install` -- Redis available at `REDIS_URL` (see `.env.example`) +- Redis available at `REDIS_URL` or via `configure({ redis: { url } })` (see `.env.example`) - Required AI keys set when using direct providers: `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY` - If using the Vercel AI Gateway, set `AI_GATEWAY_API_KEY` - If using CUA mode (`configure({ ai: { mode: "cua" } })`), set `OPENAI_API_KEY` and use `gateway: "none"` @@ -74,7 +74,7 @@ redis-server & docker run --rm -p 6379:6379 redis ``` -Set `REDIS_URL` in your environment (see `.env.example`) so Passmark can connect. +Set `REDIS_URL` in your environment (see `.env.example`), or pass it via `configure({ redis: { url } })`, so Passmark can connect. If you intentionally don't want Redis, the code logs a warning and continues without caching. diff --git a/src/__tests__/assertion.test.ts b/src/__tests__/assertion.test.ts index c07e587..636b1e8 100644 --- a/src/__tests__/assertion.test.ts +++ b/src/__tests__/assertion.test.ts @@ -1,7 +1,10 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; // Disable Axiom instrumentation -vi.mock("../instrumentation", () => ({ axiomEnabled: false })); +vi.mock("../instrumentation", () => ({ + isAxiomEnabled: () => false, + initTelemetry: vi.fn(), +})); // Mock models.resolveModel to return the model id string so our AI mock can // branch based on the model identifier. diff --git a/src/__tests__/data-cache.test.ts b/src/__tests__/data-cache.test.ts index 69be5ec..f5d90db 100644 --- a/src/__tests__/data-cache.test.ts +++ b/src/__tests__/data-cache.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("../redis", () => ({ - redis: { hgetall: vi.fn(), hset: vi.fn(), expire: vi.fn() }, + getRedis: () => ({ hgetall: vi.fn(), hset: vi.fn(), expire: vi.fn() }), })); vi.mock("../email", () => ({ diff --git a/src/__tests__/integration/run-steps.test.ts b/src/__tests__/integration/run-steps.test.ts index 8151f8e..5dd590b 100644 --- a/src/__tests__/integration/run-steps.test.ts +++ b/src/__tests__/integration/run-steps.test.ts @@ -1,15 +1,19 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; -// Mock instrumentation (imported as side effect) -vi.mock("../../instrumentation", () => ({ axiomEnabled: false })); +// Mock instrumentation +vi.mock("../../instrumentation", () => ({ + isAxiomEnabled: () => false, + initTelemetry: vi.fn(), +})); // Mock Redis +const mockRedis = { + hgetall: vi.fn().mockResolvedValue({}), + hset: vi.fn().mockResolvedValue("OK"), + expire: vi.fn().mockResolvedValue(1), +}; vi.mock("../../redis", () => ({ - redis: { - hgetall: vi.fn().mockResolvedValue({}), - hset: vi.fn().mockResolvedValue("OK"), - expire: vi.fn().mockResolvedValue(1), - }, + getRedis: () => mockRedis, })); // Mock AI SDK @@ -96,7 +100,6 @@ vi.mock("../../cua", () => ({ import { runSteps } from "../../index"; import { configure, resetConfig } from "../../config"; -import { redis } from "../../redis"; import { generateText } from "ai"; import { runCUALoop } from "../../cua"; import type { Page } from "@playwright/test"; @@ -130,7 +133,7 @@ describe("runSteps", () => { vi.clearAllMocks(); resetConfig(); // Reset redis mock to default empty - vi.mocked(redis!.hgetall).mockResolvedValue({}); + vi.mocked(mockRedis.hgetall).mockResolvedValue({}); }); it("executes a simple step", async () => { @@ -207,7 +210,7 @@ describe("runSteps", () => { const steps: Step[] = [{ description: "Click submit" }]; // Mock redis to return cached step data - vi.mocked(redis!.hgetall).mockResolvedValue({ + vi.mocked(mockRedis.hgetall).mockResolvedValue({ locator: 'getByRole("button", { name: "Submit" })', action: "click", description: "Submit button", @@ -229,7 +232,7 @@ describe("runSteps", () => { const steps: Step[] = [{ description: "Click submit" }]; // Mock redis to return cached step data - vi.mocked(redis!.hgetall).mockResolvedValue({ + vi.mocked(mockRedis.hgetall).mockResolvedValue({ locator: 'getByRole("button", { name: "Submit" })', action: "click", description: "Submit button", @@ -364,7 +367,7 @@ describe("runSteps", () => { const page = createMockPage(); // Mock redis to return cached data - vi.mocked(redis!.hgetall).mockResolvedValue({ + vi.mocked(mockRedis.hgetall).mockResolvedValue({ locator: 'getByRole("button", { name: "Go" })', action: "click", description: "Go button", diff --git a/src/config.ts b/src/config.ts index 82c6974..f4788de 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,3 +1,5 @@ +import { initTelemetry } from "./instrumentation"; + export type EmailProvider = { /** Domain for generating test emails (e.g. "emailsink.dev") */ domain: string; @@ -65,11 +67,37 @@ export type AIOverride = { models?: ModelConfig; }; +export type RedisConfig = { + /** + * Redis connection URL used for step caching, {{global.*}} placeholders, + * and project data. Falls back to `process.env.REDIS_URL` when omitted. + * If neither is set, those features are disabled. + */ + url?: string; +}; + +export type TelemetryConfig = { + /** + * Axiom API token for OpenTelemetry tracing of AI calls. + * Falls back to `process.env.AXIOM_TOKEN` when omitted. + */ + axiomToken?: string; + /** + * Axiom dataset for trace storage. + * Falls back to `process.env.AXIOM_DATASET` when omitted. + */ + axiomDataset?: string; +}; + type Config = { email?: EmailProvider; ai?: AIOverride; /** Base path for file uploads. Default: "./uploads" */ uploadBasePath?: string; + /** Redis connection. When omitted, falls back to `REDIS_URL` env var. */ + redis?: RedisConfig; + /** Telemetry (Axiom) connection. When omitted, falls back to `AXIOM_TOKEN`/`AXIOM_DATASET` env vars. */ + telemetry?: TelemetryConfig; }; let globalConfig: Config = {}; @@ -96,6 +124,10 @@ export function configure(config: Config) { ); } globalConfig = { ...globalConfig, ...config }; + + if (config.telemetry) { + initTelemetry(); + } } /** diff --git a/src/data-cache.ts b/src/data-cache.ts index 01ecec2..17fb9c8 100644 --- a/src/data-cache.ts +++ b/src/data-cache.ts @@ -4,7 +4,7 @@ import { getConfig } from "./config"; import { extractEmailContent } from "./email"; import { GLOBAL_VALUES_TTL_SECONDS } from "./constants"; import { logger } from "./logger"; -import { redis } from "./redis"; +import { getRedis } from "./redis"; import { Step } from "./types"; import { generatePhoneNumber } from "./utils"; @@ -112,6 +112,7 @@ function getRedisKey(executionId: string): string { export async function getGlobalValues( executionId: string, ): Promise | null> { + const redis = getRedis(); if (!redis) return null; const key = getRedisKey(executionId); const values = await redis.hgetall(key); @@ -131,6 +132,7 @@ export async function saveGlobalValues( executionId: string, values: GlobalPlaceholders, ): Promise { + const redis = getRedis(); if (!redis) return; const key = getRedisKey(executionId); @@ -160,6 +162,7 @@ function getProjectDataRedisKey(projectId: string): string { * Returns an empty object if no data exists. */ export async function getProjectData(projectId: string): Promise { + const redis = getRedis(); if (!redis) return {}; const key = getProjectDataRedisKey(projectId); const values = await redis.hgetall(key); diff --git a/src/index.ts b/src/index.ts index 95fdc25..4165c6a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,4 @@ import { StepExecutionError, ValidationError } from "./errors"; -import "./instrumentation"; // For Axiom AI instrumentation import { PlaywrightTestArgs, @@ -11,18 +10,18 @@ import { import { generateText, hasToolCall, Output, stepCountIs } from "ai"; import { withSpan } from "axiom/ai"; import shortid from "shortid"; -import { axiomEnabled } from "./instrumentation"; +import { initTelemetry, isAxiomEnabled } from "./instrumentation"; // Only use withSpan when Axiom is configured, otherwise just execute the function directly async function maybeWithSpan( meta: { capability: string; step: string }, fn: () => Promise, ): Promise { - return axiomEnabled ? withSpan(meta, async () => fn()) : fn(); + return isAxiomEnabled() ? withSpan(meta, async () => fn()) : fn(); } import { z } from "zod"; import { buildRunStepsPrompt, buildRunUserFlowPrompt } from "./prompts"; -import { redis } from "./redis"; +import { getRedis } from "./redis"; import { getAItools } from "./tools"; import { RunStepsOptions, UserFlowOptions } from "./types"; import { @@ -107,10 +106,15 @@ export const runSteps = async ({ }: RunStepsOptions) => { executionId = executionId || process.env.executionId; + // Initialize Axiom telemetry now that any user `configure()` call has run. + // Idempotent — re-entry is a no-op. + initTelemetry(); + // Track all open tabs for this run. The active page is updated automatically // when a new tab opens, or explicitly via the `switchToTab` step field. const tabManager = createTabManager(page); + const redis = getRedis(); if (!redis) { logger.warn( "Redis not configured. Step caching is disabled — all steps will use AI execution.", diff --git a/src/instrumentation.ts b/src/instrumentation.ts index d5e2027..5c46c4e 100644 --- a/src/instrumentation.ts +++ b/src/instrumentation.ts @@ -5,14 +5,29 @@ import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node"; import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions"; import { trace } from "@opentelemetry/api"; import { initAxiomAI, RedactionPolicy } from "axiom/ai"; +import { getConfig } from "./config"; import { logger } from "./logger"; -const axiomToken = process.env.AXIOM_TOKEN; -const axiomDataset = process.env.AXIOM_DATASET; +let initialized = false; +let enabled = false; -export const axiomEnabled = !!(axiomToken && axiomDataset); +/** + * Initializes Axiom AI tracing. Idempotent — safe to call multiple times. + * + * Resolution order: `configure({ telemetry: ... })` first, then + * `AXIOM_TOKEN`/`AXIOM_DATASET` env vars. If neither is set, telemetry stays + * disabled and AI calls run unwrapped. + */ +export function initTelemetry() { + if (initialized) return; + initialized = true; + + const telemetry = getConfig().telemetry; + const axiomToken = telemetry?.axiomToken ?? process.env.AXIOM_TOKEN; + const axiomDataset = telemetry?.axiomDataset ?? process.env.AXIOM_DATASET; + + if (!axiomToken || !axiomDataset) return; -if (axiomToken && axiomDataset) { logger.info("Axiom AI instrumentation enabled"); const tracer = trace.getTracer("ai-logs-tracer"); @@ -41,4 +56,21 @@ if (axiomToken && axiomDataset) { provider.register(); initAxiomAI({ tracer, redactionPolicy: RedactionPolicy.AxiomDefault }); + enabled = true; +} + +/** + * Returns true iff `initTelemetry()` succeeded (token + dataset were set). + * Use this at call sites — not a cached const — so post-`configure()` state + * is reflected. + */ +export function isAxiomEnabled(): boolean { + if (!initialized) initTelemetry(); + return enabled; +} + +/** @internal Reset for tests. */ +export function resetTelemetry() { + initialized = false; + enabled = false; } diff --git a/src/models.ts b/src/models.ts index f326ea6..f6c608c 100644 --- a/src/models.ts +++ b/src/models.ts @@ -5,10 +5,10 @@ import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { gateway, type LanguageModel } from "ai"; import { wrapAISDKModel } from "axiom/ai"; import { type AIGateway, getConfig } from "./config"; -import { axiomEnabled } from "./instrumentation"; +import { isAxiomEnabled } from "./instrumentation"; function wrapModel(model: LanguageModel): LanguageModel { - return axiomEnabled ? wrapAISDKModel(model) : model; + return isAxiomEnabled() ? wrapAISDKModel(model) : model; } let _google: ReturnType | null = null; diff --git a/src/redis.ts b/src/redis.ts index bf3f34d..a004b6b 100644 --- a/src/redis.ts +++ b/src/redis.ts @@ -1,14 +1,38 @@ import Redis from "ioredis"; +import { getConfig } from "./config"; import { logger } from "./logger"; -let redis: Redis | null = null; +let client: Redis | null = null; +let initialized = false; -if (process.env.REDIS_URL) { - redis = new Redis(process.env.REDIS_URL); -} else { - logger.warn( - "REDIS_URL not set. Step caching, global placeholders, and project data are disabled.", - ); +/** + * Returns a memoized Redis client. Reads `configure({ redis: { url } })` first, + * then falls back to `process.env.REDIS_URL`. Returns null when neither is set, + * which disables step caching, {{global.*}} placeholders, and project data. + * + * Lazy: the connection is opened on first call so users can call `configure()` + * before any Redis-dependent code path runs. + */ +export function getRedis(): Redis | null { + if (initialized) return client; + initialized = true; + + const url = getConfig().redis?.url ?? process.env.REDIS_URL; + if (!url) { + logger.warn( + "Redis URL not set (configure({ redis: { url } }) or REDIS_URL). " + + "Step caching, global placeholders, and project data are disabled.", + ); + return null; + } + + client = new Redis(url); + return client; } -export { redis }; +/** @internal Reset the memoized client. Used for testing only. */ +export function resetRedis() { + client?.disconnect(); + client = null; + initialized = false; +} diff --git a/src/tools.ts b/src/tools.ts index f900522..df205e1 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -4,7 +4,7 @@ import { Locator, type Page } from "@playwright/test"; import { wrapTool } from "axiom/ai"; import shortid from "shortid"; import { getConfig } from "./config"; -import { axiomEnabled } from "./instrumentation"; +import { isAxiomEnabled } from "./instrumentation"; import { logger } from "./logger"; import { LOCATOR_ACTION_TIMEOUT, SNAPSHOT_TIMEOUT, STOP_DELAY } from "./constants"; import { @@ -30,12 +30,16 @@ type ToolSettings = { tabManager?: TabManager; }; -// Only wrap tools with Axiom instrumentation when Axiom is configured -const maybeWrapTool: typeof wrapTool = axiomEnabled ? wrapTool : (_name: string, t: T): T => t; - export function getAItools(page: Page, settings?: ToolSettings) { const playwrightTools = new PlaywrightTools(page, settings); + // Only wrap tools with Axiom instrumentation when Axiom is configured. + // Resolved per-call so users who call `configure({ telemetry })` before + // `runSteps` (rather than setting env vars) still get instrumentation. + const maybeWrapTool: typeof wrapTool = isAxiomEnabled() + ? wrapTool + : (_name: string, t: T): T => t; + const withSnapshot = async ( fn: (args: TArgs) => Promise, args: TArgs, From 1808130ad7408b9d38fdcf332031bd237a6b7179 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 6 May 2026 16:27:02 +0530 Subject: [PATCH 22/33] 1.0.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23c847b..924d581 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.11", + "version": "1.0.12", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From ce0da4ac60dd38f25e9d48f482ed6e97c8668c39 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 7 May 2026 17:13:36 +0530 Subject: [PATCH 23/33] Fix assertion: Assertions will now use value extracted in a previous step --- src/index.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 4165c6a..8365e07 100644 --- a/src/index.ts +++ b/src/index.ts @@ -586,7 +586,15 @@ export const runSteps = async ({ } if (processedAssertions && processedAssertions.length > 0 && expect) { - for (const { assertion, effort, images } of processedAssertions) { + for (const { assertion: preProcessedAssertion, effort, images } of processedAssertions) { + // Re-resolve placeholders against the latest localValues so extracted + // values from steps (e.g. {{run.emailContent}}) get substituted in. + const assertion = replacePlaceholders( + preProcessedAssertion, + localValues, + globalValues, + projectDataValues, + ); logger.info(`Running assertion: ${assertion}`); const id = shortid.generate(); From 1cb6a0bdec4f6db7030f9e9a209b31621f082a5b Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 7 May 2026 17:13:40 +0530 Subject: [PATCH 24/33] 1.0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 924d581..06242f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.12", + "version": "1.0.13", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From bb29d5a3765c44a7796b8a7b7b5924f1a9d522d5 Mon Sep 17 00:00:00 2001 From: Ipseeta Date: Tue, 12 May 2026 17:38:29 +0530 Subject: [PATCH 25/33] Add video assertions: record step run and validate via Gemini Files API --- README.md | 31 +++++- package.json | 1 + pnpm-lock.yaml | 79 ++++++++++++- src/assertion.ts | 41 +++++++ src/config.ts | 6 + src/constants.ts | 8 ++ src/data-cache.ts | 6 + src/index.ts | 129 ++++++++++++++------- src/types.ts | 13 +++ src/video.ts | 277 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 546 insertions(+), 45 deletions(-) create mode 100644 src/video.ts diff --git a/README.md b/README.md index e646689..d27e120 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ Set `OPENAI_API_KEY` whenever any step opts into `mode: "cua"`. CUA steps still - **Core Execution** — `runSteps()` and `runUserFlow()` for flexible test orchestration in natural language, with smart caching and auto-healing - **Multi-Model Assertion Engine** — Consensus-based validation using Claude and Gemini, with an arbiter model to resolve disagreements +- **Video Assertions** — Opt in per-assertion to record the full step run and evaluate the assertion against the whole video via Gemini's Files API. Useful for ephemeral UI (toasts, snackbars) that a single screenshot may miss - **Redis-Based Step Caching** — Cache-first execution with AI fallback and automatic self-healing when cached steps fail - **Configurable AI Models** — 8 dedicated model slots for step execution, assertions, extraction, and more - **AI Gateway Support** — Route requests through Vercel AI Gateway, OpenRouter, Cloudflare AI Gateway, or connect directly to provider SDKs @@ -225,6 +226,34 @@ const result = await assert({ }); ``` +### Video Assertions + +For UI that's only visible for a second or two — toast messages, snackbar confirmations, transient banners — a single end-of-flow screenshot often misses the evidence. Set `video: true` on an assertion inside `runSteps` and Passmark will record the entire step run with `page.screencast`, upload the resulting `.webm` to Gemini's Files API, and evaluate the assertion against the full video: + +```typescript +await runSteps({ + page, + userFlow: "Add to cart", + steps: [ + { description: "Click Acme Circles T-Shirt" }, + { description: "Add to cart" }, + ], + assertions: [ + { assertion: "An 'Added to cart' toast appears", video: true }, + ], + test, + expect, +}); +``` + +Notes: + +- Recording spans the **entire** step run (start of first step to end of last step). One recording is shared across all `video: true` assertions in the same `runSteps` call. +- The video file is written to `/tmp/passmark-recordings/` by default and deleted automatically after the assertions consume it. Override via `configure({ videoDir: "/your/path" })`. +- This path uses **only Gemini** (no Claude/Gemini consensus) since Claude doesn't accept video. The model is `gemini-3-flash-preview`. +- Video assertions go **directly** to Gemini's Files API regardless of any configured `gateway` — file URIs are tied to the uploading Google account, so the gateway can't proxy them. You must set `GOOGLE_GENERATIVE_AI_API_KEY` (or `GEMINI_API_KEY`) even when the rest of your stack runs through Vercel / OpenRouter / Cloudflare. +- If `page.screencast.start()` fails (rare), video assertions silently fall back to the regular screenshot/snapshot path so the run still completes. + ## Configuration Call `configure()` once before using any functions: @@ -250,7 +279,7 @@ configure({ |----------|----------|---------|-------------| | `REDIS_URL` | No | - | Redis connection URL for step caching and global state. Can also be set via `configure({ redis: { url } })`, which takes precedence. | | `ANTHROPIC_API_KEY` | Yes | - | Anthropic API key for Claude models | -| `GOOGLE_GENERATIVE_AI_API_KEY` | Yes | - | Google API key for Gemini models | +| `GOOGLE_GENERATIVE_AI_API_KEY` | Yes | - | Google API key for Gemini models. Also required for `video: true` assertions regardless of gateway (file URIs are tied to the uploading account). | | `AI_GATEWAY_API_KEY` | If gateway=vercel | - | Vercel AI Gateway API key | | `OPENROUTER_API_KEY` | If gateway=openrouter | - | OpenRouter API key | | `CLOUDFLARE_ACCOUNT_ID` | If gateway=cloudflare | - | Cloudflare account ID that owns the AI Gateway | diff --git a/package.json b/package.json index 06242f4..a404fdd 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@ai-sdk/google-vertex": "^4.0.105", "@ai-sdk/openai": "^3.0.52", "@faker-js/faker": "^10.1.0", + "@google/genai": "^2.1.0", "@openrouter/ai-sdk-provider": "^2.5.1", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-trace-otlp-http": "^0.207.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e012bdb..61b260b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@faker-js/faker': specifier: ^10.1.0 version: 10.4.0 + '@google/genai': + specifier: ^2.1.0 + version: 2.1.0 '@openrouter/ai-sdk-provider': specifier: ^2.5.1 version: 2.5.1(ai@6.0.161(zod@4.3.6))(zod@4.3.6) @@ -58,7 +61,7 @@ importers: version: 5.10.1 openai: specifier: ^6.34.0 - version: 6.34.0(zod@4.3.6) + version: 6.34.0(ws@8.20.0)(zod@4.3.6) pino: specifier: ^10.3.1 version: 10.3.1 @@ -395,6 +398,15 @@ packages: resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@google/genai@2.1.0': + resolution: {integrity: sha512-2tF/P5LMkiV31slQpTA92EqP7SRHB8VM1IXWdtC9jWzpp8J5j4TakywSqpB/R0K1aPLlpMt3PgB2O1c/+wJPXQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + '@grpc/grpc-js@1.14.3': resolution: {integrity: sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==} engines: {node: '>=12.10.0'} @@ -1070,66 +1082,79 @@ packages: resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.60.3': resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.60.3': resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.60.3': resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.60.3': resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.3': resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.60.3': resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.3': resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.60.3': resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.60.3': resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.60.3': resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.3': resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.60.3': resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.60.3': resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} @@ -1212,6 +1237,9 @@ packages: '@types/pg@8.15.4': resolution: {integrity: sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/shortid@2.2.0': resolution: {integrity: sha512-jBG2FgBxcaSf0h662YloTGA32M8UtNbnTPekUr/eCmWXq0JWQXgNEQ/P5Gf05Cv66QZtE1Ttr83I1AJBPdzCBg==} @@ -1849,24 +1877,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -1998,6 +2030,10 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2138,6 +2174,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + rollup@4.60.3: resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -2411,6 +2451,18 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + wsl-utils@0.1.0: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} @@ -2635,6 +2687,17 @@ snapshots: '@faker-js/faker@10.4.0': {} + '@google/genai@2.1.0': + dependencies: + google-auth-library: 10.6.2 + p-retry: 4.6.2 + protobufjs: 7.5.4 + ws: 8.20.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@grpc/grpc-js@1.14.3': dependencies: '@grpc/proto-loader': 0.8.0 @@ -3615,6 +3678,8 @@ snapshots: pg-protocol: 1.13.0 pg-types: 2.2.0 + '@types/retry@0.12.0': {} + '@types/shortid@2.2.0': {} '@types/tedious@4.0.14': @@ -4434,8 +4499,9 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 - openai@6.34.0(zod@4.3.6): + openai@6.34.0(ws@8.20.0)(zod@4.3.6): optionalDependencies: + ws: 8.20.0 zod: 4.3.6 optionator@0.9.4: @@ -4455,6 +4521,11 @@ snapshots: dependencies: p-limit: 3.1.0 + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -4608,6 +4679,8 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + retry@0.13.1: {} + rollup@4.60.3: dependencies: '@types/estree': 1.0.8 @@ -4833,6 +4906,8 @@ snapshots: wrappy@1.0.2: {} + ws@8.20.0: {} + wsl-utils@0.1.0: dependencies: is-wsl: 3.1.1 diff --git a/src/assertion.ts b/src/assertion.ts index f20b765..23bd099 100644 --- a/src/assertion.ts +++ b/src/assertion.ts @@ -6,6 +6,7 @@ import { logger } from "./logger"; import { resolveModel } from "./models"; import { AssertionResult, AssertionOptions } from "./types"; import { resolvePage, safeSnapshot, withTimeout } from "./utils"; +import { assertVideoFile, deleteGeminiFile, uploadVideoToGemini } from "./video"; const assertionSchema = z.object({ assertionPassed: z.boolean().describe("Indicates whether the assertion passed or not."), @@ -57,9 +58,49 @@ export const assert = async ({ failSilently, maxRetries = 1, onRetry = (retryCount: number, previousResult: AssertionResult) => {}, + video, + videoFilePath, }: AssertionOptions): Promise => { const thinkingEnabled = effort === "high"; + // Video assertion path: when a recorded video is provided, evaluate the + // assertion against the full video using a video-capable Gemini model. + // Consensus isn't available here (Claude doesn't accept video), so this is + // a single-model call. The screenshot/snapshot path below is unchanged. + if (video && videoFilePath) { + logger.debug({ assertion, videoFilePath }, "Running video assertion path"); + const runVideoAssertion = async (): Promise => { + const file = await uploadVideoToGemini(videoFilePath); + try { + return await assertVideoFile({ + assertion, + fileUri: file.uri, + fileMimeType: file.mimeType, + }); + } finally { + await deleteGeminiFile(file.name); + } + }; + + let videoResult = await runVideoAssertion(); + for (let retry = 0; retry < maxRetries && !videoResult.assertionPassed; retry++) { + logger.debug("Video assertion failed, retrying..."); + onRetry(retry, videoResult); + videoResult = await runVideoAssertion(); + } + + test?.info().annotations.push({ + type: "AI Summary (video)", + description: videoResult.reasoning, + }); + + const status = videoResult.assertionPassed ? "✅ passed" : "❌ failed"; + if (!failSilently) { + expect(videoResult.assertionPassed, videoResult.reasoning).toBe(true); + } + return `${videoResult.reasoning}\n\n[Assertion ${status}]`; + } + const runFullAssertion = async (): Promise => { const snapshot = await safeSnapshot(page); const imageContent = images diff --git a/src/config.ts b/src/config.ts index f4788de..dffa078 100644 --- a/src/config.ts +++ b/src/config.ts @@ -98,6 +98,12 @@ type Config = { redis?: RedisConfig; /** Telemetry (Axiom) connection. When omitted, falls back to `AXIOM_TOKEN`/`AXIOM_DATASET` env vars. */ telemetry?: TelemetryConfig; + /** + * Directory used to temporarily store video recordings for video-flagged + * assertions. Defaults to `/tmp/passmark-recordings`. Files are deleted + * after the assertions consume them. + */ + videoDir?: string; }; let globalConfig: Config = {}; diff --git a/src/constants.ts b/src/constants.ts index 195521f..8c14452 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -24,3 +24,11 @@ export const THINKING_BUDGET_DEFAULT = 1024; // Redis export const GLOBAL_VALUES_TTL_SECONDS = 86400; + +// Video assertions +export const VIDEO_DEFAULT_DIR = "/tmp/passmark-recordings"; +export const VIDEO_DEFAULT_WIDTH = 1280; +export const VIDEO_DEFAULT_HEIGHT = 720; +export const VIDEO_FILE_POLL_INTERVAL = 1500; +export const VIDEO_FILE_POLL_TIMEOUT = 120000; +export const VIDEO_ASSERTION_MODEL = "gemini-3-flash-preview"; diff --git a/src/data-cache.ts b/src/data-cache.ts index 17fb9c8..3295fa8 100644 --- a/src/data-cache.ts +++ b/src/data-cache.ts @@ -47,6 +47,12 @@ export type AssertionItem = { assertion: string; effort?: "low" | "high"; images?: string[]; + /** + * When true, `runSteps` records a video while executing the surrounding + * steps and passes it to the assertion for evaluation. Useful for + * ephemeral UI like toasts that a screenshot may miss. + */ + video?: boolean; }; export type ProcessPlaceholdersResult = { diff --git a/src/index.ts b/src/index.ts index 8365e07..5a95521 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,6 +33,7 @@ import { } from "./utils"; import { assert } from "./assertion"; +import { VideoRecorder } from "./video"; import { getDynamicEmail, processPlaceholders, @@ -141,6 +142,24 @@ export const runSteps = async ({ logger.info(`Starting step-by-step execution of ${processedSteps.length} steps.`); + // If any assertion opted into video evaluation, record a single screencast + // spanning the full step run. One recording is shared across all video + // assertions in this call; cleanup happens in a finally block below. + const needsVideo = processedAssertions?.some((a) => a.video) ?? false; + let videoRecorder: VideoRecorder | undefined; + if (needsVideo) { + videoRecorder = new VideoRecorder(tabManager.active()); + try { + await videoRecorder.start(); + } catch (error) { + logger.warn( + { err: error }, + "Failed to start screencast — video assertions will fall back to screenshot/snapshot.", + ); + videoRecorder = undefined; + } + } + let errorInStepExecution, stepThatFailed: string = ""; for (let i = 0; i < processedSteps.length; i++) { @@ -582,60 +601,86 @@ export const runSteps = async ({ }); } + // Stop & delete the recording before re-throwing so we don't leak a + // running screencast or a temp file when steps fail mid-flow. + if (videoRecorder) { + await videoRecorder.stop(); + await videoRecorder.cleanup(); + } + throw new StepExecutionError(errorDescription, stepThatFailed); } - if (processedAssertions && processedAssertions.length > 0 && expect) { - for (const { assertion: preProcessedAssertion, effort, images } of processedAssertions) { - // Re-resolve placeholders against the latest localValues so extracted - // values from steps (e.g. {{run.emailContent}}) get substituted in. - const assertion = replacePlaceholders( - preProcessedAssertion, - localValues, - globalValues, - projectDataValues, - ); - logger.info(`Running assertion: ${assertion}`); + // Stop recording (if any) before running assertions so the saved file is + // ready to upload. Cleanup of the file happens in the finally below. + if (videoRecorder) { + await videoRecorder.stop(); + } - const id = shortid.generate(); + try { + if (processedAssertions && processedAssertions.length > 0 && expect) { + for (const { + assertion: preProcessedAssertion, + effort, + images, + video, + } of processedAssertions) { + // Re-resolve placeholders against the latest localValues so extracted + // values from steps (e.g. {{run.emailContent}}) get substituted in. + const assertion = replacePlaceholders( + preProcessedAssertion, + localValues, + globalValues, + projectDataValues, + ); + logger.info(`Running assertion: ${assertion}`); - if (onStepStart) { - onStepStart({ - id, - description: "Starting assertion verification", - }); - } + const id = shortid.generate(); - if (onReasoning) { - onReasoning({ - id, - reasoning: `Verifying assertion: ${assertion}`, - }); - } + if (onStepStart) { + onStepStart({ + id, + description: "Starting assertion verification", + }); + } - const reasoning = await assert({ - page: tabManager, - assertion, - test, - expect, - effort, - images, - failSilently: failAssertionsSilently, - maxRetries: 1, - onRetry: (retryCount, previousResult) => {}, - }); + if (onReasoning) { + onReasoning({ + id, + reasoning: `Verifying assertion: ${assertion}`, + }); + } - if (onReasoning) { - onReasoning({ - id, - reasoning: `\n\n${reasoning}`, + const reasoning = await assert({ + page: tabManager, + assertion, + test, + expect, + effort, + images, + failSilently: failAssertionsSilently, + maxRetries: 1, + onRetry: (retryCount, previousResult) => {}, + video: video && Boolean(videoRecorder), + videoFilePath: videoRecorder?.filePath, }); - } - if (onStepEnd) { - onStepEnd({ id, description: "Successfully verified assertion" }); + if (onReasoning) { + onReasoning({ + id, + reasoning: `\n\n${reasoning}`, + }); + } + + if (onStepEnd) { + onStepEnd({ id, description: "Successfully verified assertion" }); + } } } + } finally { + if (videoRecorder) { + await videoRecorder.cleanup(); + } } }; diff --git a/src/types.ts b/src/types.ts index e4ff76e..7f9d546 100644 --- a/src/types.ts +++ b/src/types.ts @@ -84,6 +84,19 @@ export type AssertionOptions = { images?: string[]; maxRetries?: number; onRetry?: (retryCount: number, previousResult: AssertionResult) => void; + /** + * When true, `runSteps` records a video across the step run and feeds it + * to a video-capable Gemini model for assertion. Useful for ephemeral UI + * (toasts, banners) that a single screenshot may miss. Standalone `assert` + * callers can also pass `videoFilePath` directly. + */ + video?: boolean; + /** + * Absolute path to a pre-recorded video file (.webm/.mp4) for the + * assertion to evaluate. Set by `runSteps` when `video: true`; can also be + * supplied by callers who record their own video. + */ + videoFilePath?: string; }; export type WaitConditionResult = { diff --git a/src/video.ts b/src/video.ts new file mode 100644 index 0000000..517ea8e --- /dev/null +++ b/src/video.ts @@ -0,0 +1,277 @@ +import type { GoogleGenAI, Schema } from "@google/genai" with { "resolution-mode": "import" }; +import { promises as fs } from "fs"; +import { dirname, join } from "path"; +import shortid from "shortid"; +import { z } from "zod"; + +import { getConfig } from "./config"; +import { + VIDEO_ASSERTION_MODEL, + VIDEO_DEFAULT_DIR, + VIDEO_DEFAULT_HEIGHT, + VIDEO_DEFAULT_WIDTH, + VIDEO_FILE_POLL_INTERVAL, + VIDEO_FILE_POLL_TIMEOUT, +} from "./constants"; +import { AIModelError, ConfigurationError } from "./errors"; +import { logger } from "./logger"; +import { AssertionResult, PageInput } from "./types"; +import { resolvePage } from "./utils"; + +const VIDEO_MIME_TYPE = "video/webm"; + +/** + * Wraps a Playwright `page.screencast` recording for a single video assertion run. + * Records to a unique file in the configured video directory; the file is + * intended to be deleted by the caller once assertions complete. + */ +export class VideoRecorder { + private started = false; + private stopped = false; + readonly filePath: string; + + constructor( + private readonly page: PageInput, + filePath?: string, + ) { + this.filePath = filePath ?? defaultVideoPath(); + } + + async start(): Promise { + if (this.started) return; + await fs.mkdir(dirname(this.filePath), { recursive: true }); + await resolvePage(this.page).screencast.start({ + path: this.filePath, + size: { width: VIDEO_DEFAULT_WIDTH, height: VIDEO_DEFAULT_HEIGHT }, + }); + this.started = true; + logger.debug({ path: this.filePath }, "Video recording started"); + } + + async stop(): Promise { + if (!this.started || this.stopped) return; + this.stopped = true; + try { + await resolvePage(this.page).screencast.stop(); + let sizeBytes: number | null = null; + try { + sizeBytes = (await fs.stat(this.filePath)).size; + } catch { + // File may not exist if save failed; sizeBytes stays null. + } + logger.debug({ path: this.filePath, sizeBytes }, "Video recording stopped"); + } catch (error) { + logger.warn({ err: error }, "Failed to stop video recording cleanly"); + } + } + + async cleanup(): Promise { + try { + await fs.unlink(this.filePath); + logger.debug(`Deleted video file: ${this.filePath}`); + } catch (error: unknown) { + // ENOENT is fine — file may not have been saved if stop() failed + if ((error as NodeJS.ErrnoException)?.code !== "ENOENT") { + logger.warn({ err: error }, `Failed to delete video file: ${this.filePath}`); + } + } + } +} + +function defaultVideoPath(): string { + const dir = getConfig().videoDir ?? VIDEO_DEFAULT_DIR; + return join(dir, `passmark-${shortid.generate()}.webm`); +} + +const videoAssertionSchema = z.object({ + assertionPassed: z.boolean(), + confidenceScore: z.number(), + reasoning: z.string(), +}); + +let _genAI: GoogleGenAI | null = null; + +async function getGenAI(): Promise { + if (_genAI) return _genAI; + const apiKey = + process.env.GOOGLE_GENERATIVE_AI_API_KEY || + process.env.GEMINI_API_KEY || + process.env.GOOGLE_API_KEY; + if (!apiKey) { + throw new ConfigurationError( + "Video assertions require a direct Gemini API key. Set GOOGLE_GENERATIVE_AI_API_KEY (preferred) or GEMINI_API_KEY in your environment. The video file is uploaded to Gemini's Files API regardless of any configured gateway.", + ); + } + // Dynamic import because @google/genai is shipped as ESM; the passmark + // package itself is CommonJS. + const { GoogleGenAI } = await import("@google/genai"); + _genAI = new GoogleGenAI({ apiKey }); + return _genAI; +} + +/** + * Uploads a video file to Gemini's Files API and polls until ACTIVE. + * Returns the file resource that can be referenced from `generateContent`. + */ +export async function uploadVideoToGemini(filePath: string): Promise<{ + name: string; + uri: string; + mimeType: string; +}> { + const ai = await getGenAI(); + logger.debug({ filePath }, "Uploading video to Gemini Files API"); + const uploaded = await ai.files.upload({ + file: filePath, + config: { mimeType: VIDEO_MIME_TYPE }, + }); + logger.debug( + { name: uploaded.name, state: uploaded.state }, + "Gemini Files API upload accepted", + ); + + if (!uploaded.name) { + throw new AIModelError("Gemini Files API did not return a file name after upload."); + } + + const start = Date.now(); + let current = uploaded; + while (current.state !== "ACTIVE") { + if (current.state === "FAILED") { + throw new AIModelError( + `Gemini file processing failed: ${current.error?.message ?? "unknown error"}`, + ); + } + if (Date.now() - start > VIDEO_FILE_POLL_TIMEOUT) { + throw new AIModelError( + `Gemini file did not become ACTIVE within ${VIDEO_FILE_POLL_TIMEOUT}ms (last state: ${current.state}).`, + ); + } + await new Promise((r) => setTimeout(r, VIDEO_FILE_POLL_INTERVAL)); + current = await ai.files.get({ name: uploaded.name }); + logger.debug({ name: uploaded.name, state: current.state }, "Gemini file poll"); + } + + if (!current.uri || !current.mimeType) { + throw new AIModelError("Gemini file is ACTIVE but is missing uri/mimeType."); + } + + logger.debug( + { name: uploaded.name, uri: current.uri, mimeType: current.mimeType }, + "Gemini file ACTIVE", + ); + return { name: uploaded.name, uri: current.uri, mimeType: current.mimeType }; +} + +/** + * Deletes a previously-uploaded Gemini file. Failures are logged but not thrown + * so they never mask a real test failure. + */ +export async function deleteGeminiFile(name: string): Promise { + try { + const ai = await getGenAI(); + await ai.files.delete({ name }); + logger.debug(`Deleted Gemini file: ${name}`); + } catch (error) { + logger.warn({ err: error }, `Failed to delete Gemini file: ${name}`); + } +} + +/** + * Runs an assertion against a video already uploaded to Gemini. + * Uses Gemini 3 Flash with a structured response schema. Unlike the + * snapshot/screenshot path, this is a single-model call — Claude does not + * accept video input, so consensus isn't available here. + */ +export async function assertVideoFile({ + assertion, + fileUri, + fileMimeType, +}: { + assertion: string; + fileUri: string; + fileMimeType: string; +}): Promise { + const prompt = ` +You are an AI-powered QA Agent designed to test web applications. + +You are given a screen recording of a user flow. Inspect the video carefully — pay particular attention to ephemeral UI such as toasts, banners, snackbars, or status messages that may appear and disappear within a second. Based on what you observe across the full video, determine whether the assertion below holds. + + +${assertion} + + + +- Watch the entire video; the relevant evidence may appear only briefly. +- Consider any frame in the video as valid evidence — if the asserted state is visible at any point, the assertion passes. +- Don't add extra conditions beyond what the assertion states. +- Don't be overly strict about exact wording — focus on intent and observable state. +- Think like a practical QA tester. + + + +Return a JSON object with: +- assertionPassed: boolean +- confidenceScore: number between 0 and 100 +- reasoning: brief string explaining your decision + + +Never hallucinate. If unsure, use a low confidence score. +`; + + const ai = await getGenAI(); + const response = await ai.models.generateContent({ + model: VIDEO_ASSERTION_MODEL, + contents: [ + { + role: "user", + parts: [ + { fileData: { fileUri, mimeType: fileMimeType } }, + { text: prompt }, + ], + }, + ], + config: { + temperature: 0, + responseMimeType: "application/json", + responseSchema: { + type: "OBJECT", + properties: { + assertionPassed: { type: "BOOLEAN" }, + confidenceScore: { type: "NUMBER" }, + reasoning: { type: "STRING" }, + }, + required: ["assertionPassed", "confidenceScore", "reasoning"], + } as unknown as Schema, + }, + }); + + const text = response.text; + logger.debug({ text }, "Gemini video assertion raw response"); + if (!text) { + throw new AIModelError("Gemini returned no text for the video assertion."); + } + + let parsed: unknown; + try { + parsed = JSON.parse(text); + } catch { + throw new AIModelError(`Failed to parse Gemini video assertion JSON: ${text}`); + } + + const result = videoAssertionSchema.safeParse(parsed); + if (!result.success) { + throw new AIModelError( + `Gemini video assertion response did not match schema: ${JSON.stringify(parsed)}`, + ); + } + + logger.debug( + { + assertionPassed: result.data.assertionPassed, + confidenceScore: result.data.confidenceScore, + reasoning: result.data.reasoning, + }, + "Gemini video assertion verdict", + ); + return result.data; +} From 54c6e636eaf567a6dc9c72e2c5185b0793040d45 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 12 May 2026 18:14:18 +0530 Subject: [PATCH 26/33] minor copy fix --- src/assertion.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assertion.ts b/src/assertion.ts index 23bd099..0173b4a 100644 --- a/src/assertion.ts +++ b/src/assertion.ts @@ -57,7 +57,7 @@ export const assert = async ({ images, failSilently, maxRetries = 1, - onRetry = (retryCount: number, previousResult: AssertionResult) => {}, + onRetry = (retryCount: number, previousResult: AssertionResult) => { }, video, videoFilePath, }: AssertionOptions): Promise => { @@ -90,7 +90,7 @@ export const assert = async ({ } test?.info().annotations.push({ - type: "AI Summary (video)", + type: "AI Summary (video analysis)", description: videoResult.reasoning, }); From 57b676aa942c236ba068643713879b4ec2619d41 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 12 May 2026 18:15:41 +0530 Subject: [PATCH 27/33] 1.0.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a404fdd..e3c61d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passmark", - "version": "1.0.13", + "version": "1.0.14", "description": "The open-source AI framework for regression testing.", "main": "dist/index.js", "types": "dist/index.d.ts", From e96c92ac871c1abde32a8df56f51bb2c5235069f Mon Sep 17 00:00:00 2001 From: Ipseeta Date: Tue, 12 May 2026 18:50:16 +0530 Subject: [PATCH 28/33] Add consensusPolicy: fail-on-disagreement option for assertions --- README.md | 21 ++++++++- src/__tests__/assertion.test.ts | 78 +++++++++++++++++++++++++++++++++ src/assertion.ts | 22 +++++++++- src/config.ts | 31 +++++++++++++ 4 files changed, 150 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d27e120..dc7d863 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ const result = await runUserFlow({ ### `assert(options: AssertionOptions)` -Multi-model consensus assertion. Runs Claude and Gemini in parallel; if they disagree, a third model arbitrates. +Multi-model consensus assertion. Runs Claude and Gemini in parallel; if they disagree, a third model arbitrates (configurable — see [Consensus Policy](#consensus-policy)). ```typescript const result = await assert({ @@ -226,6 +226,25 @@ const result = await assert({ }); ``` +### Consensus Policy + +When the primary (Claude) and secondary (Gemini) assertion models reach the same verdict, the result is used directly. When they **disagree**, you choose how Passmark resolves it: + +| Policy | Behavior | +|---|---| +| `consult-arbiter-on-disagreement` *(default)* | Calls the arbiter model (Gemini 3.1 Pro) to break the tie. | +| `fail-on-disagreement` | Treats any disagreement as a failure immediately — no arbiter call. The returned reasoning includes both models' takes so you can inspect what they saw differently. | + +Pick `fail-on-disagreement` when you'd rather surface ambiguity/flakiness in the UI under test than let a single model swing the result. Pick the default when you trust the arbiter to make the final call. + +```typescript +configure({ + assertions: { + consensusPolicy: "fail-on-disagreement", + }, +}); +``` + ### Video Assertions For UI that's only visible for a second or two — toast messages, snackbar confirmations, transient banners — a single end-of-flow screenshot often misses the evidence. Set `video: true` on an assertion inside `runSteps` and Passmark will record the entire step run with `page.screencast`, upload the resulting `.webm` to Gemini's Files API, and evaluate the assertion against the full video: diff --git a/src/__tests__/assertion.test.ts b/src/__tests__/assertion.test.ts index 636b1e8..583add3 100644 --- a/src/__tests__/assertion.test.ts +++ b/src/__tests__/assertion.test.ts @@ -36,6 +36,7 @@ vi.mock("../utils", () => ({ })); import { assert } from "../assertion"; +import { configure, resetConfig } from "../config"; import { withTimeout } from "../utils"; import { generateText } from "ai"; @@ -85,6 +86,7 @@ function makeGenerateTextImpl(opts: { beforeEach(() => { vi.clearAllMocks(); + resetConfig(); }); describe("assert consensus logic", () => { @@ -233,3 +235,79 @@ describe("assert consensus logic", () => { expect(res).toContain("✅ passed"); }); }); + +describe("consensusPolicy", () => { + it('fails on disagreement when policy is "fail-on-disagreement" and skips the arbiter', async () => { + configure({ assertions: { consensusPolicy: "fail-on-disagreement" } }); + + const page = createMockPage(); + let arbiterCalled = false; + + vi.mocked(generateText).mockImplementation((async (args: any) => { + const model = String(args.model ?? ""); + const wantsStructured = Boolean(args.output); + if (!wantsStructured) return { text: "claude text" } as any; + if (model.includes("anthropic")) { + return { output: { assertionPassed: true, confidenceScore: 90, reasoning: "Claude says pass" } } as any; + } + if (model.includes("3.1-pro-preview")) { + arbiterCalled = true; + return { output: { assertionPassed: true, confidenceScore: 80, reasoning: "Arbiter should NOT be called" } } as any; + } + if (model.includes("gemini-3-flash")) { + return { output: { assertionPassed: false, confidenceScore: 70, reasoning: "Gemini says fail" } } as any; + } + return { output: { assertionPassed: false, confidenceScore: 0, reasoning: "unknown" } } as any; + }) as any); + + const res = await assert({ + page, + assertion: "The page shows 3 items", + test: mockTest, + expect: ((a: unknown, _m?: string) => ({ toBe: (_v: unknown) => {} })) as any, + failSilently: true, + maxRetries: 0, // skip the outer retry loop so we observe a single attempt + }); + + expect(arbiterCalled).toBe(false); + expect(res).toContain("❌ failed"); + expect(res).toContain("Claude says pass"); + expect(res).toContain("Gemini says fail"); + expect(res).toContain("fail-on-disagreement"); + }); + + it("still consults the arbiter on disagreement when policy is the default", async () => { + // No configure() — should use default "consult-arbiter-on-disagreement" + const page = createMockPage(); + let arbiterCalled = false; + + vi.mocked(generateText).mockImplementation((async (args: any) => { + const model = String(args.model ?? ""); + const wantsStructured = Boolean(args.output); + if (!wantsStructured) return { text: "claude text" } as any; + if (model.includes("anthropic")) { + return { output: { assertionPassed: true, confidenceScore: 90, reasoning: "Claude says pass" } } as any; + } + if (model.includes("3.1-pro-preview")) { + arbiterCalled = true; + return { output: { assertionPassed: true, confidenceScore: 75, reasoning: "Arbiter: pass" } } as any; + } + if (model.includes("gemini-3-flash")) { + return { output: { assertionPassed: false, confidenceScore: 70, reasoning: "Gemini says fail" } } as any; + } + return { output: { assertionPassed: false, confidenceScore: 0, reasoning: "unknown" } } as any; + }) as any); + + const res = await assert({ + page, + assertion: "The page shows 3 items", + test: mockTest, + expect: ((a: unknown, _m?: string) => ({ toBe: (_v: unknown) => {} })) as any, + failSilently: true, + }); + + expect(arbiterCalled).toBe(true); + expect(res).toContain("✅ passed"); + expect(res).toContain("Arbiter: pass"); + }); +}); diff --git a/src/assertion.ts b/src/assertion.ts index 0173b4a..b83152b 100644 --- a/src/assertion.ts +++ b/src/assertion.ts @@ -1,6 +1,6 @@ import { generateText, ModelMessage, Output } from "ai"; import { z } from "zod"; -import { getModelId } from "./config"; +import { getConsensusPolicy, getModelId } from "./config"; import { ASSERTION_MODEL_TIMEOUT, THINKING_BUDGET_DEFAULT } from "./constants"; import { logger } from "./logger"; import { resolveModel } from "./models"; @@ -312,6 +312,26 @@ Please carefully review the evidence (screenshot and accessibility snapshot (whe // Check if models disagree on assertionPassed if (claudeResult.assertionPassed !== geminiResult.assertionPassed) { + const policy = getConsensusPolicy(); + + if (policy === "fail-on-disagreement") { + logger.debug( + "Models disagree on assertion result; failing per consensusPolicy=fail-on-disagreement.", + ); + const lower = Math.min( + claudeResult.confidenceScore, + geminiResult.confidenceScore, + ); + return { + assertionPassed: false, + confidenceScore: Math.round(lower), + reasoning: + `Assertion failed: models disagreed and consensusPolicy is "fail-on-disagreement".\n` + + `Claude (passed=${claudeResult.assertionPassed}, ${claudeResult.confidenceScore}%): ${claudeResult.reasoning}\n` + + `Gemini (passed=${geminiResult.assertionPassed}, ${geminiResult.confidenceScore}%): ${geminiResult.reasoning}`, + }; + } + logger.debug("Models disagree on assertion result, consulting arbiter..."); const arbiterResult = await withTimeout( getArbiterDecision(claudeResult, geminiResult), diff --git a/src/config.ts b/src/config.ts index dffa078..f47cc98 100644 --- a/src/config.ts +++ b/src/config.ts @@ -76,6 +76,27 @@ export type RedisConfig = { url?: string; }; +/** + * Policy for resolving disagreements between the primary and secondary + * assertion models. + * - "consult-arbiter-on-disagreement" (default): a third arbiter model + * makes the final call. Best when you trust the arbiter to break ties. + * - "fail-on-disagreement": any disagreement fails the assertion + * immediately. Strictest possible setting — useful when you'd rather + * surface flakiness/ambiguity than risk a single model being wrong. + */ +export type ConsensusPolicy = + | "consult-arbiter-on-disagreement" + | "fail-on-disagreement"; + +export type AssertionsConfig = { + /** + * How to resolve disagreements between the primary and secondary + * assertion models. Defaults to "consult-arbiter-on-disagreement". + */ + consensusPolicy?: ConsensusPolicy; +}; + export type TelemetryConfig = { /** * Axiom API token for OpenTelemetry tracing of AI calls. @@ -98,6 +119,8 @@ type Config = { redis?: RedisConfig; /** Telemetry (Axiom) connection. When omitted, falls back to `AXIOM_TOKEN`/`AXIOM_DATASET` env vars. */ telemetry?: TelemetryConfig; + /** Behavior of the multi-model assertion consensus engine. */ + assertions?: AssertionsConfig; /** * Directory used to temporarily store video recordings for video-flagged * assertions. Defaults to `/tmp/passmark-recordings`. Files are deleted @@ -161,6 +184,14 @@ export function getMode(): AIMode { return getConfig().ai?.mode ?? "snapshot"; } +/** + * Returns the effective consensus policy. Defaults to + * "consult-arbiter-on-disagreement" so existing users see no change. + */ +export function getConsensusPolicy(): ConsensusPolicy { + return getConfig().assertions?.consensusPolicy ?? "consult-arbiter-on-disagreement"; +} + /** * Effective AI config for a single step / call after merging overrides with * the global config. `getModelId` looks up a model with the same precedence From cfbce7d6d3acbacc18fbd9030816b8c5f5580cac Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Fri, 29 May 2026 14:50:29 +0530 Subject: [PATCH 29/33] support storage of extracted values in global scope --- src/data-cache.ts | 18 ++++++++++++++ src/extract.ts | 58 ++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 62 +++++++++++++++++++---------------------------- src/types.ts | 13 +++++++--- 4 files changed, 111 insertions(+), 40 deletions(-) diff --git a/src/data-cache.ts b/src/data-cache.ts index 3295fa8..216c24e 100644 --- a/src/data-cache.ts +++ b/src/data-cache.ts @@ -22,6 +22,9 @@ export type LocalPlaceholders = { "{{run.email}}": string; "{{run.dynamicEmail}}": string; "{{run.phoneNumber}}": string; +} & { + // Values extracted at runtime via `extract` with scope "local" are stored as {{run.}}. + [key: string]: string; }; /** @@ -35,6 +38,9 @@ export type GlobalPlaceholders = { "{{global.email}}": string; "{{global.dynamicEmail}}": string; "{{global.phoneNumber}}": string; +} & { + // Values extracted at runtime via `extract` with scope "global" are stored as {{global.}}. + [key: string]: string; }; /** @@ -214,6 +220,8 @@ export async function generateGlobalValues( const emailDomain = getConfig().email?.domain; return { + // Preserve any runtime-extracted {{global.}} values so they survive across runSteps calls. + ...(existingValues ?? {}), "{{global.shortid}}": existingValues?.["{{global.shortid}}"] ?? shortid.generate(), "{{global.fullName}}": existingValues?.["{{global.fullName}}"] ?? faker.person.fullName(), "{{global.email}}": existingValues?.["{{global.email}}"] ?? faker.internet.email(), @@ -413,6 +421,16 @@ export async function processPlaceholders( ); } + // Check if any step extracts into the global scope without an executionId + const hasGlobalExtract = steps.some((step) => step.extract?.scope === "global"); + + if (hasGlobalExtract && !executionId) { + throw new ValidationError( + 'extract with scope "global" requires an executionId. ' + + "Please provide executionId in runSteps options to extract values into the global scope.", + ); + } + // Check if project data placeholders are used without projectId const hasProjectDataPlaceholders = stepsContainProjectDataPlaceholders(steps); diff --git a/src/extract.ts b/src/extract.ts index abff50d..e9b1e5b 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -2,6 +2,12 @@ import { generateText, Output } from "ai"; import { z } from "zod"; import { getModelId } from "./config"; import { resolveModel } from "./models"; +import { ValidationError } from "./errors"; +import { GlobalPlaceholders, LocalPlaceholders, saveGlobalValues } from "./data-cache"; +import { logger } from "./logger"; +import { ExtractionConfig } from "./types"; +import { safeSnapshot } from "./utils"; +import { createTabManager } from "./utils/tab-manager"; const extractionSchema = z.object({ extractedValue: z.string().describe("The extracted value based on the prompt"), @@ -68,3 +74,55 @@ Return the extracted value.`, return output.extractedValue; } + +/** + * Runs an `extract` step: pulls a value off the current page with AI and stores + * it under the requested scope so later steps can reference it via placeholder. + * + * - scope "local" (default) → stored as {{run.}} in `localValues`, available + * only within the current runSteps call. + * - scope "global" → stored as {{global.}} in `globalValues` and persisted to + * Redis under `executionId`, so subsequent runSteps calls with the same + * executionId can read it. Requires `executionId`. + */ +export async function applyExtraction({ + extract, + tabManager, + localValues, + globalValues, + executionId, +}: { + extract: ExtractionConfig; + tabManager: ReturnType; + localValues: LocalPlaceholders; + globalValues?: GlobalPlaceholders; + executionId?: string; +}): Promise { + const snapshot = await safeSnapshot(tabManager); + const url = tabManager.active().url(); + const extracted = await extractDataWithAI({ + snapshot, + url, + prompt: extract.prompt, + }); + + const scope = extract.scope ?? "local"; + + if (scope === "global") { + if (!executionId || !globalValues) { + // Should be caught earlier in processPlaceholders, but guard defensively. + throw new ValidationError( + `extract with scope "global" requires an executionId. Cannot extract "${extract.as}" into the global scope.`, + ); + } + const placeholderKey = `{{global.${extract.as}}}`; + globalValues[placeholderKey] = extracted; + // Persist so subsequent runSteps calls with the same executionId can read it. + await saveGlobalValues(executionId, globalValues); + logger.info(`Extracted {{global.${extract.as}}}: "${extracted}"`); + } else { + const placeholderKey = `{{run.${extract.as}}}`; + localValues[placeholderKey] = extracted; + logger.info(`Extracted {{run.${extract.as}}}: "${extracted}"`); + } +} diff --git a/src/index.ts b/src/index.ts index 5a95521..1e4d648 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,7 +42,7 @@ import { } from "./data-cache"; import { resolveAI } from "./config"; import { runCUALoop, buildRunStepsPromptCUA, buildRunUserFlowPromptCUA } from "./cua"; -import { extractDataWithAI } from "./extract"; +import { applyExtraction } from "./extract"; import { logger } from "./logger"; import { resolveModel } from "./models"; import { runSecureScript } from "./utils/secure-script-runner"; @@ -264,16 +264,13 @@ export const runSteps = async ({ // Handle data extraction if specified // This is done post script execution if (step.extract) { - const snapshot = await safeSnapshot(tabManager); - const url = tabManager.active().url(); - const extracted = await extractDataWithAI({ - snapshot, - url, - prompt: step.extract.prompt, + await applyExtraction({ + extract: step.extract, + tabManager, + localValues, + globalValues, + executionId, }); - const placeholderKey = `{{run.${step.extract.as}}}` as keyof typeof localValues; - (localValues as Record)[placeholderKey] = extracted; - logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); } if (onStepEnd) { @@ -342,16 +339,13 @@ export const runSteps = async ({ } if (step.extract) { - const snapshot = await safeSnapshot(tabManager); - const url = tabManager.active().url(); - const extracted = await extractDataWithAI({ - snapshot, - url, - prompt: step.extract.prompt, + await applyExtraction({ + extract: step.extract, + tabManager, + localValues, + globalValues, + executionId, }); - const placeholderKey = `{{run.${step.extract.as}}}` as keyof typeof localValues; - (localValues as Record)[placeholderKey] = extracted; - logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); } if (onStepEnd) { @@ -447,16 +441,13 @@ export const runSteps = async ({ // Handle data extraction if specified // This is done post cached step execution if (step.extract) { - const snapshot = await safeSnapshot(tabManager); - const url = tabManager.active().url(); - const extracted = await extractDataWithAI({ - snapshot, - url, - prompt: step.extract.prompt, + await applyExtraction({ + extract: step.extract, + tabManager, + localValues, + globalValues, + executionId, }); - const placeholderKey = `{{run.${step.extract.as}}}` as keyof typeof localValues; - (localValues as Record)[placeholderKey] = extracted; - logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); } continue; } catch (error) { @@ -573,16 +564,13 @@ export const runSteps = async ({ // Handle data extraction if specified // This is done post AI step execution if (step.extract) { - const snapshot = await safeSnapshot(tabManager); - const url = tabManager.active().url(); - const extracted = await extractDataWithAI({ - snapshot, - url, - prompt: step.extract.prompt, + await applyExtraction({ + extract: step.extract, + tabManager, + localValues, + globalValues, + executionId, }); - const placeholderKey = `{{run.${step.extract.as}}}` as keyof typeof localValues; - (localValues as Record)[placeholderKey] = extracted; - logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); } if (onStepEnd) { diff --git a/src/types.ts b/src/types.ts index 7f9d546..4ae3e62 100644 --- a/src/types.ts +++ b/src/types.ts @@ -42,13 +42,20 @@ export type UserFlowOptions = { /** * Configuration for extracting data from a page using AI. - * The extracted value will be stored as {{run.keyName}} and can be used in subsequent steps. + * The extracted value will be stored under the chosen scope and can be used in subsequent steps. */ export type ExtractionConfig = { - /** Key name - the extracted value will be accessible as {{run.keyName}} in subsequent steps' data.value */ + /** Key name - the extracted value will be accessible as {{run.keyName}} (local scope) or {{global.keyName}} (global scope) in subsequent steps' data.value */ as: string; /** Prompt describing what to extract from the page/URL */ prompt: string; + /** + * Where to store the extracted value. + * - "local" (default): stored as {{run.as}}, available only within the current runSteps call. + * - "global": stored as {{global.as}} and persisted to Redis under the runSteps `executionId`, + * so subsequent runSteps calls with the same executionId can read it. Requires `executionId`. + */ + scope?: "local" | "global"; }; export type Step = { @@ -59,7 +66,7 @@ export type Step = { isScript?: boolean; script?: string; moduleId?: string; - /** Extract data from page/URL using AI and store as {{run.as}} for later use */ + /** Extract data from page/URL using AI and store as {{run.as}} (local) or {{global.as}} (global) for later use */ extract?: ExtractionConfig; /** Switch the active page before this step runs. 'main' = original tab, 'latest' = most recently opened, or numeric index. */ switchToTab?: "main" | "latest" | number; From 79e92a877ec5a8cc107ca93c95d2b6435d40065e Mon Sep 17 00:00:00 2001 From: Unclebigbay Date: Mon, 8 Jun 2026 13:13:20 +0100 Subject: [PATCH 30/33] feat: extend callbackurl to runstep auth --- src/cua/prompts.ts | 46 ++++++++++++++++++++++++++-------------------- src/types.ts | 9 +++++---- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/cua/prompts.ts b/src/cua/prompts.ts index a266b03..3a8bada 100644 --- a/src/cua/prompts.ts +++ b/src/cua/prompts.ts @@ -35,28 +35,32 @@ ${step.description} Current Step Index: ${stepIndex + 1} out of ${steps.length} steps. -${stepIndex + 1 < steps.length - ? ` +${ + stepIndex + 1 < steps.length + ? ` (For context only — DO NOT execute.) Next step: "${steps[stepIndex + 1].description}" ` - : "" - } + : "" +} -${step.data - ? ` +${ + step.data + ? ` Use this data for the current step: ${JSON.stringify(step.data)} ` - : "" - } + : "" +} -${auth - ? ` +${ + auth + ? ` If a login screen appears, use: - Email: ${auth.email} - Password: ${auth.password} +go to this callbackUrl post login: ${auth.callbackUrl} ` - : "" - } + : "" +} - Look at the current screenshot before acting. If the page is still loading, use the wait action. @@ -85,17 +89,19 @@ You are an expert QA agent testing a web application using computer-use capabili ${userFlow} -${steps - ? ` +${ + steps + ? ` Follow these steps in order: ${steps} Stop once all steps are complete. ` - : "" - } + : "" +} -${assertion - ? ` +${ + assertion + ? ` ${assertion} @@ -103,8 +109,8 @@ When the flow is complete, evaluate the assertion and report: - assertionPassed: boolean - confidenceScore: 0-100 - reasoning: short explanation` - : "" - } + : "" +} - Inspect each screenshot before acting. diff --git a/src/types.ts b/src/types.ts index 4ae3e62..a639b6a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,6 +31,7 @@ export type UserFlowOptions = { auth?: { email: string; password: string; + callbackUrl: string; }; model?: LanguageModel; /** @@ -136,7 +137,7 @@ export type RunStepsOptions = { // optional fields bypassCache?: boolean; failAssertionsSilently?: boolean; - auth?: { email: string; password: string }; + auth?: { email: string; password: string; callbackUrl: string }; onStepStart?: (step: { id: string; description: string }) => void; onStepEnd?: (step: { id: string; description: string }) => void; onReasoning?: (step: { id: string; reasoning: string }) => void; @@ -155,9 +156,9 @@ export type RunStepsOptions = { */ ai?: AIOverride; } & ( - | { + | { assertions: Omit[]; expect: Expect<{}>; } - | { assertions?: never; expect?: never } - ); + | { assertions?: never; expect?: never } +); From 93f50cdf21a24b01a69b63111a14313118bbcf9f Mon Sep 17 00:00:00 2001 From: Unclebigbay Date: Mon, 8 Jun 2026 13:20:03 +0100 Subject: [PATCH 31/33] chore: undo formatting --- src/cua/prompts.ts | 48 ++++++++++++++++++++-------------------------- src/types.ts | 6 +++--- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/cua/prompts.ts b/src/cua/prompts.ts index 3a8bada..8f65bc9 100644 --- a/src/cua/prompts.ts +++ b/src/cua/prompts.ts @@ -35,32 +35,28 @@ ${step.description} Current Step Index: ${stepIndex + 1} out of ${steps.length} steps. -${ - stepIndex + 1 < steps.length - ? ` +${stepIndex + 1 < steps.length + ? ` (For context only — DO NOT execute.) Next step: "${steps[stepIndex + 1].description}" ` - : "" -} + : "" + } -${ - step.data - ? ` +${step.data + ? ` Use this data for the current step: ${JSON.stringify(step.data)} ` - : "" -} + : "" + } -${ - auth - ? ` +${auth + ? ` If a login screen appears, use: - Email: ${auth.email} - Password: ${auth.password} -go to this callbackUrl post login: ${auth.callbackUrl} -` - : "" -} + go to this callbackUrl post login: ${auth.callbackUrl}` + : "" + } - Look at the current screenshot before acting. If the page is still loading, use the wait action. @@ -89,19 +85,17 @@ You are an expert QA agent testing a web application using computer-use capabili ${userFlow} -${ - steps - ? ` +${steps + ? ` Follow these steps in order: ${steps} Stop once all steps are complete. ` - : "" -} + : "" + } -${ - assertion - ? ` +${assertion + ? ` ${assertion} @@ -109,8 +103,8 @@ When the flow is complete, evaluate the assertion and report: - assertionPassed: boolean - confidenceScore: 0-100 - reasoning: short explanation` - : "" -} + : "" + } - Inspect each screenshot before acting. diff --git a/src/types.ts b/src/types.ts index a639b6a..62b5680 100644 --- a/src/types.ts +++ b/src/types.ts @@ -156,9 +156,9 @@ export type RunStepsOptions = { */ ai?: AIOverride; } & ( - | { + | { assertions: Omit[]; expect: Expect<{}>; } - | { assertions?: never; expect?: never } -); + | { assertions?: never; expect?: never } + ); From ca0694de724bd0c9ff99288fef9edbb2ab0b3b2c Mon Sep 17 00:00:00 2001 From: Unclebigbay Date: Mon, 8 Jun 2026 15:26:34 +0100 Subject: [PATCH 32/33] chore: make callbackurl optional --- src/cua/prompts.ts | 4 ++-- src/prompts/index.ts | 2 +- src/types.ts | 14 ++++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/cua/prompts.ts b/src/cua/prompts.ts index 8f65bc9..d0c8a5a 100644 --- a/src/cua/prompts.ts +++ b/src/cua/prompts.ts @@ -53,8 +53,8 @@ ${auth ? ` If a login screen appears, use: - Email: ${auth.email} -- Password: ${auth.password} - go to this callbackUrl post login: ${auth.callbackUrl}` +- Password: ${auth.password}${auth.callbackUrl ? `\n- Go to this callbackUrl post login: ${auth.callbackUrl}` : ""} +` : "" } diff --git a/src/prompts/index.ts b/src/prompts/index.ts index b2643b2..cf878ba 100644 --- a/src/prompts/index.ts +++ b/src/prompts/index.ts @@ -55,7 +55,7 @@ Use the following data for the current step: If presented with login screen, log in to the website using the following credentials: - Email: ${auth.email} - - Password: ${auth.password} + - Password: ${auth.password}${auth.callbackUrl ? `\n - Go to this callbackUrl post login: ${auth.callbackUrl}` : ""} ` : "" } diff --git a/src/types.ts b/src/types.ts index 62b5680..38f826f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,12 @@ export type AssertionResult = { reasoning: string; // Brief explanation of the reasoning behind the assertion }; +export type AuthConfig = { + email: string; + password: string; + callbackUrl?: string; +}; + export type UserFlowOptions = { page: Page; userFlow: string; @@ -28,11 +34,7 @@ export type UserFlowOptions = { assertion?: string; effort?: "low" | "high"; thinkingBudget?: number; // in tokens, default 1024 - auth?: { - email: string; - password: string; - callbackUrl: string; - }; + auth?: AuthConfig; model?: LanguageModel; /** * Override the AI mode/gateway/models for this user-flow run only. @@ -137,7 +139,7 @@ export type RunStepsOptions = { // optional fields bypassCache?: boolean; failAssertionsSilently?: boolean; - auth?: { email: string; password: string; callbackUrl: string }; + auth?: AuthConfig; onStepStart?: (step: { id: string; description: string }) => void; onStepEnd?: (step: { id: string; description: string }) => void; onReasoning?: (step: { id: string; reasoning: string }) => void; From 435b2b458c1bb157e3077b072a6802723dc383ad Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 15 Jun 2026 12:40:46 +0000 Subject: [PATCH 33/33] Remove committed dist/ directory The dist/ build output is already listed in .gitignore and should not be tracked. Per maintainer review feedback on PR #36, untrack it. --- dist/assertion.d.ts | 29 - dist/assertion.js | 290 ---- dist/cache.d.ts | 10 - dist/cache.js | 156 -- dist/config.d.ts | 69 - dist/config.js | 53 - dist/constants.d.ts | 19 - dist/constants.js | 26 - dist/data-cache.d.ts | 134 -- dist/data-cache.js | 388 ----- dist/email.d.ts | 46 - dist/email.js | 77 - dist/errors.d.ts | 61 - dist/errors.js | 91 - dist/extract.d.ts | 24 - dist/extract.js | 62 - dist/index.d.ts | 97 -- dist/index.js | 572 ------- dist/instrumentation.d.ts | 1 - dist/instrumentation.js | 36 - dist/logger.d.ts | 2 - dist/logger.js | 14 - dist/models.d.ts | 18 - dist/models.js | 173 -- dist/prompts/index.d.ts | 6 - dist/prompts/index.js | 112 -- dist/providers/emailsink.d.ts | 11 - dist/providers/emailsink.js | 38 - dist/redis.d.ts | 3 - dist/redis.js | 16 - dist/tools.d.ts | 188 --- dist/tools.js | 500 ------ dist/types.d.ts | 109 -- dist/types.js | 2 - dist/utils/index.d.ts | 67 - dist/utils/index.js | 298 ---- dist/utils/playwright-best-practices.d.ts | 2 - dist/utils/playwright-best-practices.js | 110 -- dist/utils/secure-script-runner.d.ts | 40 - dist/utils/secure-script-runner.js | 1830 --------------------- dist/utils/tab-manager.d.ts | 8 - dist/utils/tab-manager.js | 47 - 42 files changed, 5835 deletions(-) delete mode 100644 dist/assertion.d.ts delete mode 100644 dist/assertion.js delete mode 100644 dist/cache.d.ts delete mode 100644 dist/cache.js delete mode 100644 dist/config.d.ts delete mode 100644 dist/config.js delete mode 100644 dist/constants.d.ts delete mode 100644 dist/constants.js delete mode 100644 dist/data-cache.d.ts delete mode 100644 dist/data-cache.js delete mode 100644 dist/email.d.ts delete mode 100644 dist/email.js delete mode 100644 dist/errors.d.ts delete mode 100644 dist/errors.js delete mode 100644 dist/extract.d.ts delete mode 100644 dist/extract.js delete mode 100644 dist/index.d.ts delete mode 100644 dist/index.js delete mode 100644 dist/instrumentation.d.ts delete mode 100644 dist/instrumentation.js delete mode 100644 dist/logger.d.ts delete mode 100644 dist/logger.js delete mode 100644 dist/models.d.ts delete mode 100644 dist/models.js delete mode 100644 dist/prompts/index.d.ts delete mode 100644 dist/prompts/index.js delete mode 100644 dist/providers/emailsink.d.ts delete mode 100644 dist/providers/emailsink.js delete mode 100644 dist/redis.d.ts delete mode 100644 dist/redis.js delete mode 100644 dist/tools.d.ts delete mode 100644 dist/tools.js delete mode 100644 dist/types.d.ts delete mode 100644 dist/types.js delete mode 100644 dist/utils/index.d.ts delete mode 100644 dist/utils/index.js delete mode 100644 dist/utils/playwright-best-practices.d.ts delete mode 100644 dist/utils/playwright-best-practices.js delete mode 100644 dist/utils/secure-script-runner.d.ts delete mode 100644 dist/utils/secure-script-runner.js delete mode 100644 dist/utils/tab-manager.d.ts delete mode 100644 dist/utils/tab-manager.js diff --git a/dist/assertion.d.ts b/dist/assertion.d.ts deleted file mode 100644 index 9fcf4ad..0000000 --- a/dist/assertion.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { AssertionOptions } from "./types"; -/** - * Multi-model consensus assertion engine. - * Runs Claude and Gemini in parallel; if they disagree, a third model (arbiter) makes the final call. - * An assertion passes only if both models agree (or the arbiter decides). - * Automatically retries failed assertions once with a fresh page snapshot. - * - * @param options - Assertion configuration - * @param options.page - The Playwright page instance to take snapshots from - * @param options.assertion - Natural language assertion to validate (e.g. "The cart shows 3 items") - * @param options.expect - Playwright expect function, used to fail the test on assertion failure - * @param options.effort - "low" (default) or "high" — high enables thinking mode for deeper analysis - * @param options.images - Optional base64 screenshot images to provide to the models - * @param options.failSilently - When true, returns the result without failing the test - * @param options.test - Playwright test instance for attaching metadata - * @returns A string summary of the assertion result - * @throws Fails the Playwright test via expect when assertion fails (unless failSilently is true) - * - * @example - * ```typescript - * await assert({ - * page, - * assertion: "The dashboard shows 3 active projects", - * expect, - * effort: "high", - * }); - * ``` - */ -export declare const assert: ({ page, assertion, test, expect, effort, images, failSilently, maxRetries, onRetry, }: AssertionOptions) => Promise; diff --git a/dist/assertion.js b/dist/assertion.js deleted file mode 100644 index 8c7c1e9..0000000 --- a/dist/assertion.js +++ /dev/null @@ -1,290 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.assert = void 0; -const ai_1 = require("ai"); -const zod_1 = require("zod"); -const config_1 = require("./config"); -const constants_1 = require("./constants"); -const logger_1 = require("./logger"); -const models_1 = require("./models"); -const utils_1 = require("./utils"); -const assertionSchema = zod_1.z.object({ - assertionPassed: zod_1.z.boolean().describe("Indicates whether the assertion passed or not."), - confidenceScore: zod_1.z - .number() - .describe("Confidence score of the assertion, between 0 and 100."), - reasoning: zod_1.z - .string() - .describe("Brief explanation of the reasoning behind your decision - explain why the assertion passed or failed."), -}); -/** - * Multi-model consensus assertion engine. - * Runs Claude and Gemini in parallel; if they disagree, a third model (arbiter) makes the final call. - * An assertion passes only if both models agree (or the arbiter decides). - * Automatically retries failed assertions once with a fresh page snapshot. - * - * @param options - Assertion configuration - * @param options.page - The Playwright page instance to take snapshots from - * @param options.assertion - Natural language assertion to validate (e.g. "The cart shows 3 items") - * @param options.expect - Playwright expect function, used to fail the test on assertion failure - * @param options.effort - "low" (default) or "high" — high enables thinking mode for deeper analysis - * @param options.images - Optional base64 screenshot images to provide to the models - * @param options.failSilently - When true, returns the result without failing the test - * @param options.test - Playwright test instance for attaching metadata - * @returns A string summary of the assertion result - * @throws Fails the Playwright test via expect when assertion fails (unless failSilently is true) - * - * @example - * ```typescript - * await assert({ - * page, - * assertion: "The dashboard shows 3 active projects", - * expect, - * effort: "high", - * }); - * ``` - */ -const assert = async ({ page, assertion, test, expect, effort = "low", images, failSilently, maxRetries = 1, onRetry = (retryCount, previousResult) => { }, }) => { - const thinkingEnabled = effort === "high"; - const runFullAssertion = async () => { - const snapshot = await (0, utils_1.safeSnapshot)(page); - const imageContent = images - ? images.map((image) => ({ type: "image", image })) - : [ - { - type: "image", - image: (await (0, utils_1.resolvePage)(page).screenshot({ fullPage: false })).toString("base64"), - }, - ]; - const basePrompt = ` -You are an AI-powered QA Agent designed to test web applications. - -You have access to the following information. Based on this information, you'll tell us whether the assertion provided below should pass or not. -${!images - ? ` -- An accessibility snapshot of the current page, which provides a detailed structure of the DOM -- A screenshot of the current page` - : "- Screenshots from various stages of the user flow"} - -${!images - ? ` - -${snapshot} - -` - : ""} - - -${assertion} - - - -- First use the attached screenshot(s) to visually inspect the page and try to verify the assertion. -- Only if the screenshot is not sufficient, use the accessibility snapshot (if supplied) to verify the assertion. -- Don't create additional assertion conditions on your own - only consider the exact assertion provided above. -- The assertion should pass if either the screenshot or the accessibility snapshot supports it. -- Don't be overly strict or pedantic about exact wording. Focus on the intent and objective of the assertion rather than literal text matching. -- Think like a practical QA tester - if the core functionality or state being asserted is present, the assertion should pass even if minor details differ. - - - - The output should contain the following information: - - \`assertionPassed\`: A boolean indicating whether the assertion passed or not. - - \`confidenceScore\`: A number between 0 and 100 indicating the confidence score of the assertion. - - \`reasoning\`: A brief string explaining the reasoning behind the assertion. - - -Never hallucinate. Be truthful and if you are not sure, use a low confidence score. -`; - const messages = [ - { - role: "user", - content: [ - { - type: "text", - text: basePrompt, - }, - ...imageContent, - ], - }, - ]; - // Claude assertion function - const getClaudeAssertion = async () => { - // First get Claude's text response with thinking if enabled - const { text } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("assertionPrimary")), - temperature: 0, - providerOptions: thinkingEnabled - ? { - anthropic: { - thinking: { type: "enabled", budgetTokens: constants_1.THINKING_BUDGET_DEFAULT }, - }, - openrouter: { - reasoning: { max_tokens: constants_1.THINKING_BUDGET_DEFAULT }, - }, - } - : undefined, - messages, - }); - // Convert Claude's response to structured format using Haiku - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("assertionPrimary")), - temperature: 0.1, - prompt: `Convert the following text output into a valid JSON object with the specified properties:\n\n${text}`, - output: ai_1.Output.object({ schema: assertionSchema }), - }); - return output; - }; - // Gemini assertion function - const getGeminiAssertion = async () => { - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("assertionSecondary")), - temperature: 0, - providerOptions: thinkingEnabled - ? { - google: { - thinkingConfig: { - thinkingBudget: constants_1.THINKING_BUDGET_DEFAULT, - }, - }, - openrouter: { - reasoning: { max_tokens: constants_1.THINKING_BUDGET_DEFAULT }, - }, - } - : undefined, - messages, - output: ai_1.Output.object({ schema: assertionSchema }), - }); - return output; - }; - // Arbiter function using Gemini 2.5 Pro with thinking enabled - const getArbiterDecision = async (claudeResult, geminiResult) => { - const arbiterPrompt = ` -You are an AI arbiter tasked with resolving a disagreement between two AI models about an assertion. - -Claude's Assessment: -- Assertion Passed: ${claudeResult.assertionPassed} -- Confidence: ${claudeResult.confidenceScore}% -- Reasoning: ${claudeResult.reasoning} - -Gemini's Assessment: -- Assertion Passed: ${geminiResult.assertionPassed} -- Confidence: ${geminiResult.confidenceScore}% -- Reasoning: ${geminiResult.reasoning} - -${!images - ? ` - -${snapshot} - -` - : ""} - - -${assertion} - - -Please carefully review the evidence (screenshot and accessibility snapshot (when provided)) and make the final determination. Consider both models' reasoning but make your own independent assessment. - - -- Make your own independent evaluation based on the evidence -- Don't simply pick one model's answer - analyze the situation yourself -- Provide clear reasoning for your decision -- Be decisive - this is the final answer -- First use the attached screenshot(s) to visually inspect the page and try to verify the assertion. -- Only if the screenshot is not sufficient, use the accessibility snapshot (if supplied) to verify the assertion. -- Don't create additional assertion conditions on your own - only consider the exact assertion provided above. -- The assertion should pass if either the screenshot or the accessibility snapshot supports it. -- Don't be overly strict or pedantic about exact wording. Focus on the intent and objective of the assertion rather than literal text matching. -- Think like a practical QA tester - if the core functionality or state being asserted is present, the assertion should pass even if minor details differ. - -`; - const arbiterMessages = [ - { - role: "user", - content: [ - { - type: "text", - text: arbiterPrompt, - }, - ...imageContent, - ], - }, - ]; - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("assertionArbiter")), - temperature: 0, - providerOptions: { - google: { - thinkingConfig: { - thinkingBudget: constants_1.THINKING_BUDGET_DEFAULT, - }, - }, - openrouter: { - reasoning: { max_tokens: constants_1.THINKING_BUDGET_DEFAULT }, - }, - }, - messages: arbiterMessages, - output: ai_1.Output.object({ schema: assertionSchema }), - }); - return output; - }; - const runAssertion = async (attempt = 0) => { - try { - // Run both models in parallel for speed optimization - const [claudeResult, geminiResult] = await Promise.all([ - (0, utils_1.withTimeout)(getClaudeAssertion(), constants_1.ASSERTION_MODEL_TIMEOUT), - (0, utils_1.withTimeout)(getGeminiAssertion(), constants_1.ASSERTION_MODEL_TIMEOUT), - ]); - // Check if models disagree on assertionPassed - if (claudeResult.assertionPassed !== geminiResult.assertionPassed) { - logger_1.logger.debug("Models disagree on assertion result, consulting arbiter..."); - const arbiterResult = await (0, utils_1.withTimeout)(getArbiterDecision(claudeResult, geminiResult), constants_1.ASSERTION_MODEL_TIMEOUT); - return { - assertionPassed: arbiterResult.assertionPassed, - confidenceScore: arbiterResult.confidenceScore, - reasoning: arbiterResult.reasoning, - }; - } - // Assertion passes only if both models agree it should pass - const assertionPassed = claudeResult.assertionPassed && geminiResult.assertionPassed; - // Calculate average confidence score - const confidenceScore = (claudeResult.confidenceScore + geminiResult.confidenceScore) / 2; - // For now take Gemini's reasoning for simplicity - const reasoning = geminiResult.reasoning; - return { - assertionPassed, - confidenceScore: Math.round(confidenceScore), - reasoning, - }; - } - catch (error) { - if (attempt < 1) { - logger_1.logger.debug("Retrying assertion due to error..."); - return await runAssertion(attempt + 1); - } - logger_1.logger.error({ err: error }, "Error running assertions after multiple retries"); - throw error; - } - }; - return await runAssertion(); - }; - // Run assertion with retry on failure - let result = await runFullAssertion(); - for (let retry = 0; retry < maxRetries && !result.assertionPassed; retry++) { - logger_1.logger.debug("Assertion failed, retrying with fresh snapshot and screenshot..."); - onRetry(retry, result); - result = await runFullAssertion(); - } - const { assertionPassed, reasoning } = result; - test?.info().annotations.push({ - type: "AI Summary", - description: reasoning, - }); - const expectStatus = assertionPassed ? "✅ passed" : "❌ failed"; - if (!failSilently) { - expect(assertionPassed, reasoning).toBe(true); - } - return `${reasoning}\n\n[Assertion ${expectStatus}]`; -}; -exports.assert = assert; diff --git a/dist/cache.d.ts b/dist/cache.d.ts deleted file mode 100644 index 4c43ccc..0000000 --- a/dist/cache.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Interface for a hash-based cache store. - * Implementations must support hash get/set and key expiration. - */ -export interface CacheStore { - hgetall(key: string): Promise>; - hset(key: string, values: Record): Promise; - expire(key: string, seconds: number): Promise; -} -export declare const cache: CacheStore | null; diff --git a/dist/cache.js b/dist/cache.js deleted file mode 100644 index 79767fa..0000000 --- a/dist/cache.js +++ /dev/null @@ -1,156 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cache = void 0; -const logger_1 = require("./logger"); -// ============================================================================= -// Redis Store -// ============================================================================= -class RedisStore { - client; - constructor(url) { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const Redis = require("ioredis"); - this.client = new Redis(url); - } - async hgetall(key) { - return this.client.hgetall(key); - } - async hset(key, values) { - await this.client.hset(key, values); - } - async expire(key, seconds) { - await this.client.expire(key, seconds); - } -} -// ============================================================================= -// File Store -// ============================================================================= -const fs = __importStar(require("fs")); -const path = __importStar(require("path")); -class FileStore { - dir; - constructor(dir) { - this.dir = dir; - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - } - filePath(key) { - // Encode key to a safe filename - const safeKey = encodeURIComponent(key); - return path.join(this.dir, `${safeKey}.json`); - } - read(key) { - const fp = this.filePath(key); - if (!fs.existsSync(fp)) - return null; - try { - const raw = JSON.parse(fs.readFileSync(fp, "utf-8")); - // Check expiration - if (raw.expiresAt && Date.now() > raw.expiresAt) { - fs.unlinkSync(fp); - return null; - } - return raw; - } - catch { - return null; - } - } - write(key, entry) { - const fp = this.filePath(key); - fs.writeFileSync(fp, JSON.stringify(entry), "utf-8"); - } - async hgetall(key) { - const entry = this.read(key); - return entry?.data ?? {}; - } - async hset(key, values) { - const existing = this.read(key); - const merged = { ...(existing?.data ?? {}), ...values }; - this.write(key, { data: merged, expiresAt: existing?.expiresAt }); - } - async expire(key, seconds) { - const existing = this.read(key); - if (!existing) - return; - this.write(key, { ...existing, expiresAt: Date.now() + seconds * 1000 }); - } -} -// ============================================================================= -// Factory -// ============================================================================= -/** - * Creates the cache store based on environment variables. - * - * CACHE_PROVIDER selects the backend: - * - "redis" (default when REDIS_URL is set): uses Redis via ioredis - * - "file": uses JSON files on disk at CACHE_DIR (defaults to .passmark-cache) - * - "none": disables caching entirely - * - * For backwards compatibility, if CACHE_PROVIDER is not set: - * - If REDIS_URL is set → uses Redis - * - Otherwise → caching is disabled (null) - */ -function createCacheStore() { - const provider = process.env.CACHE_PROVIDER?.toLowerCase(); - if (provider === "none") { - logger_1.logger.warn("Cache provider set to 'none'. Caching is disabled."); - return null; - } - if (provider === "file") { - const dir = process.env.CACHE_DIR || ".passmark-cache"; - logger_1.logger.info(`Using file-based cache at: ${dir}`); - return new FileStore(dir); - } - if (provider === "redis" || (!provider && process.env.REDIS_URL)) { - if (!process.env.REDIS_URL) { - logger_1.logger.warn("CACHE_PROVIDER is 'redis' but REDIS_URL is not set. Caching is disabled."); - return null; - } - logger_1.logger.info("Using Redis cache."); - return new RedisStore(process.env.REDIS_URL); - } - if (provider) { - logger_1.logger.warn(`Unknown CACHE_PROVIDER '${provider}'. Caching is disabled.`); - return null; - } - // No CACHE_PROVIDER and no REDIS_URL - logger_1.logger.warn("No cache provider configured. Set CACHE_PROVIDER=redis|file|none or REDIS_URL. " + - "Step caching, global placeholders, and project data are disabled."); - return null; -} -exports.cache = createCacheStore(); diff --git a/dist/config.d.ts b/dist/config.d.ts deleted file mode 100644 index 033c829..0000000 --- a/dist/config.d.ts +++ /dev/null @@ -1,69 +0,0 @@ -export type EmailProvider = { - /** Domain for generating test emails (e.g. "emailsink.dev") */ - domain: string; - /** - * Function to extract content from an email. - * Called with the email address and a prompt describing what to extract. - * Should return the extracted string value. - */ - extractContent: (params: { - email: string; - prompt: string; - }) => Promise; -}; -export type AIGateway = "vercel" | "openrouter" | "cloudflare" | "none"; -export type ModelConfig = { - /** Model for executing individual steps. Default: google/gemini-3-flash */ - stepExecution?: string; - /** Model for running user flows (low effort). Default: google/gemini-3-flash-preview */ - userFlowLow?: string; - /** Model for running user flows (high effort). Default: google/gemini-3.1-pro-preview */ - userFlowHigh?: string; - /** Model for assertions (primary). Default: anthropic/claude-haiku-4.5 */ - assertionPrimary?: string; - /** Model for assertions (secondary). Default: google/gemini-3-flash */ - assertionSecondary?: string; - /** Model for assertion arbiter. Default: google/gemini-3.1-pro-preview */ - assertionArbiter?: string; - /** Model for data extraction, wait conditions, and lightweight tasks. Default: google/gemini-2.5-flash */ - utility?: string; -}; -export declare const DEFAULT_MODELS: Required; -type Config = { - email?: EmailProvider; - ai?: { - gateway?: AIGateway; - models?: ModelConfig; - }; - /** Base path for file uploads. Default: "./uploads" */ - uploadBasePath?: string; -}; -/** - * Sets global configuration for Passmark. Call once before using any functions. - * Subsequent calls merge with existing config (does not reset unset fields). - * - * @param config - Configuration options for AI gateway, models, email, and uploads - * - * @example - * ```typescript - * configure({ - * ai: { gateway: "none", models: { stepExecution: "google/gemini-3-flash" } }, - * email: { domain: "test.com", extractContent: async ({ email, prompt }) => "..." }, - * }); - * ``` - */ -export declare function configure(config: Config): void; -/** - * Returns the current global configuration. - */ -export declare function getConfig(): Config; -/** - * Returns the configured model ID for a given use case, falling back to the default. - * - * @param key - The model use case key (e.g. "stepExecution", "utility") - * @returns The model identifier string (e.g. "google/gemini-3-flash") - */ -export declare function getModelId(key: keyof ModelConfig): string; -/** @internal Reset config to empty state. Used for testing only. */ -export declare function resetConfig(): void; -export {}; diff --git a/dist/config.js b/dist/config.js deleted file mode 100644 index 3f6bac8..0000000 --- a/dist/config.js +++ /dev/null @@ -1,53 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.DEFAULT_MODELS = void 0; -exports.configure = configure; -exports.getConfig = getConfig; -exports.getModelId = getModelId; -exports.resetConfig = resetConfig; -exports.DEFAULT_MODELS = { - stepExecution: "google/gemini-3-flash", - userFlowLow: "google/gemini-3-flash", - userFlowHigh: "google/gemini-3.1-pro-preview", - assertionPrimary: "anthropic/claude-haiku-4.5", - assertionSecondary: "google/gemini-3-flash", - assertionArbiter: "google/gemini-3.1-pro-preview", - utility: "google/gemini-2.5-flash", -}; -let globalConfig = {}; -/** - * Sets global configuration for Passmark. Call once before using any functions. - * Subsequent calls merge with existing config (does not reset unset fields). - * - * @param config - Configuration options for AI gateway, models, email, and uploads - * - * @example - * ```typescript - * configure({ - * ai: { gateway: "none", models: { stepExecution: "google/gemini-3-flash" } }, - * email: { domain: "test.com", extractContent: async ({ email, prompt }) => "..." }, - * }); - * ``` - */ -function configure(config) { - globalConfig = { ...globalConfig, ...config }; -} -/** - * Returns the current global configuration. - */ -function getConfig() { - return globalConfig; -} -/** - * Returns the configured model ID for a given use case, falling back to the default. - * - * @param key - The model use case key (e.g. "stepExecution", "utility") - * @returns The model identifier string (e.g. "google/gemini-3-flash") - */ -function getModelId(key) { - return getConfig().ai?.models?.[key] ?? exports.DEFAULT_MODELS[key]; -} -/** @internal Reset config to empty state. Used for testing only. */ -function resetConfig() { - globalConfig = {}; -} diff --git a/dist/constants.d.ts b/dist/constants.d.ts deleted file mode 100644 index f6993d5..0000000 --- a/dist/constants.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -export declare const LOCATOR_ACTION_TIMEOUT = 2000; -export declare const CACHED_ACTION_TIMEOUT = 5000; -export declare const STOP_DELAY = 3000; -export declare const SNAPSHOT_TIMEOUT = 5000; -export declare const DOM_STABILIZATION_IDLE = 500; -export declare const DOM_STABILIZATION_TIMEOUT = 5000; -export declare const INITIAL_DOM_STABILIZATION_IDLE = 3000; -export declare const ASSERTION_MODEL_TIMEOUT = 35000; -export declare const STEP_EXECUTION_TIMEOUT = 180000; -export declare const WAIT_CONDITION_TIMEOUT = 120000; -export declare const WAIT_CONDITION_INITIAL_INTERVAL = 1000; -export declare const WAIT_CONDITION_MAX_INTERVAL = 10000; -export declare const EMAIL_INITIAL_WAIT = 5000; -export declare const EMAIL_RETRY_DELAY = 60000; -export declare const STEP_EXECUTION_MAX_STEPS = 25; -export declare const USER_FLOW_MAX_STEPS = 50; -export declare const MAX_RETRIES = 3; -export declare const THINKING_BUDGET_DEFAULT = 1024; -export declare const GLOBAL_VALUES_TTL_SECONDS = 86400; diff --git a/dist/constants.js b/dist/constants.js deleted file mode 100644 index 54af458..0000000 --- a/dist/constants.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.GLOBAL_VALUES_TTL_SECONDS = exports.THINKING_BUDGET_DEFAULT = exports.MAX_RETRIES = exports.USER_FLOW_MAX_STEPS = exports.STEP_EXECUTION_MAX_STEPS = exports.EMAIL_RETRY_DELAY = exports.EMAIL_INITIAL_WAIT = exports.WAIT_CONDITION_MAX_INTERVAL = exports.WAIT_CONDITION_INITIAL_INTERVAL = exports.WAIT_CONDITION_TIMEOUT = exports.STEP_EXECUTION_TIMEOUT = exports.ASSERTION_MODEL_TIMEOUT = exports.INITIAL_DOM_STABILIZATION_IDLE = exports.DOM_STABILIZATION_TIMEOUT = exports.DOM_STABILIZATION_IDLE = exports.SNAPSHOT_TIMEOUT = exports.STOP_DELAY = exports.CACHED_ACTION_TIMEOUT = exports.LOCATOR_ACTION_TIMEOUT = void 0; -// Timeouts (milliseconds) -exports.LOCATOR_ACTION_TIMEOUT = 2000; -exports.CACHED_ACTION_TIMEOUT = 5000; -exports.STOP_DELAY = 3000; -exports.SNAPSHOT_TIMEOUT = 5000; -exports.DOM_STABILIZATION_IDLE = 500; -exports.DOM_STABILIZATION_TIMEOUT = 5000; -exports.INITIAL_DOM_STABILIZATION_IDLE = 3000; -exports.ASSERTION_MODEL_TIMEOUT = 35000; -exports.STEP_EXECUTION_TIMEOUT = 180000; -exports.WAIT_CONDITION_TIMEOUT = 120000; -exports.WAIT_CONDITION_INITIAL_INTERVAL = 1000; -exports.WAIT_CONDITION_MAX_INTERVAL = 10000; -exports.EMAIL_INITIAL_WAIT = 5000; -exports.EMAIL_RETRY_DELAY = 60000; -// Limits -exports.STEP_EXECUTION_MAX_STEPS = 25; -exports.USER_FLOW_MAX_STEPS = 50; -exports.MAX_RETRIES = 3; -// Thinking budgets (tokens) -exports.THINKING_BUDGET_DEFAULT = 1024; -// Cache -exports.GLOBAL_VALUES_TTL_SECONDS = 86400; diff --git a/dist/data-cache.d.ts b/dist/data-cache.d.ts deleted file mode 100644 index a503bbe..0000000 --- a/dist/data-cache.d.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Step } from "./types"; -/** - * Local placeholders that are fresh for each runSteps call. - * These values are NOT persisted and are regenerated every time. - */ -export type LocalPlaceholders = { - "{{run.shortid}}": string; - "{{run.fullName}}": string; - "{{run.email}}": string; - "{{run.dynamicEmail}}": string; - "{{run.phoneNumber}}": string; -}; -/** - * Global placeholders that are shared across all tests within an execution. - * These values are persisted to the cache and loaded for subsequent runSteps calls - * with the same executionId. - */ -export type GlobalPlaceholders = { - "{{global.shortid}}": string; - "{{global.fullName}}": string; - "{{global.email}}": string; - "{{global.dynamicEmail}}": string; - "{{global.phoneNumber}}": string; -}; -/** - * Project data placeholders for {{data.key}} syntax. - * These are stored in the cache and managed via project settings. - */ -export type ProjectDataPlaceholders = Record; -export type AssertionItem = { - assertion: string; - effort?: "low" | "high"; - images?: string[]; -}; -export type ProcessPlaceholdersResult = { - processedSteps: Step[]; - processedAssertions?: AssertionItem[]; - localValues: LocalPlaceholders; - globalValues?: GlobalPlaceholders; - projectDataValues?: ProjectDataPlaceholders; -}; -/** - * Pattern to match email extraction placeholders. - * Format: {{email.:}} or {{email.::}} - * Examples: - * - {{email.otp:get the 6 digit verification code}} - * - {{email.otp:get the 6 digit verification code:sandeep@bug0.ai}} - * - {{email.link:get the magic link url}} - * - {{email.code:get the confirmation code}} - */ -export declare const EMAIL_EXTRACTION_PATTERN: RegExp; -export declare const LOCAL_PLACEHOLDER_KEYS: (keyof LocalPlaceholders)[]; -export declare const GLOBAL_PLACEHOLDER_KEYS: (keyof GlobalPlaceholders)[]; -/** - * Fetches global values from the cache for a given execution ID. - * Returns null if no values exist. - */ -export declare function getGlobalValues(executionId: string): Promise | null>; -/** - * Saves global values to the cache for a given execution ID. - * Sets a 24-hour TTL on the key. - */ -export declare function saveGlobalValues(executionId: string, values: GlobalPlaceholders): Promise; -/** - * Fetches project data from the cache for a given project ID. - * Returns an empty object if no data exists. - */ -export declare function getProjectData(projectId: string): Promise; -/** - * Generates local values for placeholders. - * These are fresh for each runSteps call. - */ -export declare function generateLocalValues(): Promise; -/** - * Generates global values, reusing any existing values provided. - * Only generates values for keys that don't exist in existingValues. - */ -export declare function generateGlobalValues(existingValues: Partial | null): Promise; -/** - * Checks if any text contains global placeholders. - */ -export declare function containsGlobalPlaceholder(text: string): boolean; -/** - * Scans steps for any global placeholders. - * Returns true if any step description, data value, or script contains a global placeholder. - */ -export declare function stepsContainGlobalPlaceholders(steps: { - description: string; - data?: Record; - script?: string; - waitUntil?: string; -}[]): boolean; -/** - * Scans assertions for any global placeholders. - */ -export declare function assertionsContainGlobalPlaceholders(assertions?: { - assertion: string; -}[]): boolean; -/** - * Checks if any text contains project data placeholders. - */ -export declare function containsProjectDataPlaceholder(text: string): boolean; -/** - * Scans steps for any project data placeholders. - * Returns true if any step description, data value, or script contains a project data placeholder. - */ -export declare function stepsContainProjectDataPlaceholders(steps: { - description: string; - data?: Record; - script?: string; - waitUntil?: string; -}[]): boolean; -/** - * Replaces dynamic placeholders in a string with their corresponding values. - * Handles {{run.*}}, {{global.*}}, and {{data.*}} placeholders. - */ -export declare function replacePlaceholders(text: string, localValues: LocalPlaceholders, globalValues?: GlobalPlaceholders, projectDataValues?: ProjectDataPlaceholders): string; -/** - * Processes steps and assertions to replace dynamic placeholders with consistent values. - * Handles {{run.*}} placeholders (fresh per call), {{global.*}} placeholders - * (shared across execution via cache), and {{data.*}} placeholders (project data from cache). - * Returns the processed steps and assertions along with the generated values. - */ -export declare function processPlaceholders(steps: Step[], assertions?: AssertionItem[], executionId?: string, projectId?: string): Promise; -/** - * Gets the dynamic email to use for email extraction. - * Prefers global email if available, otherwise falls back to local email. - */ -export declare function getDynamicEmail(localValues: LocalPlaceholders, globalValues?: GlobalPlaceholders): string; -/** - * Resolves email extraction placeholders in step data. - * This should be called just before step execution to ensure emails have arrived. - */ -export declare function resolveEmailPlaceholders(step: Step, dynamicEmail: string): Promise; diff --git a/dist/data-cache.js b/dist/data-cache.js deleted file mode 100644 index e10290e..0000000 --- a/dist/data-cache.js +++ /dev/null @@ -1,388 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.GLOBAL_PLACEHOLDER_KEYS = exports.LOCAL_PLACEHOLDER_KEYS = exports.EMAIL_EXTRACTION_PATTERN = void 0; -exports.getGlobalValues = getGlobalValues; -exports.saveGlobalValues = saveGlobalValues; -exports.getProjectData = getProjectData; -exports.generateLocalValues = generateLocalValues; -exports.generateGlobalValues = generateGlobalValues; -exports.containsGlobalPlaceholder = containsGlobalPlaceholder; -exports.stepsContainGlobalPlaceholders = stepsContainGlobalPlaceholders; -exports.assertionsContainGlobalPlaceholders = assertionsContainGlobalPlaceholders; -exports.containsProjectDataPlaceholder = containsProjectDataPlaceholder; -exports.stepsContainProjectDataPlaceholders = stepsContainProjectDataPlaceholders; -exports.replacePlaceholders = replacePlaceholders; -exports.processPlaceholders = processPlaceholders; -exports.getDynamicEmail = getDynamicEmail; -exports.resolveEmailPlaceholders = resolveEmailPlaceholders; -const errors_1 = require("./errors"); -const shortid_1 = __importDefault(require("shortid")); -const config_1 = require("./config"); -const email_1 = require("./email"); -const constants_1 = require("./constants"); -const logger_1 = require("./logger"); -const cache_1 = require("./cache"); -const utils_1 = require("./utils"); -// ============================================================================= -// Constants -// ============================================================================= -/** - * Pattern to match email extraction placeholders. - * Format: {{email.:}} or {{email.::}} - * Examples: - * - {{email.otp:get the 6 digit verification code}} - * - {{email.otp:get the 6 digit verification code:sandeep@bug0.ai}} - * - {{email.link:get the magic link url}} - * - {{email.code:get the confirmation code}} - */ -exports.EMAIL_EXTRACTION_PATTERN = /\{\{email\.(\w+):([^:}]+)(?::([^}]+))?\}\}/; -exports.LOCAL_PLACEHOLDER_KEYS = [ - "{{run.shortid}}", - "{{run.fullName}}", - "{{run.email}}", - "{{run.dynamicEmail}}", - "{{run.phoneNumber}}", -]; -exports.GLOBAL_PLACEHOLDER_KEYS = [ - "{{global.shortid}}", - "{{global.fullName}}", - "{{global.email}}", - "{{global.dynamicEmail}}", - "{{global.phoneNumber}}", -]; -/** Pattern to detect any global placeholder in text */ -const GLOBAL_PLACEHOLDER_PATTERN = /\{\{global\.\w+\}\}/; -/** Pattern to detect any project data placeholder in text */ -const PROJECT_DATA_PLACEHOLDER_PATTERN = /\{\{data\.(\w+)\}\}/g; -// ============================================================================= -// Cache Operations (Global Values) -// ============================================================================= -/** - * Generates a cache key for storing global values for an execution. - */ -function getCacheKey(executionId) { - return `execution:${executionId}:globals`; -} -/** - * Fetches global values from the cache for a given execution ID. - * Returns null if no values exist. - */ -async function getGlobalValues(executionId) { - if (!cache_1.cache) - return null; - const key = getCacheKey(executionId); - const values = await cache_1.cache.hgetall(key); - if (!values || Object.keys(values).length === 0) { - return null; - } - return values; -} -/** - * Saves global values to the cache for a given execution ID. - * Sets a 24-hour TTL on the key. - */ -async function saveGlobalValues(executionId, values) { - if (!cache_1.cache) - return; - const key = getCacheKey(executionId); - // Save all values as a hash - await cache_1.cache.hset(key, values); - // Set TTL - await cache_1.cache.expire(key, constants_1.GLOBAL_VALUES_TTL_SECONDS); - logger_1.logger.debug(`Saved global values to cache for execution: ${executionId}`); -} -// ============================================================================= -// Cache Operations (Project Data) -// ============================================================================= -/** - * Generates a cache key for storing project data. - */ -function getProjectDataCacheKey(projectId) { - return `project:${projectId}:data`; -} -/** - * Fetches project data from the cache for a given project ID. - * Returns an empty object if no data exists. - */ -async function getProjectData(projectId) { - if (!cache_1.cache) - return {}; - const key = getProjectDataCacheKey(projectId); - const values = await cache_1.cache.hgetall(key); - if (!values || Object.keys(values).length === 0) { - return {}; - } - return values; -} -// ============================================================================= -// Value Generation -// ============================================================================= -/** - * Generates local values for placeholders. - * These are fresh for each runSteps call. - */ -async function generateLocalValues() { - const { faker } = await import("@faker-js/faker"); - const { v4: uuidv4 } = await import("uuid"); - const emailDomain = (0, config_1.getConfig)().email?.domain; - return { - "{{run.shortid}}": shortid_1.default.generate(), - "{{run.fullName}}": faker.person.fullName(), - "{{run.email}}": faker.internet.email(), - "{{run.dynamicEmail}}": emailDomain ? `e2e-tester-${uuidv4()}@${emailDomain}` : "", - "{{run.phoneNumber}}": (0, utils_1.generatePhoneNumber)(), - }; -} -/** - * Generates global values, reusing any existing values provided. - * Only generates values for keys that don't exist in existingValues. - */ -async function generateGlobalValues(existingValues) { - const { faker } = await import("@faker-js/faker"); - const { v4: uuidv4 } = await import("uuid"); - const emailDomain = (0, config_1.getConfig)().email?.domain; - return { - "{{global.shortid}}": existingValues?.["{{global.shortid}}"] ?? shortid_1.default.generate(), - "{{global.fullName}}": existingValues?.["{{global.fullName}}"] ?? faker.person.fullName(), - "{{global.email}}": existingValues?.["{{global.email}}"] ?? faker.internet.email(), - "{{global.dynamicEmail}}": existingValues?.["{{global.dynamicEmail}}"] ?? - (emailDomain ? `e2e-tester-${uuidv4()}@${emailDomain}` : ""), - "{{global.phoneNumber}}": existingValues?.["{{global.phoneNumber}}"] ?? (0, utils_1.generatePhoneNumber)(), - }; -} -// ============================================================================= -// Placeholder Detection -// ============================================================================= -/** - * Checks if any text contains global placeholders. - */ -function containsGlobalPlaceholder(text) { - return GLOBAL_PLACEHOLDER_PATTERN.test(text); -} -/** - * Scans steps for any global placeholders. - * Returns true if any step description, data value, or script contains a global placeholder. - */ -function stepsContainGlobalPlaceholders(steps) { - for (const step of steps) { - if (containsGlobalPlaceholder(step.description)) { - return true; - } - if (step.data) { - for (const value of Object.values(step.data)) { - if (containsGlobalPlaceholder(value)) { - return true; - } - } - } - if (step.script && containsGlobalPlaceholder(step.script)) { - return true; - } - if (step.waitUntil && containsGlobalPlaceholder(step.waitUntil)) { - return true; - } - } - return false; -} -/** - * Scans assertions for any global placeholders. - */ -function assertionsContainGlobalPlaceholders(assertions) { - if (!assertions) - return false; - for (const item of assertions) { - if (containsGlobalPlaceholder(item.assertion)) { - return true; - } - } - return false; -} -/** - * Checks if any text contains project data placeholders. - */ -function containsProjectDataPlaceholder(text) { - // Reset lastIndex since we're using a global regex - PROJECT_DATA_PLACEHOLDER_PATTERN.lastIndex = 0; - return PROJECT_DATA_PLACEHOLDER_PATTERN.test(text); -} -/** - * Scans steps for any project data placeholders. - * Returns true if any step description, data value, or script contains a project data placeholder. - */ -function stepsContainProjectDataPlaceholders(steps) { - for (const step of steps) { - if (containsProjectDataPlaceholder(step.description)) { - return true; - } - if (step.data) { - for (const value of Object.values(step.data)) { - if (containsProjectDataPlaceholder(value)) { - return true; - } - } - } - if (step.script && containsProjectDataPlaceholder(step.script)) { - return true; - } - if (step.waitUntil && containsProjectDataPlaceholder(step.waitUntil)) { - return true; - } - } - return false; -} -// ============================================================================= -// Placeholder Replacement -// ============================================================================= -/** - * Replaces dynamic placeholders in a string with their corresponding values. - * Handles {{run.*}}, {{global.*}}, and {{data.*}} placeholders. - */ -function replacePlaceholders(text, localValues, globalValues, projectDataValues) { - let result = text; - // Throw if dynamicEmail placeholders are used without an email provider configured - const dynamicEmailPlaceholders = ["{{run.dynamicEmail}}", "{{global.dynamicEmail}}"]; - for (const placeholder of dynamicEmailPlaceholders) { - if (result.includes(placeholder) && !(0, config_1.getConfig)().email) { - throw new errors_1.ConfigurationError(`Email provider not configured. Call configure({ email: ... }) before using ${placeholder}.`); - } - } - // Replace {{run.*}} placeholders - for (const [placeholder, value] of Object.entries(localValues)) { - result = result.split(placeholder).join(value); - } - // Replace {{global.*}} placeholders - if (globalValues) { - for (const [placeholder, value] of Object.entries(globalValues)) { - result = result.split(placeholder).join(value); - } - } - // Replace {{data.key}} placeholders - if (projectDataValues) { - result = result.replace(/\{\{data\.(\w+)\}\}/g, (match, key) => { - const value = projectDataValues[key]; - if (value === undefined) { - logger_1.logger.warn(`[ProjectData] Placeholder ${match} not found`); - return match; - } - return value; - }); - } - return result; -} -// ============================================================================= -// Main Processing Function -// ============================================================================= -/** - * Processes steps and assertions to replace dynamic placeholders with consistent values. - * Handles {{run.*}} placeholders (fresh per call), {{global.*}} placeholders - * (shared across execution via cache), and {{data.*}} placeholders (project data from cache). - * Returns the processed steps and assertions along with the generated values. - */ -async function processPlaceholders(steps, assertions, executionId, projectId) { - // Check if global placeholders are used without executionId - const hasGlobalPlaceholders = stepsContainGlobalPlaceholders(steps) || assertionsContainGlobalPlaceholders(assertions); - if (hasGlobalPlaceholders && !executionId) { - throw new errors_1.ValidationError("{{global.*}} placeholders require an executionId. " + - "Please provide executionId in runSteps options to use global placeholders."); - } - // Check if project data placeholders are used without projectId - const hasProjectDataPlaceholders = stepsContainProjectDataPlaceholders(steps); - if (hasProjectDataPlaceholders && !projectId) { - throw new errors_1.ValidationError("{{data.*}} placeholders require a projectId. " + - "Please provide projectId in runSteps options to use project data placeholders."); - } - // Generate fresh run values (always new per runSteps call) - const localValues = await generateLocalValues(); - // Handle global values if executionId is provided - let globalValues; - if (executionId) { - // Try to load existing global values from Redis - const existingGlobalValues = await getGlobalValues(executionId); - // Generate global values, reusing existing ones - globalValues = await generateGlobalValues(existingGlobalValues); - // Save global values back to Redis (updates TTL and adds any new values) - await saveGlobalValues(executionId, globalValues); - logger_1.logger.debug({ globalValues }, `Using global values for execution ${executionId}`); - } - // Fetch project data if projectId is provided - let projectDataValues; - if (projectId) { - projectDataValues = await getProjectData(projectId); - logger_1.logger.debug({ projectDataValues }, `Using project data for project ${projectId}`); - } - // Deep clone and process steps - // Note: Email extraction placeholders ({{email.xxx:prompt}}) are NOT resolved here. - // They are resolved lazily in runSteps just before each step executes. - const processedSteps = steps.map((step) => { - const processedStep = { ...step }; - if (processedStep.data) { - processedStep.data = { ...processedStep.data }; - for (const key in processedStep.data) { - processedStep.data[key] = replacePlaceholders(processedStep.data[key], localValues, globalValues, projectDataValues); - } - } - // Process script placeholders if present - if (processedStep.script) { - processedStep.script = replacePlaceholders(processedStep.script, localValues, globalValues, projectDataValues); - } - // Process waitUntil placeholders if present - if (processedStep.waitUntil) { - processedStep.waitUntil = replacePlaceholders(processedStep.waitUntil, localValues, globalValues, projectDataValues); - } - return processedStep; - }); - // Process assertions if provided - let processedAssertions; - if (assertions) { - processedAssertions = assertions.map((assertionItem) => ({ - ...assertionItem, - assertion: replacePlaceholders(assertionItem.assertion, localValues, globalValues, projectDataValues), - })); - } - return { - processedSteps, - processedAssertions, - localValues, - globalValues, - projectDataValues, - }; -} -/** - * Gets the dynamic email to use for email extraction. - * Prefers global email if available, otherwise falls back to local email. - */ -function getDynamicEmail(localValues, globalValues) { - return globalValues?.["{{global.dynamicEmail}}"] || localValues["{{run.dynamicEmail}}"]; -} -/** - * Resolves email extraction placeholders in step data. - * This should be called just before step execution to ensure emails have arrived. - */ -async function resolveEmailPlaceholders(step, dynamicEmail) { - if (!step.data) - return step; - const resolvedData = { ...step.data }; - let hasEmailExtraction = false; - for (const key in resolvedData) { - const value = resolvedData[key]; - const match = value.match(exports.EMAIL_EXTRACTION_PATTERN); - if (match) { - hasEmailExtraction = true; - const [fullMatch, extractType, prompt, explicitEmail] = match; - const targetEmail = explicitEmail?.trim() || dynamicEmail; - logger_1.logger.debug(`Extracting ${extractType} from ${targetEmail} with prompt: "${prompt}"`); - const extractedValue = await (0, email_1.extractEmailContent)({ - email: targetEmail, - prompt: prompt.trim(), - }); - resolvedData[key] = value.replace(fullMatch, extractedValue); - } - } - if (hasEmailExtraction) { - return { ...step, data: resolvedData }; - } - return step; -} diff --git a/dist/email.d.ts b/dist/email.d.ts deleted file mode 100644 index 99e1011..0000000 --- a/dist/email.d.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Generates a unique test email address using the configured email provider's domain. - * - * @param options - Optional email generation parameters - * @param options.prefix - Email prefix before the timestamp. Default: "test.user" - * @param options.timestamp - Timestamp for uniqueness. Default: Date.now() - * @returns Email address in the format `prefix.timestamp@domain` - * @throws If no email provider is configured via `configure()` - * - * @example - * ```typescript - * const email = generateEmail(); // "test.user.1711234567890@emailsink.dev" - * const custom = generateEmail({ prefix: "signup" }); // "signup.1711234567890@emailsink.dev" - * ``` - */ -export declare const generateEmail: ({ prefix, timestamp, }?: { - prefix?: string; - timestamp?: number; -}) => string; -/** - * Extracts content from an email using the configured email provider. - * Waits for the email to arrive, then polls the provider with retries. - * - * @param options - Extraction configuration - * @param options.email - The email address to extract content from - * @param options.prompt - Natural language prompt describing what to extract (e.g. "get the 6 digit verification code") - * @param options.maxRetries - Maximum number of extraction attempts. Default: 3 - * @param options.retryDelayMs - Delay between retries in milliseconds. Default: 60000 (1 minute) - * @returns The extracted content as a string - * @throws If no email provider is configured via `configure()` - * @throws If content cannot be extracted after all retry attempts - * - * @example - * ```typescript - * const otp = await extractEmailContent({ - * email: "test.user.123@emailsink.dev", - * prompt: "get the 6 digit verification code", - * }); - * ``` - */ -export declare function extractEmailContent({ email, prompt, maxRetries, retryDelayMs, }: { - email: string; - prompt: string; - maxRetries?: number; - retryDelayMs?: number; -}): Promise; diff --git a/dist/email.js b/dist/email.js deleted file mode 100644 index dd116c7..0000000 --- a/dist/email.js +++ /dev/null @@ -1,77 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.generateEmail = void 0; -exports.extractEmailContent = extractEmailContent; -const errors_1 = require("./errors"); -const config_1 = require("./config"); -const constants_1 = require("./constants"); -const logger_1 = require("./logger"); -function getEmailProvider() { - const provider = (0, config_1.getConfig)().email; - if (!provider) { - throw new errors_1.ConfigurationError("Email provider not configured. Call configure({ email: ... }) before using email features."); - } - return provider; -} -/** - * Generates a unique test email address using the configured email provider's domain. - * - * @param options - Optional email generation parameters - * @param options.prefix - Email prefix before the timestamp. Default: "test.user" - * @param options.timestamp - Timestamp for uniqueness. Default: Date.now() - * @returns Email address in the format `prefix.timestamp@domain` - * @throws If no email provider is configured via `configure()` - * - * @example - * ```typescript - * const email = generateEmail(); // "test.user.1711234567890@emailsink.dev" - * const custom = generateEmail({ prefix: "signup" }); // "signup.1711234567890@emailsink.dev" - * ``` - */ -const generateEmail = ({ prefix = "test.user", timestamp = Date.now(), } = {}) => { - const { domain } = getEmailProvider(); - return `${prefix}.${timestamp}@${domain}`; -}; -exports.generateEmail = generateEmail; -/** - * Extracts content from an email using the configured email provider. - * Waits for the email to arrive, then polls the provider with retries. - * - * @param options - Extraction configuration - * @param options.email - The email address to extract content from - * @param options.prompt - Natural language prompt describing what to extract (e.g. "get the 6 digit verification code") - * @param options.maxRetries - Maximum number of extraction attempts. Default: 3 - * @param options.retryDelayMs - Delay between retries in milliseconds. Default: 60000 (1 minute) - * @returns The extracted content as a string - * @throws If no email provider is configured via `configure()` - * @throws If content cannot be extracted after all retry attempts - * - * @example - * ```typescript - * const otp = await extractEmailContent({ - * email: "test.user.123@emailsink.dev", - * prompt: "get the 6 digit verification code", - * }); - * ``` - */ -async function extractEmailContent({ email, prompt, maxRetries = constants_1.MAX_RETRIES, retryDelayMs = constants_1.EMAIL_RETRY_DELAY, }) { - const provider = getEmailProvider(); - // Add an initial delay before the first attempt to allow email to arrive - logger_1.logger.info(`Initial wait before extracting email content for ${email}...`); - await new Promise((resolve) => setTimeout(resolve, constants_1.EMAIL_INITIAL_WAIT)); - for (let attempt = 1; attempt <= maxRetries; attempt++) { - logger_1.logger.debug(`Waiting for email content (attempt ${attempt}/${maxRetries})...`); - try { - const result = await provider.extractContent({ email, prompt }); - logger_1.logger.info(`Successfully extracted email content: ${result}`); - return result; - } - catch (error) { - logger_1.logger.warn(`Error fetching email content (attempt ${attempt}): ${error}`); - } - if (attempt < maxRetries) { - await new Promise((resolve) => setTimeout(resolve, retryDelayMs)); - } - } - throw new errors_1.AIModelError(`Failed to extract email content after ${maxRetries} attempts. Email: ${email}, Prompt: ${prompt}`); -} diff --git a/dist/errors.d.ts b/dist/errors.d.ts deleted file mode 100644 index d2abcc2..0000000 --- a/dist/errors.d.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * errors.ts - * - * Custom error hierarchy for Passmark. - * All Passmark errors extend PassmarkError so callers can distinguish - * framework errors from generic runtime errors with a simple instanceof check. - * - * Usage: - * import { StepExecutionError, AIModelError } from "./errors"; - * - * try { ... } - * catch (e) { - * if (e instanceof StepExecutionError) { ... } - * } - */ -export declare class PassmarkError extends Error { - /** Machine-readable error code, stable across versions. */ - readonly code: string; - constructor(message: string, code: string); -} -/** - * Thrown when a test step fails during AI or cached execution. - * - * Replaces: throw new Error(errorDescription) in index.ts - */ -export declare class StepExecutionError extends PassmarkError { - readonly stepDescription: string; - constructor(message: string, stepDescription: string); -} -/** - * Thrown when an AI model call fails or the provider is misconfigured. - * - * Replaces: throw new Error(`Unknown AI provider: ${provider}`) in models.ts - */ -export declare class AIModelError extends PassmarkError { - constructor(message: string); -} -/** - * Thrown when a Redis operation fails or cache is unavailable. - * - * For future use as Redis error handling gets more granular. - */ -export declare class CacheError extends PassmarkError { - constructor(message: string); -} -/** - * Thrown when required environment variables or configuration are missing. - * - * Replaces: throw new Error("GOOGLE_GENERATIVE_AI_API_KEY isn't set...") in models.ts - */ -export declare class ConfigurationError extends PassmarkError { - constructor(message: string); -} -/** - * Thrown when input fails validation (e.g. a script step has no script). - * - * Replaces: throw new Error(`Script step ${step.description} has no script content.`) - */ -export declare class ValidationError extends PassmarkError { - constructor(message: string); -} diff --git a/dist/errors.js b/dist/errors.js deleted file mode 100644 index d433228..0000000 --- a/dist/errors.js +++ /dev/null @@ -1,91 +0,0 @@ -"use strict"; -/** - * errors.ts - * - * Custom error hierarchy for Passmark. - * All Passmark errors extend PassmarkError so callers can distinguish - * framework errors from generic runtime errors with a simple instanceof check. - * - * Usage: - * import { StepExecutionError, AIModelError } from "./errors"; - * - * try { ... } - * catch (e) { - * if (e instanceof StepExecutionError) { ... } - * } - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ValidationError = exports.ConfigurationError = exports.CacheError = exports.AIModelError = exports.StepExecutionError = exports.PassmarkError = void 0; -// ─── Base ───────────────────────────────────────────────────────────────── -class PassmarkError extends Error { - /** Machine-readable error code, stable across versions. */ - code; - constructor(message, code) { - super(message); - this.name = this.constructor.name; - this.code = code; - // Maintains proper stack trace in V8 (Node.js / Chrome) - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } - } -} -exports.PassmarkError = PassmarkError; -// ─── Subclasses ─────────────────────────────────────────────────────────── -/** - * Thrown when a test step fails during AI or cached execution. - * - * Replaces: throw new Error(errorDescription) in index.ts - */ -class StepExecutionError extends PassmarkError { - stepDescription; - constructor(message, stepDescription) { - super(message, "STEP_EXECUTION_FAILED"); - this.stepDescription = stepDescription; - } -} -exports.StepExecutionError = StepExecutionError; -/** - * Thrown when an AI model call fails or the provider is misconfigured. - * - * Replaces: throw new Error(`Unknown AI provider: ${provider}`) in models.ts - */ -class AIModelError extends PassmarkError { - constructor(message) { - super(message, "AI_MODEL_ERROR"); - } -} -exports.AIModelError = AIModelError; -/** - * Thrown when a Redis operation fails or cache is unavailable. - * - * For future use as Redis error handling gets more granular. - */ -class CacheError extends PassmarkError { - constructor(message) { - super(message, "CACHE_ERROR"); - } -} -exports.CacheError = CacheError; -/** - * Thrown when required environment variables or configuration are missing. - * - * Replaces: throw new Error("GOOGLE_GENERATIVE_AI_API_KEY isn't set...") in models.ts - */ -class ConfigurationError extends PassmarkError { - constructor(message) { - super(message, "CONFIGURATION_ERROR"); - } -} -exports.ConfigurationError = ConfigurationError; -/** - * Thrown when input fails validation (e.g. a script step has no script). - * - * Replaces: throw new Error(`Script step ${step.description} has no script content.`) - */ -class ValidationError extends PassmarkError { - constructor(message) { - super(message, "VALIDATION_ERROR"); - } -} -exports.ValidationError = ValidationError; diff --git a/dist/extract.d.ts b/dist/extract.d.ts deleted file mode 100644 index 44e0584..0000000 --- a/dist/extract.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Extracts data from a page snapshot and URL using AI. - * Uses Gemini 2.5 Flash for fast, accurate extraction. - * - * @param snapshot - The accessibility snapshot of the page - * @param url - The current page URL - * @param prompt - The extraction prompt describing what to extract - * @returns The extracted value as a string - * - * @example - * ```typescript - * const token = await extractDataWithAI({ - * snapshot: await safeSnapshot(page), - * url: page.url(), - * prompt: 'Extract the token query parameter value from the URL' - * }); - * // Returns: "abc123" - * ``` - */ -export declare function extractDataWithAI({ snapshot, url, prompt, }: { - snapshot: string; - url: string; - prompt: string; -}): Promise; diff --git a/dist/extract.js b/dist/extract.js deleted file mode 100644 index 6685a04..0000000 --- a/dist/extract.js +++ /dev/null @@ -1,62 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.extractDataWithAI = extractDataWithAI; -const ai_1 = require("ai"); -const zod_1 = require("zod"); -const config_1 = require("./config"); -const models_1 = require("./models"); -const extractionSchema = zod_1.z.object({ - extractedValue: zod_1.z.string().describe("The extracted value based on the prompt"), -}); -/** - * Extracts data from a page snapshot and URL using AI. - * Uses Gemini 2.5 Flash for fast, accurate extraction. - * - * @param snapshot - The accessibility snapshot of the page - * @param url - The current page URL - * @param prompt - The extraction prompt describing what to extract - * @returns The extracted value as a string - * - * @example - * ```typescript - * const token = await extractDataWithAI({ - * snapshot: await safeSnapshot(page), - * url: page.url(), - * prompt: 'Extract the token query parameter value from the URL' - * }); - * // Returns: "abc123" - * ``` - */ -async function extractDataWithAI({ snapshot, url, prompt, }) { - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("utility")), - temperature: 0, - output: ai_1.Output.object({ schema: extractionSchema }), - prompt: `You are an AI assistant that extracts specific data from web pages. - -Given the following page snapshot and URL, extract the value described in the extraction prompt. - - -${url} - - - -${snapshot} - - - -${prompt} - - - -- Extract exactly what is requested in the prompt -- If extracting from the URL, parse query parameters, path segments, or hash values as needed -- If extracting from the page content, find the relevant text in the snapshot -- Return only the extracted value, not the surrounding context -- If the value cannot be found, return an empty string - - -Return the extracted value.`, - }); - return output.extractedValue; -} diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index d83f7fc..0000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,97 +0,0 @@ -import "./instrumentation"; -import { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType } from "@playwright/test"; -import { RunStepsOptions, UserFlowOptions } from "./types"; -/** - * Executes a sequence of test steps using AI with intelligent caching. - * Each step is described in natural language and executed via browser automation. - * Successfully executed steps are cached for faster subsequent runs. - * - * @param options - Configuration including page, steps, assertions, and callbacks - * @param options.page - The Playwright page instance - * @param options.userFlow - Name of the user flow (used as cache key prefix) - * @param options.steps - Array of steps to execute, each with a description and optional data - * @param options.bypassCache - When true, skips cache and forces AI execution for all steps - * @param options.assertions - Optional assertions to verify after step execution - * @param options.executionId - Links multiple runSteps calls to share {{global.*}} placeholders - * @param options.onStepStart - Callback fired when a step begins execution - * @param options.onStepEnd - Callback fired when a step completes - * @param options.onReasoning - Callback fired with AI reasoning for each tool call - * @throws Rethrows step execution timeout errors - * - * @example - * ```typescript - * await runSteps({ - * page, - * userFlow: "Checkout Flow", - * steps: [ - * { description: "Add item to cart" }, - * { description: "Fill in email", data: { value: "{{run.email}}" } }, - * ], - * assertions: [{ assertion: "Order confirmation is displayed" }], - * expect, - * }); - * ``` - */ -export declare const runSteps: ({ page, test, expect, userFlow, steps, auth, bypassCache, onStepStart, onStepEnd, onReasoning, assertions, projectId, executionId, failAssertionsSilently, }: RunStepsOptions) => Promise; -/** - * Runs a complete user flow as a single AI agent call. - * Best for exploratory testing where exact steps are flexible. - * The AI autonomously navigates, interacts, and verifies the flow. - * - * @param options - User flow configuration - * @param options.page - The Playwright page instance - * @param options.userFlow - Description of the user flow to execute - * @param options.steps - Natural language description of steps to perform - * @param options.effort - "low" uses a faster model, "high" uses a more capable model with deeper thinking - * @param options.assertion - Optional assertion to verify after the flow completes - * @returns The assertion result if an assertion was provided, the raw AI text response otherwise, or undefined on error - * - * @example - * ```typescript - * const result = await runUserFlow({ - * page, - * userFlow: "Complete a purchase", - * steps: "Navigate to store, add an item, checkout", - * effort: "high", - * assertion: "Order confirmation is displayed", - * }); - * ``` - */ -export declare const runUserFlow: ({ page, userFlow, steps, assertion, effort, thinkingBudget, }: UserFlowOptions) => Promise; -/** - * Wraps a cached Playwright flow with AI fallback for auto-healing. - * Tries the cached flow first; if it fails (e.g., due to UI changes), falls back to AI execution. - * - * @param config - Configuration for cached and AI flow execution - * @param config.cachedFlow - The cached Playwright flow to try first - * @param config.aiFlow - The AI-powered fallback flow to run if cached flow fails - * @param config.aiFlowTimeout - Optional timeout for the AI flow in milliseconds - * @param config.test - Playwright test instance for retry detection and timeout management - * - * @example - * ```typescript - * await executeWithAutoHealing({ - * cachedFlow: async () => { await page.getByRole("button").click(); }, - * aiFlow: async () => { await runSteps({ page, userFlow: "Click submit", steps }); }, - * test, - * }); - * ``` - */ -export declare const executeWithAutoHealing: (config: { - cachedFlow: () => Promise; - aiFlow: () => Promise; - aiFlowTimeout?: number; - test: TestType; -}) => Promise; -export { configure } from "./config"; -export type { EmailProvider } from "./config"; -export { emailsinkProvider } from "./providers/emailsink"; -export { extractEmailContent, generateEmail } from "./email"; -export { assert } from "./assertion"; -export type { AssertionResult } from "./types"; -export type { CacheStore } from "./cache"; -export { PassmarkError, StepExecutionError, ValidationError, AIModelError, CacheError, ConfigurationError } from "./errors"; diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index a4e3505..0000000 --- a/dist/index.js +++ /dev/null @@ -1,572 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ConfigurationError = exports.CacheError = exports.AIModelError = exports.ValidationError = exports.StepExecutionError = exports.PassmarkError = exports.assert = exports.generateEmail = exports.extractEmailContent = exports.emailsinkProvider = exports.configure = exports.executeWithAutoHealing = exports.runUserFlow = exports.runSteps = void 0; -const errors_1 = require("./errors"); -require("./instrumentation"); // For Axiom AI instrumentation -const ai_1 = require("ai"); -const ai_2 = require("axiom/ai"); -const shortid_1 = __importDefault(require("shortid")); -const instrumentation_1 = require("./instrumentation"); -// Only use withSpan when Axiom is configured, otherwise just execute the function directly -async function maybeWithSpan(meta, fn) { - return instrumentation_1.axiomEnabled ? (0, ai_2.withSpan)(meta, async () => fn()) : fn(); -} -const zod_1 = require("zod"); -const prompts_1 = require("./prompts"); -const cache_1 = require("./cache"); -const tools_1 = require("./tools"); -const utils_1 = require("./utils"); -const assertion_1 = require("./assertion"); -const data_cache_1 = require("./data-cache"); -const config_1 = require("./config"); -const extract_1 = require("./extract"); -const logger_1 = require("./logger"); -const models_1 = require("./models"); -const secure_script_runner_1 = require("./utils/secure-script-runner"); -const tab_manager_1 = require("./utils/tab-manager"); -const constants_1 = require("./constants"); -/** - * Executes a sequence of test steps using AI with intelligent caching. - * Each step is described in natural language and executed via browser automation. - * Successfully executed steps are cached for faster subsequent runs. - * - * @param options - Configuration including page, steps, assertions, and callbacks - * @param options.page - The Playwright page instance - * @param options.userFlow - Name of the user flow (used as cache key prefix) - * @param options.steps - Array of steps to execute, each with a description and optional data - * @param options.bypassCache - When true, skips cache and forces AI execution for all steps - * @param options.assertions - Optional assertions to verify after step execution - * @param options.executionId - Links multiple runSteps calls to share {{global.*}} placeholders - * @param options.onStepStart - Callback fired when a step begins execution - * @param options.onStepEnd - Callback fired when a step completes - * @param options.onReasoning - Callback fired with AI reasoning for each tool call - * @throws Rethrows step execution timeout errors - * - * @example - * ```typescript - * await runSteps({ - * page, - * userFlow: "Checkout Flow", - * steps: [ - * { description: "Add item to cart" }, - * { description: "Fill in email", data: { value: "{{run.email}}" } }, - * ], - * assertions: [{ assertion: "Order confirmation is displayed" }], - * expect, - * }); - * ``` - */ -const runSteps = async ({ page, test, expect, userFlow, steps, auth, bypassCache = false, onStepStart, onStepEnd, onReasoning, assertions, projectId, executionId, failAssertionsSilently, }) => { - executionId = executionId || process.env.executionId; - // Track all open tabs for this run. The active page is updated automatically - // when a new tab opens, or explicitly via the `switchToTab` step field. - const tabManager = (0, tab_manager_1.createTabManager)(page); - if (!cache_1.cache) { - logger_1.logger.warn("Cache not configured. Step caching is disabled — all steps will use AI execution."); - if (executionId) { - logger_1.logger.warn("{{global.*}} placeholders will not persist across runSteps calls without a cache provider."); - } - } - // Check if this is a Playwright retry - if so, bypass cache and use AI only - const isPlaywrightRetry = test ? test.info().retry > 0 : false; - if (isPlaywrightRetry) { - logger_1.logger.debug(`Playwright retry detected (retry #${test.info().retry}). Bypassing cache and using AI only.`); - } - // Process dynamic placeholders before running steps - const { processedSteps, processedAssertions, localValues, globalValues, projectDataValues } = await (0, data_cache_1.processPlaceholders)(steps, assertions, executionId, projectId); - logger_1.logger.info(`Starting step-by-step execution of ${processedSteps.length} steps.`); - let errorInStepExecution, stepThatFailed = ""; - for (let i = 0; i < processedSteps.length; i++) { - // Resolve email placeholders lazily just before step execution - // This ensures the email has arrived before we try to extract content - // Use global email if available, otherwise fall back to run email, and then use the supplied email from regex - // ~~~ This logic needs to be fixed as global email will always be present if executionId is provided ~~~ - const dynamicEmail = (0, data_cache_1.getDynamicEmail)(localValues, globalValues); - // Re-process step data and waitUntil with current localValues to pick up extracted values from previous steps - let currentStep = processedSteps[i]; - if (currentStep.data) { - currentStep = { - ...currentStep, - data: Object.fromEntries(Object.entries(currentStep.data).map(([k, v]) => [ - k, - (0, data_cache_1.replacePlaceholders)(v, localValues, globalValues, projectDataValues), - ])), - }; - } - if (currentStep.waitUntil) { - currentStep = { - ...currentStep, - waitUntil: (0, data_cache_1.replacePlaceholders)(currentStep.waitUntil, localValues, globalValues, projectDataValues), - }; - } - const step = await (0, data_cache_1.resolveEmailPlaceholders)(currentStep, dynamicEmail); - const id = shortid_1.default.generate(); - if (onStepStart) { - onStepStart({ id, description: step.description }); - } - // Switch tab before executing the step if requested. - if (step.switchToTab !== undefined) { - await tabManager.switchTo(step.switchToTab); - } - // Script mode: execute script directly, skip AI and cache - if (step.isScript) { - if (!step.script) { - throw new errors_1.ValidationError(`Script step ${step.description} has no script content.`); - } - logger_1.logger.debug(`Executing Script Step: ${step.description}`); - if (step.moduleId) { - // moduleId is optional metadata used only for logging/debugging to identify the source module of this script step. - logger_1.logger.debug(`Module ID: ${step.moduleId}`); - } - try { - let pageScreenshotBeforeApplyingAction = ""; - if (step.waitUntil) { - pageScreenshotBeforeApplyingAction = (await tabManager.active().screenshot({ fullPage: false })).toString("base64"); - } - if (onReasoning) { - onReasoning({ - id, - reasoning: `Executing script for step: ${step.description}`, - }); - } - // Execute script securely using AST-based validation - // This prevents arbitrary code execution by only allowing safe Playwright method chains - await (0, secure_script_runner_1.runSecureScript)({ - page: tabManager, - script: step.script, - localValues: localValues, - globalValues: globalValues, - expect, // Pass expect for assertions like expect(locator).toContainText() - }); - // Handle waitUntil if specified - if (step.waitUntil) { - await (0, utils_1.waitForCondition)({ - page: tabManager, - condition: step.waitUntil, - pageScreenshotBeforeApplyingAction, - previousSteps: processedSteps.slice(0, i), - currentStep: step, - nextStep: processedSteps[i + 1], - }); - } - // Handle data extraction if specified - // This is done post script execution - if (step.extract) { - const snapshot = await (0, utils_1.safeSnapshot)(tabManager); - const url = tabManager.active().url(); - const extracted = await (0, extract_1.extractDataWithAI)({ - snapshot, - url, - prompt: step.extract.prompt, - }); - const placeholderKey = `{{run.${step.extract.as}}}`; - localValues[placeholderKey] = extracted; - logger_1.logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); - } - if (onStepEnd) { - onStepEnd({ id, description: step.description }); - } - continue; // Skip to next step - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - logger_1.logger.error(`Script execution failed: ${message}`); - errorInStepExecution = message; - stepThatFailed = step.description; - break; // Stop execution on script failure - } - } - // First check if the step is cached on redis - const cachedStep = cache_1.cache ? await cache_1.cache.hgetall(`step:${userFlow}:${step.description}`) : {}; - if (!bypassCache && - !isPlaywrightRetry && - !step.bypassCache && - cachedStep && - Object.keys(cachedStep).length > 0) { - // Running cached step - logger_1.logger.debug(`Executing Cached Step: ${step.description}`); - const locator = cachedStep["locator"]; - const action = cachedStep["action"]; - const description = cachedStep["description"].replace(/'/g, "\\'"); - const value = cachedStep["value"]; - const input = step.data?.value || value; - let code = ""; - switch (action) { - case "click": - case "dblclick": - code = `await page.${locator}.describe('${description}').${action}({ timeout: ${constants_1.CACHED_ACTION_TIMEOUT} });`; - break; - case "fill": - code = `await page.${locator}.describe('${description}').fill("${input}", { timeout: ${constants_1.CACHED_ACTION_TIMEOUT} })`; - break; - case "hover": - code = `await page.${locator}.describe('${description}').hover({ timeout: ${constants_1.CACHED_ACTION_TIMEOUT} })`; - break; - case "select-option": - code = `await page.${locator}.describe('${description}').selectOption("${input}", { timeout: ${constants_1.CACHED_ACTION_TIMEOUT} })`; - break; - case "waitForText": - code = `await page.getByText("${value}", { exact: true }).first().waitFor({ state: "visible" })`; - break; - } - logger_1.logger.debug(`Executing cached action:\n${code}`); - try { - let pageScreenshotBeforeApplyingAction = ""; - if (step.waitUntil) { - pageScreenshotBeforeApplyingAction = (await tabManager.active().screenshot({ fullPage: false })).toString("base64"); - } - /** - * Before executing the first cached step, ensure the DOM is stable to avoid - * taking snapshot of a loading or transitioning state. Give it higher idle time because the page might - * take a bit longer to stabilize right after navigation. - */ - const INITIAL_DOM_STABILIZATION_IDLE_TIME = constants_1.INITIAL_DOM_STABILIZATION_IDLE; - if (i === 0) { - await (0, utils_1.waitForDOMStabilization)(tabManager, test, INITIAL_DOM_STABILIZATION_IDLE_TIME); - } - const pageSnapshotBeforeApplyingAction = await (0, utils_1.safeSnapshot)(tabManager); - await (0, utils_1.runLocatorCode)(tabManager, code); - /** - * Verify that the action had the intended effect on the page. This is because sometimes cached pw action may silently fail. - * - * Before verifying, this function will wait for the DOM to stabilize. - * stabilization idle time is set to 500ms by default. - * - * This means workflow is this: action performed -> wait for DOM stabilization -> check if action had effect -> next step - * - * Auto healing will be triggered if the action did not have any effect on the page. - */ - await (0, utils_1.verifyActionEffect)(tabManager, action, pageSnapshotBeforeApplyingAction); - if (step.waitUntil) { - await (0, utils_1.waitForCondition)({ - page: tabManager, - condition: step.waitUntil, - pageScreenshotBeforeApplyingAction, - previousSteps: processedSteps.slice(0, i), - currentStep: step, - nextStep: processedSteps[i + 1], - }); - } - // Handle data extraction if specified - // This is done post cached step execution - if (step.extract) { - const snapshot = await (0, utils_1.safeSnapshot)(tabManager); - const url = tabManager.active().url(); - const extracted = await (0, extract_1.extractDataWithAI)({ - snapshot, - url, - prompt: step.extract.prompt, - }); - const placeholderKey = `{{run.${step.extract.as}}}`; - localValues[placeholderKey] = extracted; - logger_1.logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); - } - continue; - } - catch (error) { - logger_1.logger.debug(`Error executing cached step, falling back to AI execution: ${error}`); - } - } - const abortController = new AbortController(); - const { tools, getPendingCacheData, clearPendingCacheData } = (0, tools_1.getAItools)(tabManager.active(), { - currentStep: step, - abortController, - test, - tabManager, - }); - logger_1.logger.debug(`Executing Step: ${step.description}`); - let pageScreenshotBeforeApplyingAction = ""; - if (step.waitUntil) { - pageScreenshotBeforeApplyingAction = (await tabManager.active().screenshot({ fullPage: false })).toString("base64"); - } - const model = (0, models_1.resolveModel)((0, config_1.getModelId)("stepExecution")); - logger_1.logger.debug(`Using model: ${(0, config_1.getModelId)("stepExecution")} for step execution / gateway: ${(0, config_1.getConfig)().ai?.gateway ?? "none"}`); - try { - const result = await maybeWithSpan({ capability: "step_execution", step: "agentic_tool_calling" }, async () => (0, ai_1.generateText)({ - model, - maxRetries: constants_1.MAX_RETRIES, - temperature: 0, - tools: tools, - providerOptions: { - google: { - thinkingConfig: { - includeThoughts: false, - thinkingLevel: "medium", - }, - }, - openrouter: { - reasoning: { - effort: "medium", - exclude: true - }, - }, - }, - onStepFinish: async ({ toolCalls }) => { - if (!onReasoning) - return; - // Append tool call reasoning to the response - toolCalls.forEach((toolCall) => { - const reasoning = `${(toolCall?.input).reasoning}\n\n`; - onReasoning({ - id, - reasoning, - }); - }); - }, - stopWhen: (0, ai_1.stepCountIs)(constants_1.STEP_EXECUTION_MAX_STEPS), - abortSignal: AbortSignal.timeout(constants_1.STEP_EXECUTION_TIMEOUT), - toolChoice: "auto", - prompt: (0, prompts_1.buildRunStepsPrompt)({ - auth, - steps: processedSteps, - step, - userFlow, - stepIndex: i, - }), - })); - // Cache the step action only if it was a single tool call (simple, deterministic action). - // Multi-step actions are not cached as they may be non-deterministic. - const allToolCalls = result.steps - .flatMap((s) => s.toolCalls) - .filter((tool) => ["browser_snapshot", "browser_stop"].indexOf(tool.toolName) === -1); - if (allToolCalls.length === 1 && cache_1.cache) { - const cacheData = getPendingCacheData(); - if (cacheData) { - await cache_1.cache.hset(`step:${userFlow}:${step.description}`, cacheData); - logger_1.logger.debug(`Cached step action: ${step.description}`); - } - } - clearPendingCacheData(); - } - catch (error) { - logger_1.logger.error({ err: error }, `Step execution failed: ${step.description}`); - errorInStepExecution = error instanceof Error ? error.message : String(error); - stepThatFailed = step.description; - break; - } - if (step.waitUntil) { - await (0, utils_1.waitForCondition)({ - page: tabManager, - condition: step.waitUntil, - pageScreenshotBeforeApplyingAction, - previousSteps: processedSteps.slice(0, i), - currentStep: step, - nextStep: processedSteps[i + 1], - }); - } - // Handle data extraction if specified - // This is done post AI step execution - if (step.extract) { - const snapshot = await (0, utils_1.safeSnapshot)(tabManager); - const url = tabManager.active().url(); - const extracted = await (0, extract_1.extractDataWithAI)({ - snapshot, - url, - prompt: step.extract.prompt, - }); - const placeholderKey = `{{run.${step.extract.as}}}`; - localValues[placeholderKey] = extracted; - logger_1.logger.info(`Extracted {{run.${step.extract.as}}}: "${extracted}"`); - } - if (onStepEnd) { - onStepEnd({ id, description: step.description }); - } - } - if (errorInStepExecution) { - logger_1.logger.warn(`Step execution encountered an error. Skipping assertions execution.`); - const errorDescription = `\n${errorInStepExecution}\nStep: ${stepThatFailed}`; - if (test) { - test.info().annotations.push({ - type: "Error", - description: errorDescription, - }); - } - throw new errors_1.StepExecutionError(errorDescription, stepThatFailed); - } - if (processedAssertions && processedAssertions.length > 0 && expect) { - for (const { assertion, effort, images } of processedAssertions) { - logger_1.logger.info(`Running assertion: ${assertion}`); - const id = shortid_1.default.generate(); - if (onStepStart) { - onStepStart({ - id, - description: "Starting assertion verification", - }); - } - if (onReasoning) { - onReasoning({ - id, - reasoning: `Verifying assertion: ${assertion}`, - }); - } - const reasoning = await (0, assertion_1.assert)({ - page: tabManager, - assertion, - test, - expect, - effort, - images, - failSilently: failAssertionsSilently, - maxRetries: 1, - onRetry: (retryCount, previousResult) => { }, - }); - if (onReasoning) { - onReasoning({ - id, - reasoning: `\n\n${reasoning}`, - }); - } - if (onStepEnd) { - onStepEnd({ id, description: "Successfully verified assertion" }); - } - } - } -}; -exports.runSteps = runSteps; -/** - * Runs a complete user flow as a single AI agent call. - * Best for exploratory testing where exact steps are flexible. - * The AI autonomously navigates, interacts, and verifies the flow. - * - * @param options - User flow configuration - * @param options.page - The Playwright page instance - * @param options.userFlow - Description of the user flow to execute - * @param options.steps - Natural language description of steps to perform - * @param options.effort - "low" uses a faster model, "high" uses a more capable model with deeper thinking - * @param options.assertion - Optional assertion to verify after the flow completes - * @returns The assertion result if an assertion was provided, the raw AI text response otherwise, or undefined on error - * - * @example - * ```typescript - * const result = await runUserFlow({ - * page, - * userFlow: "Complete a purchase", - * steps: "Navigate to store, add an item, checkout", - * effort: "high", - * assertion: "Order confirmation is displayed", - * }); - * ``` - */ -const runUserFlow = async ({ page, userFlow, steps, assertion, effort = "low", thinkingBudget = constants_1.THINKING_BUDGET_DEFAULT, }) => { - const abortController = new AbortController(); - const model = effort === "low" - ? (0, models_1.resolveModel)((0, config_1.getModelId)("userFlowLow")) - : (0, models_1.resolveModel)((0, config_1.getModelId)("userFlowHigh")); - const { tools } = (0, tools_1.getAItools)(page, { - abortController, - }); - try { - const { text } = await maybeWithSpan({ capability: "user_flow_execution", step: "agentic_tool_calling" }, async () => { - return (0, ai_1.generateText)({ - model, - maxRetries: constants_1.MAX_RETRIES, - temperature: 0, - tools: tools, - providerOptions: { - google: { - thinkingConfig: { - thinkingBudget, - }, - }, - openrouter: { - reasoning: { - max_tokens: thinkingBudget, - }, - }, - }, - stopWhen: (0, ai_1.stepCountIs)(constants_1.USER_FLOW_MAX_STEPS), - abortSignal: abortController.signal, - prepareStep: async ({ messages }) => { - // Remove older messages to keep the context window small - if (messages.length > 11) { - const modifiedMessages = [messages[0], ...messages.slice(-10)]; - return { - messages: modifiedMessages, - }; - } - return {}; - }, - toolChoice: "auto", - prompt: (0, prompts_1.buildRunUserFlowPrompt)({ - steps, - userFlow, - assertion, - }), - }); - }); - if (assertion) { - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("utility")), - prompt: `Convert the following text output into a valid JSON object with the specified properties:\n\n${text}`, - output: ai_1.Output.object({ - schema: zod_1.z.object({ - assertionPassed: zod_1.z.boolean().describe("Indicates whether the assertion passed or not."), - confidenceScore: zod_1.z - .number() - .describe("Confidence score of the assertion, between 0 and 100."), - reasoning: zod_1.z - .string() - .describe("Brief explanation of the reasoning behind the assertion."), - }), - }), - }); - return output; - } - return text; - } - catch (error) { - logger_1.logger.error({ err: error }, "Error during user flow execution"); - } -}; -exports.runUserFlow = runUserFlow; -/** - * Wraps a cached Playwright flow with AI fallback for auto-healing. - * Tries the cached flow first; if it fails (e.g., due to UI changes), falls back to AI execution. - * - * @param config - Configuration for cached and AI flow execution - * @param config.cachedFlow - The cached Playwright flow to try first - * @param config.aiFlow - The AI-powered fallback flow to run if cached flow fails - * @param config.aiFlowTimeout - Optional timeout for the AI flow in milliseconds - * @param config.test - Playwright test instance for retry detection and timeout management - * - * @example - * ```typescript - * await executeWithAutoHealing({ - * cachedFlow: async () => { await page.getByRole("button").click(); }, - * aiFlow: async () => { await runSteps({ page, userFlow: "Click submit", steps }); }, - * test, - * }); - * ``` - */ -const executeWithAutoHealing = async (config) => { - const { cachedFlow, aiFlow, test, aiFlowTimeout } = config; - if (process.env.AI || test.info().retry > 0) { - if (aiFlowTimeout) { - test.setTimeout(aiFlowTimeout); - } - await aiFlow(); - } - else { - await cachedFlow(); - } -}; -exports.executeWithAutoHealing = executeWithAutoHealing; -var config_2 = require("./config"); -Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return config_2.configure; } }); -var emailsink_1 = require("./providers/emailsink"); -Object.defineProperty(exports, "emailsinkProvider", { enumerable: true, get: function () { return emailsink_1.emailsinkProvider; } }); -var email_1 = require("./email"); -Object.defineProperty(exports, "extractEmailContent", { enumerable: true, get: function () { return email_1.extractEmailContent; } }); -Object.defineProperty(exports, "generateEmail", { enumerable: true, get: function () { return email_1.generateEmail; } }); -var assertion_2 = require("./assertion"); -Object.defineProperty(exports, "assert", { enumerable: true, get: function () { return assertion_2.assert; } }); -var errors_2 = require("./errors"); -Object.defineProperty(exports, "PassmarkError", { enumerable: true, get: function () { return errors_2.PassmarkError; } }); -Object.defineProperty(exports, "StepExecutionError", { enumerable: true, get: function () { return errors_2.StepExecutionError; } }); -Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_2.ValidationError; } }); -Object.defineProperty(exports, "AIModelError", { enumerable: true, get: function () { return errors_2.AIModelError; } }); -Object.defineProperty(exports, "CacheError", { enumerable: true, get: function () { return errors_2.CacheError; } }); -Object.defineProperty(exports, "ConfigurationError", { enumerable: true, get: function () { return errors_2.ConfigurationError; } }); diff --git a/dist/instrumentation.d.ts b/dist/instrumentation.d.ts deleted file mode 100644 index 5aeb2e3..0000000 --- a/dist/instrumentation.d.ts +++ /dev/null @@ -1 +0,0 @@ -export declare const axiomEnabled: boolean; diff --git a/dist/instrumentation.js b/dist/instrumentation.js deleted file mode 100644 index a2051e6..0000000 --- a/dist/instrumentation.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.axiomEnabled = void 0; -const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http"); -const resources_1 = require("@opentelemetry/resources"); -const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node"); -const sdk_trace_node_2 = require("@opentelemetry/sdk-trace-node"); -const semantic_conventions_1 = require("@opentelemetry/semantic-conventions"); -const api_1 = require("@opentelemetry/api"); -const ai_1 = require("axiom/ai"); -const logger_1 = require("./logger"); -const axiomToken = process.env.AXIOM_TOKEN; -const axiomDataset = process.env.AXIOM_DATASET; -exports.axiomEnabled = !!(axiomToken && axiomDataset); -if (axiomToken && axiomDataset) { - logger_1.logger.info("Axiom AI instrumentation enabled"); - const tracer = api_1.trace.getTracer("ai-logs-tracer"); - const provider = new sdk_trace_node_1.NodeTracerProvider({ - resource: (0, resources_1.resourceFromAttributes)({ - [semantic_conventions_1.ATTR_SERVICE_NAME]: "passmark", - }, { - schemaUrl: "https://opentelemetry.io/schemas/1.37.0", - }), - spanProcessors: [ - new sdk_trace_node_2.SimpleSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({ - url: `https://api.axiom.co/v1/traces`, - headers: { - Authorization: `Bearer ${axiomToken}`, - "X-Axiom-Dataset": axiomDataset, - }, - })), - ], - }); - provider.register(); - (0, ai_1.initAxiomAI)({ tracer, redactionPolicy: ai_1.RedactionPolicy.AxiomDefault }); -} diff --git a/dist/logger.d.ts b/dist/logger.d.ts deleted file mode 100644 index d5c3d5a..0000000 --- a/dist/logger.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -import pino from "pino"; -export declare const logger: pino.Logger; diff --git a/dist/logger.js b/dist/logger.js deleted file mode 100644 index 27402dd..0000000 --- a/dist/logger.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.logger = void 0; -const pino_1 = __importDefault(require("pino")); -exports.logger = (0, pino_1.default)({ - name: "passmark-ai", - level: process.env.PASSMARK_LOG_LEVEL || "info", - transport: process.env.NODE_ENV !== "production" - ? { target: "pino-pretty", options: { colorize: true } } - : undefined, -}); diff --git a/dist/models.d.ts b/dist/models.d.ts deleted file mode 100644 index ff7da8f..0000000 --- a/dist/models.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { type LanguageModel } from "ai"; -/** - * Resolves a canonical model ID to a LanguageModel instance wrapped with Axiom instrumentation. - * Input format: "provider/model-name" (e.g. "google/gemini-3-flash") - * - * Users always use canonical IDs (gateway-style). When using direct providers, - * model names are automatically mapped to the correct provider-specific names - * (e.g. "gemini-3-flash" → "gemini-3-flash-preview" for Google's direct API). - * - * When gateway is "vercel", routes through the Vercel AI Gateway as-is. - * When gateway is "openrouter", routes through OpenRouter. - * When gateway is "cloudflare", routes through Cloudflare AI Gateway using the - * provider-native paths (google-ai-studio, anthropic) so provider-specific fields - * like Gemini's thought_signature pass through unchanged. - * When gateway is "none" (default), creates a direct provider instance with alias resolution. - * All paths wrap the model with wrapAISDKModel for tracing when Axiom is enabled. - */ -export declare function resolveModel(modelId: string): LanguageModel; diff --git a/dist/models.js b/dist/models.js deleted file mode 100644 index 074e698..0000000 --- a/dist/models.js +++ /dev/null @@ -1,173 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.resolveModel = resolveModel; -const errors_1 = require("./errors"); -const anthropic_1 = require("@ai-sdk/anthropic"); -const google_1 = require("@ai-sdk/google"); -const ai_sdk_provider_1 = require("@openrouter/ai-sdk-provider"); -const ai_1 = require("ai"); -const ai_2 = require("axiom/ai"); -const config_1 = require("./config"); -const instrumentation_1 = require("./instrumentation"); -function wrapModel(model) { - return instrumentation_1.axiomEnabled ? (0, ai_2.wrapAISDKModel)(model) : model; -} -let _google = null; -let _anthropic = null; -let _openrouter = null; -let _cloudflareGoogle = null; -let _cloudflareAnthropic = null; -function getGoogleProvider() { - if (!_google) { - if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) { - throw new errors_1.ConfigurationError("GOOGLE_GENERATIVE_AI_API_KEY isn't set. Add it to your environment (for example: export GOOGLE_GENERATIVE_AI_API_KEY=your_key), or use a gateway: configure({ ai: { gateway: 'vercel' } }) with AI_GATEWAY_API_KEY, configure({ ai: { gateway: 'openrouter' } }) with OPENROUTER_API_KEY, or configure({ ai: { gateway: 'cloudflare' } }) with CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_AI_GATEWAY, GOOGLE_GENERATIVE_AI_API_KEY, and CLOUDFLARE_AI_GATEWAY_API_KEY. See .env.example for reference."); - } - _google = (0, google_1.createGoogleGenerativeAI)({ - apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY, - }); - } - return _google; -} -function getAnthropicProvider() { - if (!_anthropic) { - if (!process.env.ANTHROPIC_API_KEY) { - throw new errors_1.ConfigurationError("ANTHROPIC_API_KEY isn't set. Add it to your environment (for example: export ANTHROPIC_API_KEY=your_key), or use a gateway: configure({ ai: { gateway: 'vercel' } }) with AI_GATEWAY_API_KEY, configure({ ai: { gateway: 'openrouter' } }) with OPENROUTER_API_KEY, or configure({ ai: { gateway: 'cloudflare' } }) with CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_AI_GATEWAY, ANTHROPIC_API_KEY, and CLOUDFLARE_AI_GATEWAY_API_KEY. See .env.example for reference."); - } - _anthropic = (0, anthropic_1.createAnthropic)({ - apiKey: process.env.ANTHROPIC_API_KEY, - }); - } - return _anthropic; -} -function getOpenRouterProvider() { - if (!_openrouter) { - if (!process.env.OPENROUTER_API_KEY) { - throw new errors_1.ConfigurationError("OPENROUTER_API_KEY isn't set. Add it to your environment (for example: export OPENROUTER_API_KEY=your_key). See .env.example for reference."); - } - _openrouter = (0, ai_sdk_provider_1.createOpenRouter)({ - apiKey: process.env.OPENROUTER_API_KEY, - }); - } - return _openrouter; -} -/** - * Builds the per-provider Cloudflare AI Gateway base URL and (optional) - * `cf-aig-authorization` header. We route through Cloudflare's native - * provider paths (not the Unified/OpenAI-compat endpoint) so that - * provider-specific fields — notably Gemini's `thought_signature` on - * thinking models — pass through unmodified. - * - * @see https://developers.cloudflare.com/ai-gateway/usage/providers/google-ai-studio/ - * @see https://developers.cloudflare.com/ai-gateway/usage/providers/anthropic/ - */ -function getCloudflareGatewayConfig(providerPath) { - const accountId = process.env.CLOUDFLARE_ACCOUNT_ID; - const gatewayName = process.env.CLOUDFLARE_AI_GATEWAY; - if (!accountId || !gatewayName) { - throw new errors_1.ConfigurationError("Cloudflare AI Gateway requires CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_AI_GATEWAY (gateway name). You must also set the upstream provider key (GOOGLE_GENERATIVE_AI_API_KEY and/or ANTHROPIC_API_KEY). If the gateway is authenticated, also set CLOUDFLARE_AI_GATEWAY_API_KEY. See .env.example for reference."); - } - const cfAigToken = process.env.CLOUDFLARE_AI_GATEWAY_API_KEY; - return { - baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayName}/${providerPath}`, - headers: cfAigToken ? { "cf-aig-authorization": `Bearer ${cfAigToken}` } : undefined, - }; -} -function getCloudflareGoogleProvider() { - if (!_cloudflareGoogle) { - if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY) { - throw new errors_1.ConfigurationError("GOOGLE_GENERATIVE_AI_API_KEY isn't set. Cloudflare AI Gateway proxies requests to Google AI Studio and requires your Google API key. Add GOOGLE_GENERATIVE_AI_API_KEY to your environment."); - } - const { baseURL, headers } = getCloudflareGatewayConfig("google-ai-studio/v1beta"); - _cloudflareGoogle = (0, google_1.createGoogleGenerativeAI)({ - apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY, - baseURL, - headers, - }); - } - return _cloudflareGoogle; -} -function getCloudflareAnthropicProvider() { - if (!_cloudflareAnthropic) { - if (!process.env.ANTHROPIC_API_KEY) { - throw new errors_1.ConfigurationError("ANTHROPIC_API_KEY isn't set. Cloudflare AI Gateway proxies requests to Anthropic and requires your Anthropic API key. Add ANTHROPIC_API_KEY to your environment."); - } - const { baseURL, headers } = getCloudflareGatewayConfig("anthropic/v1"); - _cloudflareAnthropic = (0, anthropic_1.createAnthropic)({ - apiKey: process.env.ANTHROPIC_API_KEY, - baseURL, - headers, - }); - } - return _cloudflareAnthropic; -} -/** - * Maps canonical model names to direct Google/Anthropic API names. - * Only needed where the gateway name differs from the direct provider name. - * Add new entries here when providers rename or graduate models. - */ -const MODEL_DIRECT_ALIASES = { - "gemini-3-flash": "gemini-3-flash-preview", - "claude-sonnet-4.6": "claude-sonnet-4-6", - "claude-haiku-4.5": "claude-haiku-4-5", -}; -function resolveDirectModelName(modelName) { - return MODEL_DIRECT_ALIASES[modelName] ?? modelName; -} -/** - * Maps canonical model IDs (provider/model) to OpenRouter model IDs. - * OpenRouter uses its own naming — add entries here when they differ from canonical IDs. - */ -const OPENROUTER_MODEL_ALIASES = { - "google/gemini-3-flash": "google/gemini-3-flash-preview", -}; -function resolveOpenRouterModelId(modelId) { - return OPENROUTER_MODEL_ALIASES[modelId] ?? modelId; -} -/** - * Resolves a canonical model ID to a LanguageModel instance wrapped with Axiom instrumentation. - * Input format: "provider/model-name" (e.g. "google/gemini-3-flash") - * - * Users always use canonical IDs (gateway-style). When using direct providers, - * model names are automatically mapped to the correct provider-specific names - * (e.g. "gemini-3-flash" → "gemini-3-flash-preview" for Google's direct API). - * - * When gateway is "vercel", routes through the Vercel AI Gateway as-is. - * When gateway is "openrouter", routes through OpenRouter. - * When gateway is "cloudflare", routes through Cloudflare AI Gateway using the - * provider-native paths (google-ai-studio, anthropic) so provider-specific fields - * like Gemini's thought_signature pass through unchanged. - * When gateway is "none" (default), creates a direct provider instance with alias resolution. - * All paths wrap the model with wrapAISDKModel for tracing when Axiom is enabled. - */ -function resolveModel(modelId) { - const gatewayConfig = (0, config_1.getConfig)().ai?.gateway ?? "none"; - if (gatewayConfig === "vercel") { - if (!process.env.AI_GATEWAY_API_KEY) { - throw new errors_1.ConfigurationError("AI_GATEWAY_API_KEY isn't set. To use the Vercel AI Gateway, add AI_GATEWAY_API_KEY to your environment. If you'd rather use direct provider keys, call configure({ ai: { gateway: 'none' } }) and set GOOGLE_GENERATIVE_AI_API_KEY and/or ANTHROPIC_API_KEY."); - } - return wrapModel((0, ai_1.gateway)(modelId)); - } - if (gatewayConfig === "openrouter") { - return wrapModel(getOpenRouterProvider()(resolveOpenRouterModelId(modelId))); - } - const [provider, ...rest] = modelId.split("/"); - const modelName = rest.join("/"); - if (gatewayConfig === "cloudflare") { - switch (provider) { - case "google": - return wrapModel(getCloudflareGoogleProvider()(resolveDirectModelName(modelName))); - case "anthropic": - return wrapModel(getCloudflareAnthropicProvider()(resolveDirectModelName(modelName))); - default: - throw new errors_1.AIModelError(`Cloudflare AI Gateway routing is not configured for provider: ${provider}`); - } - } - switch (provider) { - case "google": - return wrapModel(getGoogleProvider()(resolveDirectModelName(modelName))); - case "anthropic": - return wrapModel(getAnthropicProvider()(resolveDirectModelName(modelName))); - default: - throw new errors_1.AIModelError(`Unknown AI provider: ${provider}`); - } -} diff --git a/dist/prompts/index.d.ts b/dist/prompts/index.d.ts deleted file mode 100644 index 0609957..0000000 --- a/dist/prompts/index.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RunStepsOptions, Step, UserFlowOptions } from "../types"; -export declare const buildRunStepsPrompt: ({ auth, userFlow, step, steps, stepIndex, }: Pick & { - step: Step; - stepIndex: number; -}) => string; -export declare const buildRunUserFlowPrompt: ({ userFlow, steps, assertion, }: Pick) => string; diff --git a/dist/prompts/index.js b/dist/prompts/index.js deleted file mode 100644 index e4d3278..0000000 --- a/dist/prompts/index.js +++ /dev/null @@ -1,112 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.buildRunUserFlowPrompt = exports.buildRunStepsPrompt = void 0; -const buildRunStepsPrompt = ({ auth, userFlow, step, steps, stepIndex, }) => { - return ` - **System Prompt:** - You are an AI-powered expert QA Agent that follows instructions precisely and is designed to test web applications. If you do not follow instructions exactly as specified below, very bad things will happen as bugs will go undetected. - - - ${userFlow} - - - The above user flow contains multiple steps that need to be executed one by one. However, right now we are only interested in executing one specific step. - - Execute **ONLY** the following step: - - - ${step.description} - - - - Current Step Index: ${stepIndex + 1} out of ${steps.length} steps. - - - ${stepIndex + 1 < steps.length - ? ` - - The next step (DO NOT EXECUTE THIS) is: "${steps[stepIndex + 1].description}" - This is provided for context only. Stop immediately after completing the current step given above. - ` - : ""} - - Remember we're only interested in executing the current step right now. We'll have a separate run for the next step. So, do not execute any steps other than the current step mentioned above. Stop right after executing the current step. - - ${step.data - ? ` -Use the following data for the current step: - -"${JSON.stringify(step.data)}". -`.trim() - : ""} - - ${auth - ? ` - If presented with login screen, log in to the website using the following credentials: - - - Email: ${auth.email} - - Password: ${auth.password} - ` - : ""} - - - - Wait for the page to be fully loaded and settled before executing the step. - - Start by taking a fresh snapshot of the page. If snapshot is not available or empty, wait and retry until you get a valid snapshot. - - [CRITICAL] After you execute the step, analyze the returned snapshot. The step execution is considered successful only if the latest snapshot reflects the expected state after performing the step. If it doesn't, you must take a fresh snapshot (and if needed a screenshot) and retry executing the step until the expected state is achieved. - - [CRITICAL] If you are unable to locate the element based on the snapshot or if there is any ambiguity, you must take a screenshot of the page to visually inspect the current state and then retry locating the element and executing the step. - - You should stop right after the step is successfully executed and reflected in the snapshot. - - At any point if you get an error or make any mistake, you will request a fresh snapshot (if needed a screenshot) and try to re execute the step correctly by using the available tools. - - If you see any data validation issue or UI or input errors, correct the input and retry the step, unless data is supplied already via data field or step description. - - [CRITICAL] Do not use fake \`ref\` locators in tool calls, use the actual locators from the snapshot. - - If you have to wait for some time at any step, wait for max 5s and then take a fresh snapshot to decide the next step. - - In case you are confused, you can also take a screenshot of the page to visually inspect the current state. - - [CRITICAL] Do not perform multiple steps. Your objective is to perform only the current step specified above and stop right after that. - - For file uploads, use \`browser_upload_file\` tool with ref of the file upload button from the snapshot. - - [CRITICAL] Do not use browser_navigate tool unless there is an explicit instruction to navigate in the **step description**. - - `; -}; -exports.buildRunStepsPrompt = buildRunStepsPrompt; -const buildRunUserFlowPrompt = ({ userFlow, steps, assertion, }) => { - return ` - **System Prompt:** - You are an AI-powered expert QA Agent that follows instructions precisely and is designed to test web applications to find regressions in user flows. If you do not follow instructions exactly as specified below, very bad things will happen as bugs will go undetected. But in some cases user flows might have changed and in those cases you can use your best judgement to fill in the gaps. - - Here's some context & instructions for the Agent: - - - ${userFlow} - - - ${steps - ? `Follow these steps **exactly** to test the user flow:\n\n\n${steps}\n- STOP user flow by calling \`browser_stop\` tool exactly once.\n` - : ""} - ${assertion - ? `\n\n${assertion}\n\n\n\n Double check your assertion analysis to ensure it's accurate.` - : ""} - - ${assertion - ? ` - The output should contain the following information: - - \`assertionPassed\`: A boolean indicating whether the assertion passed or not. - - \`confidenceScore\`: A number between 0 and 100 indicating the confidence score of the assertion. - - \`reasoning\`: A brief string explaining the reasoning behind the assertion. - ` - : ""} - - Follow these instructions carefully while testing the website: - - - You are given the above user flow and corresponding steps to test that user flow. You need to manually test it and assert that it works as expected. - - Run the steps one by one using the tools provided. - - At the end of each step, you will get a fresh snapshot of the page. Based on the snapshot, you will decide the optimal next step. Use your thinking to plan and iterate. - - At any point if you get an error or take any wrong step, you will request a fresh snapshot and try to correct the mistake by using the available tools. - - If you see any data validation issue or UI or input errors, correct the input and retry the step. - - Start by taking a fresh snapshot of the page. If snapshot is not available or empty, wait and retry until you get a valid snapshot. - - DO not use fake \`ref\` locators in tool calls, use the actual locators from the snapshot. - - If you have to wait for some time at any step, wait for max 5s and then take a fresh snapshot to decide the next step. - - In case you are confused, you can also take a screenshot of the page to visually inspect the current state. - - Never get stuck in a \`waitForTimeout\` loop forever. Analyze the current state and decide the next step based on the snapshot and previous tool calls. - - `; -}; -exports.buildRunUserFlowPrompt = buildRunUserFlowPrompt; diff --git a/dist/providers/emailsink.d.ts b/dist/providers/emailsink.d.ts deleted file mode 100644 index 610c6a9..0000000 --- a/dist/providers/emailsink.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { EmailProvider } from "../config"; -/** - * Emailsink is a simple email service by Bug0 that allows you to receive emails at a unique address and retrieve their content via an API - * The free plan doesn't require an API key, but you can consider getting one by upgrading to a paid plan for higher rate limits and reliability. - * - * @param options - Configuration options for the Emailsink provider - * @returns An EmailProvider instance - */ -export declare function emailsinkProvider(options: { - apiKey?: string; -}): EmailProvider; diff --git a/dist/providers/emailsink.js b/dist/providers/emailsink.js deleted file mode 100644 index 0f04d1b..0000000 --- a/dist/providers/emailsink.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.emailsinkProvider = emailsinkProvider; -/** - * Emailsink is a simple email service by Bug0 that allows you to receive emails at a unique address and retrieve their content via an API - * The free plan doesn't require an API key, but you can consider getting one by upgrading to a paid plan for higher rate limits and reliability. - * - * @param options - Configuration options for the Emailsink provider - * @returns An EmailProvider instance - */ -function emailsinkProvider(options) { - return { - domain: "emailsink.dev", - extractContent: async ({ email, prompt }) => { - let url = `https://get.emailsink.dev/?email=${encodeURIComponent(email)}&prompt=${encodeURIComponent(prompt)}`; - if (options.apiKey) { - url += `&secret=${encodeURIComponent(options.apiKey)}`; - } - const response = await fetch(url); - const data = (await response.json()); - let result = data.result; - // Handle case where result is a string containing a JSON object - if (typeof result === "string" && result.startsWith("{")) { - try { - const parsedResult = JSON.parse(result); - result = parsedResult.result; - } - catch { - // Keep the original result if parsing fails - } - } - if (result !== undefined && result !== null && result !== "") { - return result; - } - throw new Error("No email content found"); - }, - }; -} diff --git a/dist/redis.d.ts b/dist/redis.d.ts deleted file mode 100644 index 75a979f..0000000 --- a/dist/redis.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Redis from "ioredis"; -declare let redis: Redis | null; -export { redis }; diff --git a/dist/redis.js b/dist/redis.js deleted file mode 100644 index 080c96d..0000000 --- a/dist/redis.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.redis = void 0; -const ioredis_1 = __importDefault(require("ioredis")); -const logger_1 = require("./logger"); -let redis = null; -exports.redis = redis; -if (process.env.REDIS_URL) { - exports.redis = redis = new ioredis_1.default(process.env.REDIS_URL); -} -else { - logger_1.logger.warn("REDIS_URL not set. Step caching, global placeholders, and project data are disabled."); -} diff --git a/dist/tools.d.ts b/dist/tools.d.ts deleted file mode 100644 index 9d659d2..0000000 --- a/dist/tools.d.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { type Page } from "@playwright/test"; -import { PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType } from "@playwright/test"; -import type { TabManager } from "./utils/tab-manager"; -type ToolSettings = { - abortController?: AbortController; - currentStep?: { - description: string; - data?: Record; - }; - test?: TestType; - /** - * Optional tab manager. When provided, tools resolve the active page - * dynamically and auto-switch to a newly opened tab after action tools. - */ - tabManager?: TabManager; -}; -export declare function getAItools(page: Page, settings?: ToolSettings): { - tools: { - browser_navigate: import("ai").Tool<{ - url: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - url: string; - } & { - snapshot: string; - })>; - browser_click: import("ai").Tool<{ - ref: string; - elementDescription: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - button?: "left" | "right" | "middle" | undefined; - doubleClick?: boolean | undefined; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_type: import("ai").Tool<{ - ref: string; - elementDescription: string; - text: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - text: string; - } & { - snapshot: string; - })>; - browser_take_screenshot: import("ai").Tool<{ - fullPage: boolean; - reasoning: string; - }, unknown>; - browser_press_key: import("ai").Tool<{ - key: string; - }, string | ({ - success: boolean; - key: string; - } & { - snapshot: string; - })>; - browser_navigate_back: import("ai").Tool, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_navigate_forward: import("ai").Tool, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_reload: import("ai").Tool<{ - reasoning: string; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_snapshot: import("ai").Tool<{ - reasoning: string; - }, string>; - browser_wait: import("ai").Tool<{ - timeout: number; - reasoning: string; - }, string | ({ - success: boolean; - timeout: number; - message: string; - } & { - snapshot: string; - })>; - browser_mouse_move: import("ai").Tool<{ - x: number; - y: number; - reasoning: string; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_mouse_down: import("ai").Tool<{ - reasoning: string; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_mouse_up: import("ai").Tool<{ - reasoning: string; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_select_dropdown_option: import("ai").Tool<{ - ref: string; - elementDescription: string; - value: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - value: string; - } & { - snapshot: string; - })>; - browser_stop: import("ai").Tool<{ - reasoning: string; - }, { - success: boolean; - message: string; - }>; - browser_drag_and_drop: import("ai").Tool<{ - sourceRef: string; - sourceElementDescription: string; - targetRef: string; - targetElementDescription: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_hover: import("ai").Tool<{ - ref: string; - elementDescription: string; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - browser_upload_file: import("ai").Tool<{ - ref: string; - elementDescription: string; - filePaths: string[]; - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - prefixedFilePaths: string[]; - } & { - snapshot: string; - })>; - browser_trigger_blur: import("ai").Tool<{ - reasoning: string; - doesActionAdvanceUsTowardsGoal: boolean; - }, string | ({ - success: boolean; - } & { - snapshot: string; - })>; - get_unique_value: import("ai").Tool<{ - prefix: string; - }, { - success: boolean; - value: string; - }>; - }; - getPendingCacheData: () => Record | null; - clearPendingCacheData: () => void; -}; -export {}; diff --git a/dist/tools.js b/dist/tools.js deleted file mode 100644 index 54312c2..0000000 --- a/dist/tools.js +++ /dev/null @@ -1,500 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getAItools = getAItools; -const ai_1 = require("ai"); -const zod_1 = require("zod"); -const ai_2 = require("axiom/ai"); -const shortid_1 = __importDefault(require("shortid")); -const config_1 = require("./config"); -const instrumentation_1 = require("./instrumentation"); -const logger_1 = require("./logger"); -const constants_1 = require("./constants"); -// Only wrap tools with Axiom instrumentation when Axiom is configured -const maybeWrapTool = instrumentation_1.axiomEnabled ? ai_2.wrapTool : (_name, t) => t; -function getAItools(page, settings) { - const playwrightTools = new PlaywrightTools(page, settings); - const withSnapshot = async (fn, args) => { - try { - const result = await fn(args); - // tab-manager's persistent 'page' listener auto-switches active focus - // when a new tab opens, so getSnapshot() below targets it automatically. - const snapshot = await playwrightTools.getSnapshot(); - return { ...result, snapshot }; - } - catch (_error) { - return `Error executing this action. Retry the action or try a different one.\n\nLatest Snapshot:\n\n${await playwrightTools.getSnapshot()}`; - } - }; - const tools = { - browser_navigate: maybeWrapTool("browser_navigate", (0, ai_1.tool)({ - description: "Navigate to a URL. This tool should be used only when an explicit instruction to navigate is given in a particular step", - inputSchema: playwrightTools.navigateSchema, - execute: async (args) => withSnapshot(playwrightTools.navigate.bind(playwrightTools), args), - })), - browser_click: maybeWrapTool("browser_click", (0, ai_1.tool)({ - description: "Click on an element", - inputSchema: playwrightTools.clickSchema, - execute: async (args) => withSnapshot(playwrightTools.click.bind(playwrightTools), args), - })), - browser_type: maybeWrapTool("browser_type", (0, ai_1.tool)({ - description: "Type text into an element", - inputSchema: playwrightTools.typeSchema, - execute: async (args) => withSnapshot(playwrightTools.type.bind(playwrightTools), args), - })), - browser_take_screenshot: maybeWrapTool("browser_take_screenshot", (0, ai_1.tool)({ - description: "Take a screenshot", - inputSchema: playwrightTools.screenshotSchema, - execute: async (args) => { - const fn = playwrightTools.takeScreenshot.bind(playwrightTools); - const screenshot = await fn(args); - return screenshot; - }, - toModelOutput: (result) => { - const base64 = (typeof result === "string" ? result : result.output); - return { - type: "content", - value: [ - { type: "media", data: base64, mediaType: "image/png" }, - ], - }; - }, - })), - browser_press_key: maybeWrapTool("browser_press_key", (0, ai_1.tool)({ - description: "Press a key", - inputSchema: playwrightTools.pressKeySchema, - execute: async (args) => withSnapshot(playwrightTools.pressKey.bind(playwrightTools), args), - })), - browser_navigate_back: maybeWrapTool("browser_navigate_back", (0, ai_1.tool)({ - description: "Go back to previous page", - inputSchema: zod_1.z.object({}), - execute: async () => withSnapshot(playwrightTools.goBack.bind(playwrightTools), {}), - })), - browser_navigate_forward: maybeWrapTool("browser_navigate_forward", (0, ai_1.tool)({ - description: "Go forward to next page", - inputSchema: zod_1.z.object({}), - execute: async () => withSnapshot(playwrightTools.goForward.bind(playwrightTools), {}), - })), - browser_reload: maybeWrapTool("browser_reload", (0, ai_1.tool)({ - description: "Reload the current page", - inputSchema: zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }), - execute: async (args) => withSnapshot(playwrightTools.reload.bind(playwrightTools), args), - })), - browser_snapshot: maybeWrapTool("browser_snapshot", (0, ai_1.tool)({ - description: "Take fresh snapshot of the current page", - inputSchema: zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }), - execute: async (_args) => { - return await playwrightTools.getSnapshot(); - }, - })), - browser_wait: maybeWrapTool("browser_wait", (0, ai_1.tool)({ - description: "Wait for a specified amount of time", - inputSchema: playwrightTools.waitSchema, - execute: async (args) => withSnapshot(playwrightTools.wait.bind(playwrightTools), args), - })), - browser_mouse_move: maybeWrapTool("browser_mouse_move", (0, ai_1.tool)({ - description: "Move the mouse to a specific coordinate", - inputSchema: playwrightTools.mouseMoveSchema, - execute: async (args) => withSnapshot(playwrightTools.mouseMove.bind(playwrightTools), args), - })), - browser_mouse_down: maybeWrapTool("browser_mouse_down", (0, ai_1.tool)({ - description: "Press the left mouse button.", - inputSchema: playwrightTools.mouseDownSchema, - execute: async (args) => withSnapshot(playwrightTools.mouseDown.bind(playwrightTools), args), - })), - browser_mouse_up: maybeWrapTool("browser_mouse_up", (0, ai_1.tool)({ - description: "Release the left mouse button", - inputSchema: playwrightTools.mouseUpSchema, - execute: async (args) => withSnapshot(playwrightTools.mouseUp.bind(playwrightTools), args), - })), - browser_select_dropdown_option: maybeWrapTool("browser_select_dropdown_option", (0, ai_1.tool)({ - description: "Select an option from a dropdown", - inputSchema: playwrightTools.selectDropdownOptionSchema, - execute: async (args) => withSnapshot(playwrightTools.selectDropdownOption.bind(playwrightTools), args), - })), - browser_stop: maybeWrapTool("browser_stop", (0, ai_1.tool)({ - description: "Stop the user flow test", - inputSchema: playwrightTools.stopSchema, - execute: async (args) => playwrightTools.stop(args), - })), - browser_drag_and_drop: maybeWrapTool("browser_drag_and_drop", (0, ai_1.tool)({ - description: "Drag an element and drop it onto another element", - inputSchema: playwrightTools.dragAndDropSchema, - execute: async (args) => withSnapshot(playwrightTools.dragAndDrop.bind(playwrightTools), args), - })), - browser_hover: maybeWrapTool("browser_hover", (0, ai_1.tool)({ - description: "Hover over an element", - inputSchema: playwrightTools.hoverSchema, - execute: async (args) => withSnapshot(playwrightTools.hover.bind(playwrightTools), args), - })), - browser_upload_file: maybeWrapTool("browser_upload_file", (0, ai_1.tool)({ - description: "Upload a file", - inputSchema: playwrightTools.uploadFileSchema, - execute: async (args) => withSnapshot(playwrightTools.uploadFile.bind(playwrightTools), args), - })), - browser_trigger_blur: maybeWrapTool("browser_trigger_blur", (0, ai_1.tool)({ - description: "Trigger a blur event by clicking on the body. Useful for when an element needs to lose focus.", - inputSchema: playwrightTools.triggerBlurSchema, - execute: async (args) => withSnapshot(playwrightTools.triggerBlur.bind(playwrightTools), args), - })), - get_unique_value: maybeWrapTool("get_unique_value", (0, ai_1.tool)({ - description: "Generate a unique value by appending a shortid to a prefix", - inputSchema: playwrightTools.getUniqueValueSchema, - execute: async (args) => playwrightTools.getUniqueValue(args), - })), - }; - return { - tools, - getPendingCacheData: () => playwrightTools.pendingCacheData, - clearPendingCacheData: () => { - playwrightTools.pendingCacheData = null; - }, - }; -} -class PlaywrightTools { - initialPage; - tabManager; - currentStep; - abortController; - pendingCacheData = null; - get page() { - return this.tabManager ? this.tabManager.active() : this.initialPage; - } - constructor(page, settings = {}) { - const { currentStep, abortController, tabManager } = settings; - this.initialPage = page; - this.tabManager = tabManager; - this.currentStep = currentStep; - this.abortController = abortController; - } - async getSnapshot() { - const snapshot = await this.page.ariaSnapshot({ mode: "ai", timeout: constants_1.SNAPSHOT_TIMEOUT }); - return `url: ${this.page.url()}\n\n${snapshot}`; - } - navigateSchema = zod_1.z.object({ - url: zod_1.z.string().describe("The URL to navigate to"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async navigate({ url }) { - await this.page.goto(url, { waitUntil: "load" }); - return { success: true, url }; - } - clickSchema = zod_1.z.object({ - ref: zod_1.z.string().describe("The ref of the element to click"), - elementDescription: zod_1.z - .string() - .describe("A description of the element to click, used for debugging"), - button: zod_1.z - .enum(["left", "right", "middle"]) - .optional() - .describe("Button to click, defaults to left"), - doubleClick: zod_1.z - .boolean() - .optional() - .describe("Whether to perform a double click instead of a single click"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async click({ ref, elementDescription, button, doubleClick, }) { - const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); - let cachedLocator = ""; - if (this.currentStep) { - cachedLocator = await this.resolveLocator(locator); - } - if (doubleClick) { - await locator.dblclick({ button, timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - } - else { - await locator.click({ button, timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - } - this.prepareCacheData(cachedLocator, doubleClick ? "dblclick" : "click", elementDescription); - return { - success: true, - }; - } - typeSchema = zod_1.z.object({ - ref: zod_1.z.string().describe("The ref of the element to type into"), - elementDescription: zod_1.z.string().describe("A description of the element, used for debugging"), - text: zod_1.z.string().describe("The text to type"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async type({ ref, elementDescription, text }) { - const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); - let cachedLocator = ""; - if (this.currentStep) { - cachedLocator = await this.resolveLocator(locator); - } - await locator.fill(text, { timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - this.prepareCacheData(cachedLocator, "fill", elementDescription, text); - return { - success: true, - text, - }; - } - screenshotSchema = zod_1.z.object({ - fullPage: zod_1.z.boolean().describe("Whether to take a screenshot of the full scrollable page"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async takeScreenshot({ fullPage: _fullPage }) { - // temporarily disabling fullPage as it sometimes causes issues with vision based models if dimension is too large. - // we can re-enable this in the future with some dimension checks and optimizations if needed - const screenshot = (await this.page.screenshot({ fullPage: false })).toString("base64"); - return screenshot; - } - pressKeySchema = zod_1.z.object({ - key: zod_1.z - .string() - .describe("Name of the key to press or a character to generate, such as `ArrowLeft` or `a`"), - }); - async pressKey({ key }) { - await this.page.keyboard.press(key); - return { success: true, key }; - } - async goBack() { - await this.page.goBack(); - return { success: true }; - } - async goForward() { - await this.page.goForward(); - return { success: true }; - } - async reload() { - await this.page.reload({ waitUntil: "load" }); - return { success: true }; - } - waitSchema = zod_1.z.object({ - timeout: zod_1.z.number().describe("Time to wait in milliseconds"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async wait({ timeout }) { - await this.page.waitForTimeout(timeout); - return { - success: true, - timeout, - message: `Waited for ${timeout}ms. You can either 1. wait more or 2. retry a previous action or 3. try a new action.`, - }; - } - mouseMoveSchema = zod_1.z.object({ - x: zod_1.z.number().describe("x-coordinate to move to"), - y: zod_1.z.number().describe("y-coordinate to move to"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async mouseMove({ x, y }) { - await this.page.mouse.move(x, y); - return { success: true }; - } - mouseDownSchema = zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async mouseDown(_) { - await this.page.mouse.down(); - return { success: true }; - } - mouseUpSchema = zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async mouseUp(_) { - await this.page.mouse.up(); - return { success: true }; - } - selectDropdownOptionSchema = zod_1.z.object({ - ref: zod_1.z.string().describe("The ref of the dropdown element to select from"), - elementDescription: zod_1.z - .string() - .describe("A description of the dropdown element, used for debugging"), - value: zod_1.z.string().describe("The value of the option to select"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async selectDropdownOption({ ref, elementDescription, value, }) { - const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); - let cachedLocator = ""; - if (this.currentStep) { - cachedLocator = await this.resolveLocator(locator); - } - await locator.selectOption(value, { timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - this.prepareCacheData(cachedLocator, "selectOption", elementDescription, value); - return { success: true, value }; - } - stopSchema = zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - }); - async stop(_) { - const DELAY = constants_1.STOP_DELAY; // 3 seconds - // brief sleep to ensure any ongoing navigation or actions are complete - // In future we could add graceful stop logic here - await new Promise((resolve) => setTimeout(resolve, DELAY)); - if (this.abortController) { - this.abortController.abort(); - } - return { success: true, message: "Execution stopped" }; - } - dragAndDropSchema = zod_1.z.object({ - sourceRef: zod_1.z.string().describe("The ref of the element to drag"), - sourceElementDescription: zod_1.z - .string() - .describe("A description of the source element being dragged, used for debugging"), - targetRef: zod_1.z.string().describe("The ref of the element to drop onto"), - targetElementDescription: zod_1.z - .string() - .describe("A description of the target element to drop onto, used for debugging"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async dragAndDrop({ sourceRef, sourceElementDescription, targetRef, targetElementDescription, }) { - const sourceLocator = this.page - .locator(`aria-ref=${sourceRef}`) - .describe(sourceElementDescription); - const targetLocator = this.page - .locator(`aria-ref=${targetRef}`) - .describe(targetElementDescription); - // Use two hover steps to ensure dragover events fire correctly across browsers - await sourceLocator.hover({ timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - await this.page.mouse.down(); - await targetLocator.hover({ timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - await targetLocator.hover({ timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - await this.page.mouse.up(); - return { - success: true, - }; - } - hoverSchema = zod_1.z.object({ - ref: zod_1.z.string().describe("The ref of the element to hover over"), - elementDescription: zod_1.z - .string() - .describe("A description of the element to hover, used for debugging"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async hover({ ref, elementDescription }) { - const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); - let cachedLocator = ""; - if (this.currentStep) { - cachedLocator = await this.resolveLocator(locator); - } - await locator.hover({ timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - this.prepareCacheData(cachedLocator, "hover", elementDescription); - return { - success: true, - }; - } - uploadFileSchema = zod_1.z.object({ - ref: zod_1.z.string().describe('The ref of the "button" that triggers a FileChooser to upload files'), - elementDescription: zod_1.z.string().describe("A description of the element, used for debugging"), - filePaths: zod_1.z.array(zod_1.z.string()).describe("Array of absolute file paths to upload"), - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async uploadFile({ ref, elementDescription, filePaths, // This is not a full path. It accepts a string filename which should be available in `uploads` directory - }) { - const locator = this.page.locator(`aria-ref=${ref}`).describe(elementDescription); - // We expect to find these files in the `./uploads` directory if no base path is configured - const uploadBasePath = (0, config_1.getConfig)().uploadBasePath || "./uploads"; - const prefixedFilePaths = filePaths.map((filePath) => `${uploadBasePath}/${filePath}`); - // File uploads are not cached for now as it needs a two step process - // We can solve this later by introducing multi-action caching if needed - const fileChooserPromise = this.page.waitForEvent("filechooser"); - await locator.click({ timeout: constants_1.LOCATOR_ACTION_TIMEOUT }); - const fileChooser = await fileChooserPromise; - await fileChooser.setFiles(prefixedFilePaths, { - timeout: constants_1.LOCATOR_ACTION_TIMEOUT, - }); - return { - success: true, - prefixedFilePaths, - }; - } - triggerBlurSchema = zod_1.z.object({ - reasoning: zod_1.z.string().describe("A quick one-line reasoning behind this action"), - doesActionAdvanceUsTowardsGoal: zod_1.z - .boolean() - .describe('"true" indicates high confidence that this action will advance us towards the goal. "false" indicates low confidence and could be an AI hallucination.'), - }); - async triggerBlur(_args) { - await this.page.locator("body").click({ position: { x: 0, y: 0 } }); - return { - success: true, - }; - } - getUniqueValueSchema = zod_1.z.object({ - prefix: zod_1.z.string().describe('The prefix to prepend to the unique id, e.g. "Topic", "Username"'), - }); - async getUniqueValue({ prefix }) { - const uniqueValue = `${prefix} ${shortid_1.default.generate()}`; - return { success: true, value: uniqueValue }; - } - async resolveLocator(locator) { - let generatedLocator = ""; - try { - generatedLocator = (await locator.normalize()).toString(); - } - catch (e) { - logger_1.logger.error({ err: e }, "Error generating locator"); - } - return generatedLocator; - } - /** - * Prepares cache data for a step action. Stores it on the instance - * instead of writing to Redis directly. The caller (runSteps in index.ts) - * decides whether to persist based on a logic (for now the number of tool calls). - */ - prepareCacheData(cachedLocator, action, elementDescription, value) { - if (!this.currentStep) { - return; - } - const ACTIONS_THAT_REQUIRE_NO_LOCATOR = ["waitForText"]; - // Skip caching if no locator is provided, unless it's an action that doesn't require a locator - if (!cachedLocator && ACTIONS_THAT_REQUIRE_NO_LOCATOR.indexOf(action) === -1) { - return; - } - /** - * If the current step's data contains values that are also present in the generated locator, it's likely that the locator is overfitted to those specific values and may not be reusable in future runs. - * In such cases, we should avoid caching to prevent storing non-reusable locators. - */ - let isCacheable = true; - if (this.currentStep.data && cachedLocator) { - for (const key in this.currentStep.data) { - const dataValue = this.currentStep.data[key]; - if (cachedLocator.includes(dataValue)) { - isCacheable = false; - break; - } - } - } - if (isCacheable) { - const cacheData = { - action, - description: elementDescription, - }; - if (cachedLocator) { - cacheData.locator = cachedLocator; - } - if (value) { - cacheData.value = value; - } - this.pendingCacheData = cacheData; - } - } -} diff --git a/dist/types.d.ts b/dist/types.d.ts deleted file mode 100644 index c7c7a73..0000000 --- a/dist/types.d.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { LanguageModel } from "ai"; -import { Expect, type Page, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType } from "@playwright/test"; -import type { TabManager } from "./utils/tab-manager"; -export type PageInput = Page | TabManager; -export type AssertionResult = { - assertionPassed: boolean; - confidenceScore: number; - reasoning: string; -}; -export type UserFlowOptions = { - page: Page; - userFlow: string; - steps: string; - assertion?: string; - effort?: "low" | "high"; - thinkingBudget?: number; - auth?: { - email: string; - password: string; - }; - model?: LanguageModel; -}; -/** - * Configuration for extracting data from a page using AI. - * The extracted value will be stored as {{run.keyName}} and can be used in subsequent steps. - */ -export type ExtractionConfig = { - /** Key name - the extracted value will be accessible as {{run.keyName}} in subsequent steps' data.value */ - as: string; - /** Prompt describing what to extract from the page/URL */ - prompt: string; -}; -export type Step = { - bypassCache?: boolean; - description: string; - data?: Record; - waitUntil?: string; - isScript?: boolean; - script?: string; - moduleId?: string; - /** Extract data from page/URL using AI and store as {{run.as}} for later use */ - extract?: ExtractionConfig; - /** Switch the active page before this step runs. 'main' = original tab, 'latest' = most recently opened, or numeric index. */ - switchToTab?: "main" | "latest" | number; -}; -export type AssertionOptions = { - page: PageInput; - assertion: string; - failSilently?: boolean; - test?: TestType; - expect: Expect<{}>; - effort?: "low" | "high"; - images?: string[]; - maxRetries?: number; - onRetry?: (retryCount: number, previousResult: AssertionResult) => void; -}; -export type WaitConditionResult = { - conditionMet: boolean; - reasoning: string; -}; -export type WaitForConditionOptions = { - page: PageInput; - condition: string; - pageScreenshotBeforeApplyingAction: string; - previousSteps?: Step[]; - currentStep: Step; - nextStep?: Step; - initialInterval?: number; - timeout?: number; - maxInterval?: number; -}; -export type RunStepsOptions = { - projectId?: string; - page: Page; - test?: TestType; - userFlow: string; - steps: Step[]; - bypassCache?: boolean; - failAssertionsSilently?: boolean; - auth?: { - email: string; - password: string; - }; - onStepStart?: (step: { - id: string; - description: string; - }) => void; - onStepEnd?: (step: { - id: string; - description: string; - }) => void; - onReasoning?: (step: { - id: string; - reasoning: string; - }) => void; - /** - * Execution ID to link multiple runSteps calls together. - * When provided, {{global.*}} placeholders are persisted to the cache - * and shared across all runSteps calls with the same executionId. - * Required when using {{global.*}} placeholders. - */ - executionId?: string; -} & ({ - assertions: Omit[]; - expect: Expect<{}>; -} | { - assertions?: never; - expect?: never; -}); diff --git a/dist/types.js b/dist/types.js deleted file mode 100644 index c8ad2e5..0000000 --- a/dist/types.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/utils/index.d.ts b/dist/utils/index.d.ts deleted file mode 100644 index ffe9cc6..0000000 --- a/dist/utils/index.d.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { type Page, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestType } from "@playwright/test"; -import { PageInput, WaitConditionResult, WaitForConditionOptions } from "../types"; -/** - * Resolves a `Page | TabManager` to the currently-active Playwright Page. - * Call this every time you need the page, so tab-switches mid-operation - * (e.g. during a polling wait) are reflected on the very next access. - */ -export declare const resolvePage: (input: PageInput) => Page; -export declare const withTimeout: (promise: Promise, ms: number, enabled?: boolean) => Promise; -export declare const safeSnapshot: (input: PageInput, timeout?: number) => Promise; -/** Deterministic short hash for Redis keys */ -export declare function flowKey(flow: string, { prefix, length, // 16 base64url chars ≈ 96 bits -secret, }?: { - prefix?: string; - length?: number; - secret?: string; -}): string; -export declare function runLocatorCode(input: PageInput, code: string): Promise; -/** - * Waits for the DOM to stabilize by observing mutations. - * Resolves when no mutations have occurred for the specified idle time. - * @param page The Playwright page instance - * @param idleTime Time in ms to wait after last mutation before considering DOM stable (default: 500ms) - * @param timeout Maximum time to wait for stabilization (default: 5000ms) - */ -export declare function waitForDOMStabilization(input: PageInput, test?: TestType, idleTime?: number, timeout?: number): Promise; -/** - * Waits for a condition to be met by polling AI with screenshots. - * Uses gemini-2.5-flash to evaluate the condition. - * Uses exponential backoff to reduce checks during long UI processes. - * - * @param options - Configuration options for waiting - * @param options.page - The Playwright page instance - * @param options.condition - The condition string to wait for - * @param options.previousSteps - Array of previous step descriptions for context - * @param options.currentStep - The current step being executed - * @param options.nextStep - The next step to be executed (for context) - * @param options.initialInterval - Initial interval between polls in ms (default: 1000) - * @param options.maxInterval - Maximum interval between polls in ms (default: 10000) - * @param options.timeout - Maximum time to wait in ms (default: 30000) - * @returns Promise with the final condition result - * - * @example - * ```typescript - * const result = await waitForCondition({ - * page, - * condition: 'The loading spinner should disappear', - * previousSteps: ['Navigate to dashboard', 'Click refresh button'], - * currentStep: 'Wait for data to load', - * nextStep: 'Verify data is displayed', - * initialInterval: 1000, - * maxInterval: 8000, - * }); - * ``` - */ -export declare function waitForCondition({ page, condition, pageScreenshotBeforeApplyingAction, previousSteps, currentStep, nextStep, initialInterval, maxInterval, timeout, }: WaitForConditionOptions): Promise; -/** - * Verifies if an action had an observable effect by comparing accessibility snapshots. - * Returns true if the action likely succeeded, false if it appears to have silently failed. - */ -export declare function verifyActionEffect(input: PageInput, action: string, snapshotBefore: string): Promise<{ - success: boolean; -}>; -/** - * Generates a random unique 10-digit phone number. - */ -export declare function generatePhoneNumber(): string; diff --git a/dist/utils/index.js b/dist/utils/index.js deleted file mode 100644 index 2dd8a61..0000000 --- a/dist/utils/index.js +++ /dev/null @@ -1,298 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.safeSnapshot = exports.withTimeout = exports.resolvePage = void 0; -exports.flowKey = flowKey; -exports.runLocatorCode = runLocatorCode; -exports.waitForDOMStabilization = waitForDOMStabilization; -exports.waitForCondition = waitForCondition; -exports.verifyActionEffect = verifyActionEffect; -exports.generatePhoneNumber = generatePhoneNumber; -const ai_1 = require("ai"); -const crypto_1 = require("crypto"); -const zod_1 = require("zod"); -const config_1 = require("../config"); -const logger_1 = require("../logger"); -const models_1 = require("../models"); -/** - * Resolves a `Page | TabManager` to the currently-active Playwright Page. - * Call this every time you need the page, so tab-switches mid-operation - * (e.g. during a polling wait) are reflected on the very next access. - */ -const resolvePage = (input) => typeof input.active === "function" - ? input.active() - : input; -exports.resolvePage = resolvePage; -const constants_1 = require("../constants"); -const withTimeout = (promise, ms, enabled = true) => { - if (!enabled) { - return promise; - } - return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => { - reject(new Error(`Promise timed out after ${ms} ms`)); - }, ms); - promise.then((res) => { - clearTimeout(timeoutId); - resolve(res); - }, (err) => { - clearTimeout(timeoutId); - reject(err); - }); - }); -}; -exports.withTimeout = withTimeout; -const safeSnapshot = async (input, timeout = constants_1.SNAPSHOT_TIMEOUT) => { - const attempt = async () => { - return await (0, exports.resolvePage)(input).ariaSnapshot({ mode: "ai", timeout }); - }; - try { - const snapshot = await attempt(); - return snapshot; - } - catch (err) { - if (err instanceof Error && err.message === "timeout") { - logger_1.logger.debug("Snapshot timed out, retrying once..."); - // retry once - return await attempt(); - } - throw err; - } -}; -exports.safeSnapshot = safeSnapshot; -/** Deterministic short hash for Redis keys */ -function flowKey(flow, { prefix = "flow", length = 16, // 16 base64url chars ≈ 96 bits -secret, // optional HMAC secret to avoid leaking the flow - } = {}) { - const h = secret - ? (0, crypto_1.createHash)("sha256").update(secret).update("\x00").update(flow).digest() - : (0, crypto_1.createHash)("sha256").update(flow).digest(); - // base64url without padding - const b64url = h.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); - const short = b64url.slice(0, length); - return `${prefix}:${short}`; -} -async function runLocatorCode(input, code) { - const fn = new Function("page", ` - return (async () => { - ${code} - })(); - `); - return fn((0, exports.resolvePage)(input)); -} -/** - * Waits for the DOM to stabilize by observing mutations. - * Resolves when no mutations have occurred for the specified idle time. - * @param page The Playwright page instance - * @param idleTime Time in ms to wait after last mutation before considering DOM stable (default: 500ms) - * @param timeout Maximum time to wait for stabilization (default: 5000ms) - */ -async function waitForDOMStabilization(input, test, idleTime = constants_1.DOM_STABILIZATION_IDLE, timeout = constants_1.DOM_STABILIZATION_TIMEOUT) { - const _waitForStabilization = async () => { - try { - await (0, exports.resolvePage)(input).evaluate(({ idleTime, timeout }) => { - return new Promise((resolve) => { - let timeoutId; - // eslint-disable-next-line prefer-const - let overallTimeoutId; - // @ts-expect-error MutationObserver exists in browser context via page.evaluate - const observer = new MutationObserver(() => { - clearTimeout(timeoutId); - timeoutId = setTimeout(() => { - observer.disconnect(); - clearTimeout(overallTimeoutId); - resolve(); - }, idleTime); - }); - // @ts-expect-error document.body exists in browser context via page.evaluate - observer.observe(document.body, { - childList: true, - subtree: true, - attributes: true, - characterData: true, - }); - // Start the idle timer immediately in case no mutations occur - timeoutId = setTimeout(() => { - observer.disconnect(); - clearTimeout(overallTimeoutId); - resolve(); - }, idleTime); - // Overall timeout to prevent hanging indefinitely - overallTimeoutId = setTimeout(() => { - observer.disconnect(); - clearTimeout(timeoutId); - resolve(); - }, timeout); - }); - }, { idleTime, timeout }); - } - catch (error) { - // If execution context was destroyed due to navigation, wait for load state - if ((error instanceof Error && error.message?.includes("Execution context was destroyed")) || - (error instanceof Error && error.message?.includes("navigation"))) { - // Navigation occurred - wait for the page to be ready - await (0, exports.resolvePage)(input).waitForLoadState("domcontentloaded").catch(() => { }); - return; - } - // Re-throw other errors - throw error; - } - }; - if (test) { - await test.step("Waiting for DOM stabilization", async () => { - await _waitForStabilization(); - }); - } - else { - await _waitForStabilization(); - } -} -const waitConditionSchema = zod_1.z.object({ - conditionMet: zod_1.z.boolean().describe("Indicates whether the wait condition has been met."), - reasoning: zod_1.z - .string() - .describe("Brief explanation of why the condition is met or not met based on the current page state."), -}); -/** - * Waits for a condition to be met by polling AI with screenshots. - * Uses gemini-2.5-flash to evaluate the condition. - * Uses exponential backoff to reduce checks during long UI processes. - * - * @param options - Configuration options for waiting - * @param options.page - The Playwright page instance - * @param options.condition - The condition string to wait for - * @param options.previousSteps - Array of previous step descriptions for context - * @param options.currentStep - The current step being executed - * @param options.nextStep - The next step to be executed (for context) - * @param options.initialInterval - Initial interval between polls in ms (default: 1000) - * @param options.maxInterval - Maximum interval between polls in ms (default: 10000) - * @param options.timeout - Maximum time to wait in ms (default: 30000) - * @returns Promise with the final condition result - * - * @example - * ```typescript - * const result = await waitForCondition({ - * page, - * condition: 'The loading spinner should disappear', - * previousSteps: ['Navigate to dashboard', 'Click refresh button'], - * currentStep: 'Wait for data to load', - * nextStep: 'Verify data is displayed', - * initialInterval: 1000, - * maxInterval: 8000, - * }); - * ``` - */ -async function waitForCondition({ page, condition, pageScreenshotBeforeApplyingAction, previousSteps = [], currentStep, nextStep, initialInterval = constants_1.WAIT_CONDITION_INITIAL_INTERVAL, maxInterval = constants_1.WAIT_CONDITION_MAX_INTERVAL, timeout = constants_1.WAIT_CONDITION_TIMEOUT, }) { - await waitForDOMStabilization(page); // Ensure DOM is stable before starting - const startTime = Date.now(); - let currentInterval = initialInterval; - const checkCondition = async () => { - const pageScreenshotAfterApplyingAction = (await (0, exports.resolvePage)(page).screenshot({ fullPage: false })).toString("base64"); - const prompt = ` -You are an AI-powered QA Agent designed to test web applications. - -You are helping to determine if a wait condition has been met during a test flow. - - -${previousSteps.length > 0 - ? `Previous steps completed:\n${previousSteps - .map((s, i) => `${i + 1}. ${s.description}\n${s.data ? ` Data: ${JSON.stringify(s.data)}` : ""}`) - .join("\n")}` - : "No previous steps."} - -Last executed step: ${currentStep.description} -${nextStep ? `Next step: ${nextStep.description}` : ""} - -Attached are before and after screenshots of the page surrounding the last executed step. Image 1 is before executing the step, and Image 2 is after executing the step. - - - -${condition} - - - -- Assume last executed step has been performed on the page. -- Examine the screenshot carefully to determine if the wait condition has been met. -- Consider the context of the previous steps and last executed step when evaluating. -- The condition should be evaluated based on what is visually present on the page. -- Be practical - if the core condition appears to be satisfied, mark it as met. -- Don't be overly strict about exact text matching; focus on the intent of the condition. - - - -- \`conditionMet\`: A boolean indicating whether the wait condition has been met. -- \`reasoning\`: A brief string explaining why the condition is or is not met. - - -Analyze the attached before and after screenshots and determine if the wait condition has been met. -`; - const { output } = await (0, ai_1.generateText)({ - model: (0, models_1.resolveModel)((0, config_1.getModelId)("utility")), - temperature: 0, - messages: [ - { - role: "user", - content: [ - { type: "text", text: prompt }, - { type: "image", image: pageScreenshotBeforeApplyingAction }, - { type: "image", image: pageScreenshotAfterApplyingAction }, - ], - }, - ], - output: ai_1.Output.object({ schema: waitConditionSchema }), - }); - return output; - }; - while (Date.now() - startTime < timeout) { - try { - const result = await checkCondition(); - if (result.conditionMet) { - logger_1.logger.info(`Condition met: ${result.reasoning}`); - return result; - } - logger_1.logger.debug(`Condition not met yet: ${result.reasoning}. Retrying in ${currentInterval}ms...`); - // Wait before next poll - await new Promise((resolve) => setTimeout(resolve, currentInterval)); - // Exponential backoff: double the interval, capped at maxInterval - currentInterval = Math.min(currentInterval * 2, maxInterval); - } - catch (error) { - logger_1.logger.error({ err: error }, "Error checking condition"); - // Wait before retry on error - await new Promise((resolve) => setTimeout(resolve, currentInterval)); - currentInterval = Math.min(currentInterval * 2, maxInterval); - } - } - // Timeout reached, do one final check - const finalResult = await checkCondition(); - if (!finalResult.conditionMet) { - logger_1.logger.warn(`Wait condition timed out after ${timeout}ms: ${finalResult.reasoning}`); - } - return finalResult; -} -/** - * Verifies if an action had an observable effect by comparing accessibility snapshots. - * Returns true if the action likely succeeded, false if it appears to have silently failed. - */ -async function verifyActionEffect(input, action, snapshotBefore) { - await waitForDOMStabilization(input); // Ensure DOM is stable before taking snapshot - // Actions that don't necessarily cause visible changes - if (action === "hover" || action === "waitForText") { - return { success: true }; - } - const snapshotAfter = await (0, exports.safeSnapshot)(input); - // If snapshots are identical, the action likely had no effect - if (snapshotBefore.trim() === snapshotAfter.trim()) { - throw new Error(`Action "${action}" appears to have had no effect on the page.`); - } - return { success: true }; -} -/** - * Generates a random unique 10-digit phone number. - */ -function generatePhoneNumber() { - // First digit should be 1-9 to avoid leading zero - const firstDigit = Math.floor(Math.random() * 9) + 1; - // Remaining 9 digits can be 0-9 - const remainingDigits = Array.from({ length: 9 }, () => Math.floor(Math.random() * 10)).join(""); - return `${firstDigit}${remainingDigits}`; -} diff --git a/dist/utils/playwright-best-practices.d.ts b/dist/utils/playwright-best-practices.d.ts deleted file mode 100644 index 957a6b5..0000000 --- a/dist/utils/playwright-best-practices.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare const PLAYWRIGHT_BEST_PRACTICES = "\n# Playwright Guidelines\n\n## 1. **Start waiting for API responses before triggering actions or use Promise.all()**\n\nStart listening for the expected network response **before** performing actions like button clicks to avoid race conditions.\n\n**\u2705 Do:**\n\n```jsx\nconst [response] = await Promise.all([\n page.waitForResponse(\"api/submit\"),\n page.getByRole('button', { name: 'Submit' }).click(),\n]);\n\nexpect(response.status()).toBe(200);\n// next steps\n```\n\n**\u2705 Do:**\n\n```jsx\nconst response = page.waitForResponse(\"api/submit\"); // notice no await here, start listening first\nawait page.getByRole('button', { name: 'Submit' }).click(); // then perform the action\nawait response; // wait for the response to complete\n```\n\nBoth of the above approaches are valid and good practice. But the following is a bad practice:\n\n**\uD83D\uDEAB Don\u2019t:**\n\n```jsx\nawait page.getByRole('button', { name: 'Submit' }).click();\nawait page.waitForResponse(\"api/submit\"); // Too late \u2014 response might have already returned\n```\n\n---\n\n## 2. **Use `test.slow()` or `test.setTimeout()` for longer tests**\n\nFor longer or more complex flows, use `test.slow()` or `test.setTimeout()` to increase timeout without causing unnecessary failures in CI.\n\n```jsx\ntest('generates invoice after third-party sync', async ({ page }) => {\n test.slow(); // Extends (3x) timeout for this test\n\n await page.click('button:has-text(\"Sync with Xero\")');\n await expect(page.getByText('Invoice generated')).toBeVisible();\n});\n\n```\n\n---\n\n## 3. Include cleanup logic using `afterAll`\n\nUse `afterAll` to clean up any test data created during the test suite. This keeps the environment clean and prevents leftover test artifacts. It also serves as a test for delete functionality.\n\n**\u2705 Example:**\n\n```jsx\nlet userId: string;\n\ntest('creates a user', async ({ page }) => {});\n\nafterAll(async ({ request }) => {\n if (userId) {\n const res = await request.delete(`/api/users/${userId}`);\n expect(res.ok()).toBeTruthy(); // Optional assertion\n }\n});\n```\n\n**\uD83D\uDD0E Why this matters:**\n\n- Ensures test-created entities are removed after execution\n- Keeps test environments clean for future runs\n- Helps catch issues in delete endpoints as well\n\n---\n\n## 4. **Use `pressSequentially` for more human-like typing**\n\nInstead of using `fill()`, consider using `pressSequentially()` when simulating text input, especially if you're recording or showcasing tests, it mimics a real user typing, making playback more natural.\n\n**\u2705 Do:**\n\n```jsx\nawait page.locator('#email').pressSequentially('test@example.com');\n```\n\n**\uD83D\uDEAB Don\u2019t:**\n\n```jsx\nawait page.fill('#email', 'test@example.com'); // Instant fill, less realistic in playback\n```\n\n---\n\n## 6. Never use magic timeouts\n\nTimeouts like `await page.waitForTimeout()` are a big reason behind flaky tests. Do not use them unless there is a very good reason behind it. Try to use other hooks like `waitFor()` or `waitForResponse()` to smartly wait for elements to appear / disappear or API calls to complete. In general, avoid `page.waitForTimeout()`.\n\n## 7. Never use page.waitForLoadState('networkidle')\n\nUsing `page.waitForLoadState('networkidle')` is an anti-pattern that can lead to flaky tests. Instead, use more specific waits like `waitForResponse()` or `waitForSelector()` to ensure the necessary conditions are met before proceeding.\n"; -export default PLAYWRIGHT_BEST_PRACTICES; diff --git a/dist/utils/playwright-best-practices.js b/dist/utils/playwright-best-practices.js deleted file mode 100644 index ec94a22..0000000 --- a/dist/utils/playwright-best-practices.js +++ /dev/null @@ -1,110 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const PLAYWRIGHT_BEST_PRACTICES = ` -# Playwright Guidelines - -## 1. **Start waiting for API responses before triggering actions or use Promise.all()** - -Start listening for the expected network response **before** performing actions like button clicks to avoid race conditions. - -**✅ Do:** - -\`\`\`jsx -const [response] = await Promise.all([ - page.waitForResponse("api/submit"), - page.getByRole('button', { name: 'Submit' }).click(), -]); - -expect(response.status()).toBe(200); -// next steps -\`\`\` - -**✅ Do:** - -\`\`\`jsx -const response = page.waitForResponse("api/submit"); // notice no await here, start listening first -await page.getByRole('button', { name: 'Submit' }).click(); // then perform the action -await response; // wait for the response to complete -\`\`\` - -Both of the above approaches are valid and good practice. But the following is a bad practice: - -**🚫 Don’t:** - -\`\`\`jsx -await page.getByRole('button', { name: 'Submit' }).click(); -await page.waitForResponse("api/submit"); // Too late — response might have already returned -\`\`\` - ---- - -## 2. **Use \`test.slow()\` or \`test.setTimeout()\` for longer tests** - -For longer or more complex flows, use \`test.slow()\` or \`test.setTimeout()\` to increase timeout without causing unnecessary failures in CI. - -\`\`\`jsx -test('generates invoice after third-party sync', async ({ page }) => { - test.slow(); // Extends (3x) timeout for this test - - await page.click('button:has-text("Sync with Xero")'); - await expect(page.getByText('Invoice generated')).toBeVisible(); -}); - -\`\`\` - ---- - -## 3. Include cleanup logic using \`afterAll\` - -Use \`afterAll\` to clean up any test data created during the test suite. This keeps the environment clean and prevents leftover test artifacts. It also serves as a test for delete functionality. - -**✅ Example:** - -\`\`\`jsx -let userId: string; - -test('creates a user', async ({ page }) => {}); - -afterAll(async ({ request }) => { - if (userId) { - const res = await request.delete(\`/api/users/\${userId}\`); - expect(res.ok()).toBeTruthy(); // Optional assertion - } -}); -\`\`\` - -**🔎 Why this matters:** - -- Ensures test-created entities are removed after execution -- Keeps test environments clean for future runs -- Helps catch issues in delete endpoints as well - ---- - -## 4. **Use \`pressSequentially\` for more human-like typing** - -Instead of using \`fill()\`, consider using \`pressSequentially()\` when simulating text input, especially if you're recording or showcasing tests, it mimics a real user typing, making playback more natural. - -**✅ Do:** - -\`\`\`jsx -await page.locator('#email').pressSequentially('test@example.com'); -\`\`\` - -**🚫 Don’t:** - -\`\`\`jsx -await page.fill('#email', 'test@example.com'); // Instant fill, less realistic in playback -\`\`\` - ---- - -## 6. Never use magic timeouts - -Timeouts like \`await page.waitForTimeout()\` are a big reason behind flaky tests. Do not use them unless there is a very good reason behind it. Try to use other hooks like \`waitFor()\` or \`waitForResponse()\` to smartly wait for elements to appear / disappear or API calls to complete. In general, avoid \`page.waitForTimeout()\`. - -## 7. Never use page.waitForLoadState('networkidle') - -Using \`page.waitForLoadState('networkidle')\` is an anti-pattern that can lead to flaky tests. Instead, use more specific waits like \`waitForResponse()\` or \`waitForSelector()\` to ensure the necessary conditions are met before proceeding. -`; -exports.default = PLAYWRIGHT_BEST_PRACTICES; diff --git a/dist/utils/secure-script-runner.d.ts b/dist/utils/secure-script-runner.d.ts deleted file mode 100644 index fa98379..0000000 --- a/dist/utils/secure-script-runner.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { Expect } from "@playwright/test"; -import type { PageInput } from "../types"; -export interface RunSecureScriptOptions { - page: PageInput; - script: string; - localValues?: Record; - globalValues?: Record; - expect?: Expect<{}>; -} -/** - * Safely execute a user-supplied Playwright script. - * - * The script is parsed as an AST and validated to only contain allowed - * Playwright method chains. User code is NEVER evaluated directly. - * - * @example - * await runSecureScript({ - * page, - * script: 'page.getByRole("button", { name: "Save" }).click()', - * }); - * - * @example - * // Multi-line scripts (each line is executed in order) - * await runSecureScript({ - * page, - * script: ` - * page.getByLabel("Email").fill("test@example.com") - * page.getByLabel("Password").fill("password123") - * page.getByRole("button", { name: "Submit" }).click() - * `, - * }); - */ -export declare function runSecureScript({ page: pageInput, script, localValues, globalValues, expect: expectFn, }: RunSecureScriptOptions): Promise; -/** - * Validate a script without executing it. - * Useful for pre-validation before saving scripts. - * - * @returns true if valid, throws Error if invalid - */ -export declare function validateScript(script: string): boolean; diff --git a/dist/utils/secure-script-runner.js b/dist/utils/secure-script-runner.js deleted file mode 100644 index 9fbe3d5..0000000 --- a/dist/utils/secure-script-runner.js +++ /dev/null @@ -1,1830 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.runSecureScript = runSecureScript; -exports.validateScript = validateScript; -const acorn_1 = require("acorn"); -const promises_1 = require("node:dns/promises"); -const logger_1 = require("../logger"); -const index_1 = require("./index"); -// ============================================================================= -// ALLOWED METHODS CONFIGURATION -// ============================================================================= -/** - * Methods that can be called directly on `page` to start a locator chain. - */ -const ALLOWED_START_METHODS = new Set([ - // Locator methods - "locator", - "getByRole", - "getByText", - "getByLabel", - "getByPlaceholder", - "getByTestId", - "getByAltText", - "getByTitle", - // Frame methods - "frameLocator", -]); -/** - * Assertion methods that can be called on expect(locator). - */ -const ALLOWED_EXPECT_ASSERTION_METHODS = new Set([ - // Text assertions - "toContainText", - "toHaveText", - // Visibility assertions - "toBeVisible", - "toBeHidden", - // State assertions - "toBeEnabled", - "toBeDisabled", - "toBeChecked", - "toBeEditable", - "toBeEmpty", - "toBeFocused", - // Attribute assertions - "toHaveAttribute", - "toHaveClass", - "toHaveCSS", - "toHaveId", - // Value assertions - "toHaveValue", - "toHaveValues", - // Count assertions - "toHaveCount", - // Screenshot assertions - "toHaveScreenshot", - // Attached assertions - "toBeAttached", - // Role assertions - "toHaveRole", - // Accessible name/description - "toHaveAccessibleName", - "toHaveAccessibleDescription", - // Generic assertions - "toBe", - "toEqual", - "toBeTruthy", - "toBeFalsy", - "toBeNull", - "toBeUndefined", - "toBeDefined", - "toBeNaN", - "toContain", - "toMatch", - "toHaveLength", -]); -/** - * Methods that can be chained on a locator to refine selection. - * Note: `and` and `or` are excluded because they require locator arguments, - * which cannot be created as literals in the current implementation. - */ -const ALLOWED_LOCATOR_CHAIN_METHODS = new Set([ - "first", - "last", - "nth", - "filter", // Note: `has`/`hasNot` options won't work (require locators), but `hasText`/`hasNotText` work - "locator", - "getByRole", - "getByText", - "getByLabel", - "getByPlaceholder", - "getByTestId", - "getByAltText", - "getByTitle", -]); -/** - * Action methods that perform interactions (must be last in chain). - * Note: `dragTo` is excluded because it requires a locator argument, - * which cannot be created as a literal in the current implementation. - */ -const ALLOWED_ACTION_METHODS = new Set([ - "click", - "dblclick", - "fill", - "type", - "press", - "check", - "uncheck", - "hover", - "focus", - "blur", - "selectOption", - "clear", - "scrollIntoViewIfNeeded", - "waitFor", - "isVisible", - "isEnabled", - "isChecked", - "textContent", - "innerText", - "innerHTML", - "getAttribute", - "inputValue", - "count", -]); -/** - * Methods that can be called directly on `page` (not locator chains). - * These are page-level operations like navigation, waits, etc. - * Note: `waitForFunction` is excluded because it requires a function argument, - * which cannot be created as a literal in the current implementation. - */ -const ALLOWED_PAGE_METHODS = new Set([ - // Navigation - "goto", - "reload", - "goBack", - "goForward", - // Waits - "waitForLoadState", - "waitForURL", - "waitForTimeout", - "waitForSelector", - // Page state - "title", - "url", - "content", - // Screenshots - "screenshot", - // Other - "close", - "bringToFront", - "setViewportSize", -]); -/** - * Methods that can be called on page.keyboard - */ -const ALLOWED_KEYBOARD_METHODS = new Set(["press", "type", "down", "up", "insertText"]); -/** - * Methods that can be called on page.mouse - */ -const ALLOWED_MOUSE_METHODS = new Set(["click", "dblclick", "down", "up", "move", "wheel"]); -/** - * Methods that can be called on context (BrowserContext). - * Accessed via page.context() internally. - */ -const ALLOWED_CONTEXT_METHODS = new Set([ - // Cookies - "cookies", - "addCookies", - "clearCookies", - // Storage - "storageState", - // Permissions - "clearPermissions", - // Geolocation - "setGeolocation", - // Other - "setOffline", - "waitForEvent", -]); -/** - * Methods that can be called on browser. - * Accessed via page.context().browser() internally. - */ -const ALLOWED_BROWSER_METHODS = new Set(["isConnected", "version"]); -/** - * Methods that can be called on console for logging. - */ -const ALLOWED_CONSOLE_METHODS = new Set(["log"]); -/** - * Methods that can be called on Response objects from fetch. - */ -const ALLOWED_RESPONSE_METHODS = new Set(["json", "text", "arrayBuffer", "blob"]); -/** - * HTTP methods allowed in fetch requests. - */ -const ALLOWED_FETCH_METHODS = new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]); -/** - * Hosts that are blocked for fetch requests (localhost/loopback). - */ -const BLOCKED_HOSTS = new Set(["localhost", "127.0.0.1", "0.0.0.0", "[::1]", "::1"]); -/** - * Reserved variable names that cannot be used in user scripts. - */ -const RESERVED_VARIABLE_NAMES = new Set([ - "page", - "context", - "browser", - "console", - "expect", - "process", - "require", - "import", - "fetch", - "eval", - "Function", -]); -/** - * Constructors allowed in computed expressions. - * Only safe, side-effect-free constructors are permitted. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const ALLOWED_CONSTRUCTORS = new Map([["URL", URL]]); -/** - * Properties/methods allowed per computed type. - * Maps constructor name → Set of allowed property/method names. - */ -const ALLOWED_COMPUTED_PROPERTIES = new Map([ - ["URL", new Set(["searchParams"])], - ["URLSearchParams", new Set(["toString"])], -]); -/** - * Binary operators allowed in computed expressions. - */ -const ALLOWED_BINARY_OPERATORS = new Set(["+"]); -/** - * Getter methods that should auto-log their return values. - * These are read-only methods that return data without side effects. - */ -const GETTER_METHODS = new Set([ - // Browser getters - "version", - "isConnected", - // Context getters - "cookies", - "storageState", - // Page getters - "title", - "url", - "content", - // Locator getters - "textContent", - "innerText", - "innerHTML", - "getAttribute", - "inputValue", - "count", - "isVisible", - "isEnabled", - "isChecked", -]); -// ============================================================================= -// ASSERTION HELPER -// ============================================================================= -function assert(condition, message) { - if (!condition) { - throw new Error(`[SecureScriptRunner] ${message}`); - } -} -// ============================================================================= -// URL VALIDATION FOR FETCH -// ============================================================================= -/** - * Check if a hostname is blocked (localhost, loopback, private IPs). - */ -function isBlockedHost(hostname) { - const lower = hostname.toLowerCase(); - if (BLOCKED_HOSTS.has(lower)) - return true; - // Block 127.x.x.x range - if (/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(lower)) - return true; - // Block private IP ranges - if (/^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(lower)) - return true; - if (/^192\.168\.\d{1,3}\.\d{1,3}$/.test(lower)) - return true; - if (/^172\.(1[6-9]|2\d|3[0-1])\.\d{1,3}\.\d{1,3}$/.test(lower)) - return true; - return false; -} -/** - * Validate a URL for fetch requests. - * Only allows http/https and blocks localhost/private IPs. - */ -function validateFetchUrl(url) { - let parsed; - try { - parsed = new URL(url); - } - catch { - throw new Error(`[SecureScriptRunner] Invalid URL: "${url}"`); - } - // Only allow http and https - if (parsed.protocol !== "http:" && parsed.protocol !== "https:") { - throw new Error(`[SecureScriptRunner] URL must use http or https protocol, got: ${parsed.protocol}`); - } - // Block localhost and private IPs - if (isBlockedHost(parsed.hostname)) { - throw new Error(`[SecureScriptRunner] Blocked URL: cannot fetch from ${parsed.hostname}`); - } -} -/** - * Validate that a URL's hostname does not resolve to a blocked IP address. - * Prevents DNS rebinding attacks where a domain initially passes hostname - * validation but resolves to a private/loopback IP at connection time. - */ -async function validateFetchUrlResolution(url) { - const parsed = new URL(url); - const hostname = parsed.hostname.replace(/^\[|\]$/g, ""); // strip IPv6 brackets - // Skip if the hostname is already an IP literal (already checked by isBlockedHost) - if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(hostname) || hostname.includes(":")) { - return; - } - try { - const { address } = await (0, promises_1.lookup)(hostname); - if (isBlockedHost(address)) { - throw new Error(`[SecureScriptRunner] DNS rebinding blocked: ${hostname} resolves to ${address}`); - } - } - catch (err) { - if (err instanceof Error && err.message.includes("DNS rebinding blocked")) { - throw err; - } - // DNS resolution failure — let fetch handle it naturally - } -} -/** - * Validate fetch options object. - */ -function validateFetchOptions(options) { - if (options === undefined || options === null) - return; - assert(typeof options === "object" && !Array.isArray(options), "fetch options must be an object"); - const opts = options; - // Validate method - if (opts.method !== undefined) { - assert(typeof opts.method === "string", "method must be a string"); - const method = opts.method.toUpperCase(); - assert(ALLOWED_FETCH_METHODS.has(method), `Invalid method: ${opts.method}. Allowed: ${[...ALLOWED_FETCH_METHODS].join(", ")}`); - } - // Validate headers - if (opts.headers !== undefined) { - assert(typeof opts.headers === "object" && !Array.isArray(opts.headers), "headers must be an object"); - for (const [key, value] of Object.entries(opts.headers)) { - assert(typeof value === "string", `header "${key}" value must be a string`); - } - } - // Validate body (string for JSON, or will auto-serialize objects) - if (opts.body !== undefined) { - assert(typeof opts.body === "string" || (typeof opts.body === "object" && opts.body !== null), "body must be a string or object"); - } -} -// ============================================================================= -// AST NODE TO STRING (for error messages) -// ============================================================================= -/** - * Convert an AST node to a readable string representation for error messages. - * This helps users understand what code caused the error. - */ -function nodeToString(node) { - switch (node.type) { - case "Identifier": - return node.name; - case "MemberExpression": { - const member = node; - const obj = nodeToString(member.object); - const prop = member.property.type === "Identifier" - ? member.property.name - : nodeToString(member.property); - return member.computed ? `${obj}[${prop}]` : `${obj}.${prop}`; - } - case "CallExpression": { - const call = node; - const callee = nodeToString(call.callee); - return `${callee}(...)`; - } - case "NewExpression": { - const newExpr = node; - const callee = nodeToString(newExpr.callee); - return `new ${callee}(...)`; - } - case "Literal": { - const literal = node; - if (literal.regex) { - return `/${literal.regex.pattern}/${literal.regex.flags}`; - } - return JSON.stringify(literal.value); - } - case "ArrayExpression": - return "[...]"; - case "ObjectExpression": - return "{...}"; - case "ArrowFunctionExpression": - case "FunctionExpression": - return "() => {...}"; - case "TemplateLiteral": - return "`...`"; - case "UnaryExpression": { - const unary = node; - return `${unary.operator}${nodeToString(unary.argument)}`; - } - case "BinaryExpression": { - const binary = node; - return `${nodeToString(binary.left)} ${binary.operator} ${nodeToString(binary.right)}`; - } - default: - return `[${node.type}]`; - } -} -// ============================================================================= -// SAFE LITERAL EVALUATION -// ============================================================================= -/** - * Only allow JSON-like literal values (string/number/boolean/null/regex/arrays/objects). - * No identifiers, function calls, template literals with expressions, etc. - */ -function evalSafeLiteral(node) { - switch (node.type) { - case "Literal": { - const literal = node; - // acorn uses Literal for string/number/bool/null and also RegExp in node.regex - if (literal.regex) { - return new RegExp(literal.regex.pattern, literal.regex.flags); - } - return literal.value; - } - case "ArrayExpression": { - const arr = node; - return arr.elements.map((el) => { - assert(el !== null, "Sparse arrays are not allowed"); - return evalSafeLiteral(el); - }); - } - case "ObjectExpression": { - const obj = node; - const out = {}; - for (const prop of obj.properties) { - assert(prop.type === "Property", "Only plain object properties allowed"); - assert(prop.kind === "init", "Only init properties allowed"); - assert(prop.computed === false, "Computed keys not allowed"); - let key = null; - if (prop.key.type === "Identifier") { - key = prop.key.name; - } - else if (prop.key.type === "Literal") { - const keyValue = prop.key.value; - if (typeof keyValue === "string") { - key = keyValue; - } - } - assert(typeof key === "string", "Object keys must be string or identifier"); - out[key] = evalSafeLiteral(prop.value); - } - return out; - } - case "UnaryExpression": { - // Handle negative numbers like -1 - const unary = node; - if (unary.operator === "-" && unary.argument.type === "Literal") { - const literal = unary.argument; - if (typeof literal.value === "number") { - return -literal.value; - } - } - throw new Error(`Unsupported unary expression: "${nodeToString(node)}". Only negative numbers like -1 are allowed.`); - } - case "TemplateLiteral": { - // Handle simple template literals without expressions (e.g., `hello`) - const template = node; - if (template.expressions.length > 0) { - throw new Error(`Template literals with expressions are not allowed: "${nodeToString(node)}". Use regular string literals instead.`); - } - // Concatenate all quasi values (for simple templates, there's just one) - return template.quasis.map((q) => q.value.cooked ?? q.value.raw).join(""); - } - default: - throw new Error(`Unsupported argument: "${nodeToString(node)}" (${node.type}). Only literals, arrays, and objects are allowed.`); - } -} -/** - * Check if a node is a literal value that can be safely evaluated. - * This includes: Literal, ArrayExpression, ObjectExpression, TemplateLiteral (without expressions), - * and UnaryExpression (for negative numbers like -1). - */ -function isLiteralNode(node) { - switch (node.type) { - case "Literal": - return true; - case "ArrayExpression": { - const arr = node; - return arr.elements.every((el) => el !== null && isLiteralNode(el)); - } - case "ObjectExpression": { - const obj = node; - return obj.properties.every((prop) => prop.type === "Property" && - prop.kind === "init" && - !prop.computed && - isLiteralNode(prop.value)); - } - case "TemplateLiteral": { - const template = node; - return template.expressions.length === 0; - } - case "UnaryExpression": { - const unary = node; - return unary.operator === "-" && unary.argument.type === "Literal"; - } - default: - return false; - } -} -/** - * Evaluate a node as a safe value, allowing variable references in addition to literals. - * Used for method arguments where variables should be allowed (e.g., page.goto(data.result)). - */ -function evalSafeValue(node, variables) { - if (variables) { - const chain = tryParseValueChain(node, variables); - if (chain) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let value = variables.get(chain.variableName); - for (const prop of chain.propertyPath) { - if (value === null || value === undefined) { - throw new Error(`Cannot read property "${prop}" of ${value} on variable "${chain.variableName}"`); - } - value = value[prop]; - } - return value; - } - // Try computed expressions (e.g., "prefix" + variable, new URL(...)) - const computed = parseSafeExpression(node, variables); - if (computed && computed.kind !== "literal") { - return evalSafeExpression(computed, variables); - } - } - return evalSafeLiteral(node); -} -// ============================================================================= -// COMPUTED EXPRESSION PARSING & EVALUATION -// ============================================================================= -const BLOCKED_PROPERTIES = new Set(["constructor", "__proto__", "prototype"]); -/** - * Parse an AST node into a safe computed expression tree. - * Returns null if the node doesn't match any computed expression pattern, - * allowing fallback to the existing parseAllowedChain. - */ -function parseSafeExpression(node, variables) { - // Literals - if (isLiteralNode(node)) { - return { kind: "literal", value: evalSafeLiteral(node) }; - } - // Variable references (identifiers and member expressions on known variables) - if (variables) { - const chain = tryParseValueChain(node, variables); - if (chain) { - return { - kind: "variableRef", - variableName: chain.variableName, - propertyPath: chain.propertyPath, - }; - } - } - // new Constructor(args) — e.g., new URL(expr) - if (node.type === "NewExpression") { - const newExpr = node; - if (newExpr.callee.type !== "Identifier") - return null; - const ctorName = newExpr.callee.name; - if (!ALLOWED_CONSTRUCTORS.has(ctorName)) - return null; - const args = []; - for (const arg of newExpr.arguments) { - const parsed = parseSafeExpression(arg, variables); - if (!parsed) - return null; - args.push(parsed); - } - return { kind: "newExpression", constructorName: ctorName, args }; - } - // Method call: expr.method(args) — e.g., searchParams.toString() - if (node.type === "CallExpression") { - const call = node; - if (call.callee.type === "MemberExpression") { - const member = call.callee; - if (member.computed) - return null; - if (member.property.type !== "Identifier") - return null; - const methodName = member.property.name; - if (BLOCKED_PROPERTIES.has(methodName)) - return null; - // If the object is a variable holding a Response, bail out so - // parseAllowedChain → executeChain handles it (which properly awaits - // async methods like .json() / .text()). - if (member.object.type === "Identifier" && - variables?.has(member.object.name) && - variables.get(member.object.name) instanceof Response) { - return null; - } - const objExpr = parseSafeExpression(member.object, variables); - if (!objExpr) - return null; - const args = []; - for (const arg of call.arguments) { - const parsed = parseSafeExpression(arg, variables); - if (!parsed) - return null; - args.push(parsed); - } - return { kind: "methodCall", object: objExpr, method: methodName, args }; - } - return null; - } - // Property access: expr.prop — e.g., url.searchParams - if (node.type === "MemberExpression") { - const member = node; - if (member.computed) - return null; - if (member.property.type !== "Identifier") - return null; - const propName = member.property.name; - if (BLOCKED_PROPERTIES.has(propName)) - return null; - const objExpr = parseSafeExpression(member.object, variables); - if (!objExpr) - return null; - return { kind: "propertyAccess", object: objExpr, property: propName }; - } - // Binary expression: left + right - if (node.type === "BinaryExpression") { - const bin = node; - if (!ALLOWED_BINARY_OPERATORS.has(bin.operator)) - return null; - const left = parseSafeExpression(bin.left, variables); - if (!left) - return null; - const right = parseSafeExpression(bin.right, variables); - if (!right) - return null; - return { kind: "binaryExpression", operator: bin.operator, left, right }; - } - return null; -} -/** - * Validate that a property/method access on a computed value is allowed. - * Enforces type-specific allowlists at runtime. - */ -function validateComputedAccess(obj, propOrMethod) { - if (BLOCKED_PROPERTIES.has(propOrMethod)) { - throw new Error(`[SecureScriptRunner] Access to "${propOrMethod}" is blocked on computed values`); - } - if (obj instanceof URL) { - const allowed = ALLOWED_COMPUTED_PROPERTIES.get("URL"); - if (!allowed || !allowed.has(propOrMethod)) { - throw new Error(`[SecureScriptRunner] Property/method "${propOrMethod}" is not allowed on URL objects. Allowed: ${[...(allowed ?? [])].join(", ")}`); - } - return; - } - if (obj instanceof URLSearchParams) { - const allowed = ALLOWED_COMPUTED_PROPERTIES.get("URLSearchParams"); - if (!allowed || !allowed.has(propOrMethod)) { - throw new Error(`[SecureScriptRunner] Property/method "${propOrMethod}" is not allowed on URLSearchParams objects. Allowed: ${[...(allowed ?? [])].join(", ")}`); - } - return; - } - // Allow property access on plain objects (e.g. JSON response data) - if (obj !== null && - obj !== undefined && - typeof obj === "object" && - Object.getPrototypeOf(obj) === Object.prototype) { - return; - } - throw new Error(`[SecureScriptRunner] Computed property/method access is not allowed on objects of this type`); -} -/** - * Evaluate a parsed safe expression tree at runtime. - */ -function evalSafeExpression(expr, variables) { - switch (expr.kind) { - case "literal": - return expr.value; - case "variableRef": { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let value = variables.get(expr.variableName); - if (value === undefined && !variables.has(expr.variableName)) { - throw new Error(`[SecureScriptRunner] Variable "${expr.variableName}" is not defined`); - } - for (const prop of expr.propertyPath) { - if (value === null || value === undefined) { - throw new Error(`[SecureScriptRunner] Cannot read property "${prop}" of ${value} on variable "${expr.variableName}"`); - } - value = value[prop]; - } - return value; - } - case "newExpression": { - const Ctor = ALLOWED_CONSTRUCTORS.get(expr.constructorName); - if (!Ctor) { - throw new Error(`[SecureScriptRunner] Constructor "${expr.constructorName}" is not allowed`); - } - const args = expr.args.map((a) => evalSafeExpression(a, variables)); - return new Ctor(...args); - } - case "propertyAccess": { - const obj = evalSafeExpression(expr.object, variables); - validateComputedAccess(obj, expr.property); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return obj[expr.property]; - } - case "methodCall": { - const obj = evalSafeExpression(expr.object, variables); - validateComputedAccess(obj, expr.method); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const fn = obj[expr.method]; - if (typeof fn !== "function") { - throw new Error(`[SecureScriptRunner] "${expr.method}" is not a function`); - } - const args = expr.args.map((a) => evalSafeExpression(a, variables)); - return fn.call(obj, ...args); - } - case "binaryExpression": { - const left = evalSafeExpression(expr.left, variables); - const right = evalSafeExpression(expr.right, variables); - if (expr.operator === "+") { - if (typeof left !== "string" && typeof right !== "string") { - throw new Error(`[SecureScriptRunner] The "+" operator requires at least one string operand`); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return left + right; - } - throw new Error(`[SecureScriptRunner] Operator "${expr.operator}" is not allowed`); - } - default: { - const _exhaustive = expr; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - throw new Error(`[SecureScriptRunner] Unknown expression kind: ${_exhaustive.kind}`); - } - } -} -// ============================================================================= -// CHAIN PARSING -// ============================================================================= -/** - * Parse a locator chain starting from page, e.g., "page.getByRole(...).first()" - * Returns the parsed steps. - */ -function parseLocatorChain(node) { - const steps = []; - let current = node; - while (current && current.type === "CallExpression") { - const call = current; - const callee = call.callee; - if (callee.type !== "MemberExpression") { - break; // Not a method call, stop - } - const member = callee; - assert(member.computed === false, "Computed property access is not allowed"); - const prop = member.property; - assert(prop.type === "Identifier", "Method name must be an identifier"); - const method = prop.name; - // Arguments must be safe literals - const args = call.arguments.map((a) => evalSafeLiteral(a)); - steps.push({ method, args }); - // Move inward: next is the object you're calling the method on - current = member.object; - } - // Now current should be Identifier("page") - assert(current !== null && current.type === "Identifier", "Locator chain must start from `page`"); - assert(current.name === "page", `Locator chain must start from 'page', got '${current.name}'`); - // We collected from outermost to innermost; reverse to execute in order - steps.reverse(); - return steps; -} -/** - * Check if a node is an identifier with a specific name - */ -function isIdentifier(node, name) { - return node.type === "Identifier" && node.name === name; -} -/** - * Check if a node is a member expression like `page.keyboard` or `page.mouse` - */ -function isPageSubObject(node, subObject) { - if (node.type !== "MemberExpression") - return false; - const member = node; - return isIdentifier(member.object, "page") && isIdentifier(member.property, subObject); -} -/** - * Parse "page.getByRole(...).click()", "page.goto(...)", "page.keyboard.press(...)", - * "fetch(...)", "variable.json()", or "expect(page.getByRole(...)).toContainText(...)" - * Returns the appropriate ParsedChain type. - */ -function parseAllowedChain(exprNode, variables) { - // Expression must be a call at the top-level (so you can actually do something) - assert(exprNode.type === "CallExpression", "Top-level must be a function call"); - const topCall = exprNode; - // Check for expect() patterns (including negated and value-based) - const expectResult = tryParseExpectChain(topCall, variables); - if (expectResult) - return expectResult; - // Check for page.keyboard.xxx() pattern - const keyboardResult = tryParseKeyboardChain(topCall); - if (keyboardResult) - return keyboardResult; - // Check for page.mouse.xxx() pattern - const mouseResult = tryParseMouseChain(topCall); - if (mouseResult) - return mouseResult; - // Check for page.method() pattern (page-level methods like goto, reload) - const pageMethodResult = tryParsePageMethodChain(topCall, variables); - if (pageMethodResult) - return pageMethodResult; - // Check for context.xxx() pattern - const contextResult = tryParseContextChain(topCall); - if (contextResult) - return contextResult; - // Check for browser.xxx() pattern - const browserResult = tryParseBrowserChain(topCall); - if (browserResult) - return browserResult; - // Check for console.xxx() pattern - const consoleResult = tryParseConsoleChain(topCall, variables); - if (consoleResult) - return consoleResult; - // Check for fetch() pattern - const fetchResult = tryParseFetchChain(topCall); - if (fetchResult) - return fetchResult; - // Check for response method pattern (variable.json(), variable.text()) - if (variables) { - const responseMethodResult = tryParseResponseMethodChain(topCall, variables); - if (responseMethodResult) - return responseMethodResult; - } - // Default: parse as locator chain (page.getByRole().click()) - const steps = parseLocatorChain(exprNode); - validateLocatorChainSteps(steps); - return { - type: "locator", - steps, - }; -} -/** - * Try to parse an expect() chain, including negated assertions. - * Patterns: - * - expect(locator).toBeVisible() - * - expect(locator).not.toBeVisible() - * - expect(variable).toBe(value) - * - expect(variable.property).toBe(value) - */ -function tryParseExpectChain(topCall, variables) { - if (topCall.callee.type !== "MemberExpression") - return null; - const topMember = topCall.callee; - let expectCall = null; - let assertionMethod = ""; - let negated = false; - // Check for negated pattern: expect(locator).not.toBeVisible() - // Structure: CallExpr { callee: MemberExpr { object: MemberExpr { object: CallExpr(expect), property: "not" }, property: "toBeVisible" } } - if (topMember.object.type === "MemberExpression" && - isIdentifier(topMember.object.property, "not")) { - const notMember = topMember.object; - if (notMember.object.type === "CallExpression" && - notMember.object.callee.type === "Identifier" && - isIdentifier(notMember.object.callee, "expect")) { - expectCall = notMember.object; - negated = true; - assert(topMember.property.type === "Identifier", "Assertion method must be an identifier"); - assertionMethod = topMember.property.name; - } - } - // Check for regular pattern: expect(locator).toBeVisible() - if (!expectCall && - topMember.object.type === "CallExpression" && - topMember.object.callee.type === "Identifier" && - isIdentifier(topMember.object.callee, "expect")) { - expectCall = topMember.object; - assert(topMember.property.type === "Identifier", "Assertion method must be an identifier"); - assertionMethod = topMember.property.name; - } - if (!expectCall) - return null; - // Validate assertion method - assert(ALLOWED_EXPECT_ASSERTION_METHODS.has(assertionMethod), `Disallowed assertion method: ${assertionMethod}. Allowed: ${[...ALLOWED_EXPECT_ASSERTION_METHODS].join(", ")}`); - // Get assertion arguments - const assertionArgs = topCall.arguments.map((a) => evalSafeLiteral(a)); - // Parse the argument inside expect() - assert(expectCall.arguments.length === 1, "expect() must have exactly one argument"); - const expectArg = expectCall.arguments[0]; - // Check if the argument is a variable reference (possibly with property access) - // e.g., expect(data) or expect(data.url) or expect(response.status) - const valueChain = tryParseValueChain(expectArg, variables); - if (valueChain) { - return { - type: "expectValue", - variableName: valueChain.variableName, - propertyPath: valueChain.propertyPath, - assertionMethod: assertionMethod, - assertionArgs, - negated, - }; - } - // Check if the argument is a literal value (string, number, boolean, etc.) - // e.g., expect("some string").toBe("expected") or expect(42).toBe(42) - if (isLiteralNode(expectArg)) { - const literalValue = evalSafeLiteral(expectArg); - return { - type: "expectLiteral", - literalValue, - assertionMethod: assertionMethod, - assertionArgs, - negated, - }; - } - // Otherwise, try to parse as a locator chain (page.getByRole(), etc.) - const locatorSteps = parseLocatorChain(expectArg); - validateLocatorSteps(locatorSteps); - return { - type: "expect", - locatorSteps, - assertionMethod: assertionMethod, - assertionArgs, - negated, - }; -} -/** - * Try to parse a value chain like `data` or `data.url` or `data.nested.property` - * Returns the variable name and property path if it's a valid variable reference. - */ -function tryParseValueChain(node, variables) { - // Simple identifier: expect(data) - if (node.type === "Identifier") { - const name = node.name; - // Only match if it's a known variable (not page, context, etc.) - if (variables && variables.has(name)) { - return { variableName: name, propertyPath: [] }; - } - return null; - } - // Member expression: expect(data.url) or expect(data.nested.property) - if (node.type === "MemberExpression") { - const propertyPath = []; - // Walk up the member chain to get all properties - let current = node; - while (current.type === "MemberExpression") { - const mem = current; - assert(mem.property.type === "Identifier", "Property access must be an identifier"); - assert(!mem.computed, "Computed property access not allowed"); - propertyPath.unshift(mem.property.name); - current = mem.object; - } - // The base should be an identifier (the variable name) - if (current.type === "Identifier") { - const name = current.name; - // Only match if it's a known variable - if (variables && variables.has(name)) { - return { variableName: name, propertyPath }; - } - } - } - return null; -} -/** - * Try to parse page.keyboard.xxx() pattern - */ -function tryParseKeyboardChain(topCall) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - if (!isPageSubObject(member.object, "keyboard")) - return null; - assert(member.property.type === "Identifier", "Keyboard method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_KEYBOARD_METHODS.has(method), `Disallowed keyboard method: ${method}. Allowed: ${[...ALLOWED_KEYBOARD_METHODS].join(", ")}`); - const args = topCall.arguments.map((a) => evalSafeLiteral(a)); - return { - type: "keyboard", - method, - args, - }; -} -/** - * Try to parse page.mouse.xxx() pattern - */ -function tryParseMouseChain(topCall) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - if (!isPageSubObject(member.object, "mouse")) - return null; - assert(member.property.type === "Identifier", "Mouse method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_MOUSE_METHODS.has(method), `Disallowed mouse method: ${method}. Allowed: ${[...ALLOWED_MOUSE_METHODS].join(", ")}`); - const args = topCall.arguments.map((a) => evalSafeLiteral(a)); - return { - type: "mouse", - method, - args, - }; -} -/** - * Try to parse page.method() pattern (page-level methods like goto, reload) - */ -function tryParsePageMethodChain(topCall, variables) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - // Check if it's page.methodName() where methodName is in ALLOWED_PAGE_METHODS - if (!isIdentifier(member.object, "page")) - return null; - assert(member.property.type === "Identifier", "Page method must be an identifier"); - const method = member.property.name; - // Only match if it's a page-level method, not a locator start method - if (!ALLOWED_PAGE_METHODS.has(method)) - return null; - const args = topCall.arguments.map((a) => evalSafeValue(a, variables)); - return { - type: "pageMethod", - method, - args, - }; -} -/** - * Try to parse context.xxx() pattern - * Executed as page.context().xxx() internally - */ -function tryParseContextChain(topCall) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - // Check if it's context.methodName() - if (!isIdentifier(member.object, "context")) - return null; - assert(member.property.type === "Identifier", "Context method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_CONTEXT_METHODS.has(method), `Disallowed context method: ${method}. Allowed: ${[...ALLOWED_CONTEXT_METHODS].join(", ")}`); - const args = topCall.arguments.map((a) => evalSafeLiteral(a)); - return { - type: "context", - method, - args, - }; -} -/** - * Try to parse browser.xxx() pattern - * Executed as page.context().browser()?.xxx() internally - */ -function tryParseBrowserChain(topCall) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - // Check if it's browser.methodName() - if (!isIdentifier(member.object, "browser")) - return null; - assert(member.property.type === "Identifier", "Browser method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_BROWSER_METHODS.has(method), `Disallowed browser method: ${method}. Allowed: ${[...ALLOWED_BROWSER_METHODS].join(", ")}`); - const args = topCall.arguments.map((a) => evalSafeLiteral(a)); - return { - type: "browser", - method, - args, - }; -} -/** - * Try to parse console.xxx() pattern - * Supports console.log, console.warn, console.error, console.info, console.debug - */ -function tryParseConsoleChain(topCall, variables) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - // Check if it's console.methodName() - if (!isIdentifier(member.object, "console")) - return null; - assert(member.property.type === "Identifier", "Console method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_CONSOLE_METHODS.has(method), `Disallowed console method: ${method}. Allowed: ${[...ALLOWED_CONSOLE_METHODS].join(", ")}`); - // Arguments can be safe literals or variable references - const args = topCall.arguments.map((a) => evalSafeValue(a, variables)); - return { - type: "console", - method, - args, - }; -} -/** - * Try to parse fetch(url, options?) pattern. - */ -function tryParseFetchChain(topCall) { - // Check if it's fetch(url, options?) - if (topCall.callee.type !== "Identifier") - return null; - if (topCall.callee.name !== "fetch") - return null; - assert(topCall.arguments.length >= 1 && topCall.arguments.length <= 2, "fetch() requires 1-2 arguments: fetch(url, options?)"); - // Extract URL - const urlArg = evalSafeLiteral(topCall.arguments[0]); - assert(typeof urlArg === "string", "fetch URL must be a string"); - // Validate URL security - validateFetchUrl(urlArg); - // Extract options if present - let options; - if (topCall.arguments.length === 2) { - const optArg = evalSafeLiteral(topCall.arguments[1]); - validateFetchOptions(optArg); - options = optArg; - } - return { - type: "fetch", - url: urlArg, - options, - }; -} -/** - * Try to parse response method chain: variable.json(), variable.text(), etc. - */ -function tryParseResponseMethodChain(topCall, variables) { - if (topCall.callee.type !== "MemberExpression") - return null; - const member = topCall.callee; - // Check if object is a variable identifier - if (member.object.type !== "Identifier") - return null; - const varName = member.object.name; - // Variable must exist (will be checked at runtime for Response type) - if (!variables.has(varName)) - return null; - assert(member.property.type === "Identifier", "Response method must be an identifier"); - const method = member.property.name; - assert(ALLOWED_RESPONSE_METHODS.has(method), `Disallowed response method: ${method}. Allowed: ${[...ALLOWED_RESPONSE_METHODS].join(", ")}`); - const args = topCall.arguments.map((a) => evalSafeLiteral(a)); - return { - type: "responseMethod", - variableName: varName, - method, - args, - }; -} -/** - * Validate locator steps (used inside expect - no actions allowed). - */ -function validateLocatorSteps(steps) { - assert(steps.length >= 1, "Empty locator chain"); - assert(ALLOWED_START_METHODS.has(steps[0].method), `First call must be one of: ${[...ALLOWED_START_METHODS].join(", ")}. Got: ${steps[0].method}`); - // All steps must be start methods or chain methods (no actions in expect locators) - for (let i = 0; i < steps.length; i++) { - const m = steps[i].method; - if (i === 0) - continue; // start method already validated - const isChain = ALLOWED_LOCATOR_CHAIN_METHODS.has(m); - const isStart = ALLOWED_START_METHODS.has(m); // For nested locators - assert(isChain || isStart, `Disallowed method in locator chain: ${m}. Allowed: ${[...ALLOWED_LOCATOR_CHAIN_METHODS].join(", ")}`); - } -} -/** - * Validate locator chain steps (actions allowed at the end). - */ -function validateLocatorChainSteps(steps) { - assert(steps.length >= 1, "Empty chain"); - assert(ALLOWED_START_METHODS.has(steps[0].method), `First call must be one of: ${[...ALLOWED_START_METHODS].join(", ")}. Got: ${steps[0].method}`); - // Validate each step is in allowlists - for (let i = 0; i < steps.length; i++) { - const m = steps[i].method; - if (i === 0) - continue; // start method already validated - const isChain = ALLOWED_LOCATOR_CHAIN_METHODS.has(m); - const isAction = ALLOWED_ACTION_METHODS.has(m); - assert(isChain || isAction, `Disallowed method: ${m}. Allowed chain methods: ${[...ALLOWED_LOCATOR_CHAIN_METHODS].join(", ")}. Allowed action methods: ${[...ALLOWED_ACTION_METHODS].join(", ")}`); - // If it's an action, it must be the last step - if (isAction && i !== steps.length - 1) { - assert(false, `Action method '${m}' must be the last in the chain, but found more methods after it`); - } - } -} -// ============================================================================= -// ARGUMENT VALIDATION -// ============================================================================= -/** - * Per-method argument validation for extra safety. - */ -function validateMethodArgs(method, args) { - switch (method) { - case "locator": - assert(typeof args[0] === "string", "locator(selector) requires a string selector"); - assert(args.length <= 2, "locator() accepts at most 2 arguments"); - break; - case "getByRole": - assert(typeof args[0] === "string", "getByRole(role) requires a string role"); - if (args[1] != null) { - assert(typeof args[1] === "object" && !Array.isArray(args[1]), "getByRole() options must be an object"); - } - break; - case "getByText": - case "getByLabel": - case "getByPlaceholder": - case "getByAltText": - case "getByTitle": - assert(typeof args[0] === "string" || args[0] instanceof RegExp, `${method}() requires a string or RegExp`); - break; - case "getByTestId": - assert(typeof args[0] === "string" || args[0] instanceof RegExp, "getByTestId() requires a string or RegExp"); - break; - case "nth": - assert(typeof args[0] === "number" && Number.isInteger(args[0]), "nth(index) requires an integer index"); - break; - case "fill": - case "type": - assert(typeof args[0] === "string", `${method}(value) requires a string value`); - break; - case "press": - assert(typeof args[0] === "string", "press(key) requires a string key"); - break; - case "selectOption": - // Can be string, array of strings, or object - break; - case "frameLocator": - assert(typeof args[0] === "string", "frameLocator(selector) requires a string selector"); - break; - // Actions that take no required arguments - case "click": - case "dblclick": - case "check": - case "uncheck": - case "hover": - case "focus": - case "blur": - case "clear": - case "scrollIntoViewIfNeeded": - case "first": - case "last": - case "count": - case "isVisible": - case "isEnabled": - case "isChecked": - case "textContent": - case "innerText": - case "innerHTML": - case "inputValue": - // These are fine with no args or optional args - break; - case "filter": - case "and": - case "or": - // These take locator options - break; - case "waitFor": - case "getAttribute": - // These have their own validation in Playwright - break; - // Page-level methods - case "goto": - assert(typeof args[0] === "string", "goto(url) requires a string URL"); - validateFetchUrl(args[0]); // Block file://, localhost, and private IPs - break; - case "waitForURL": - assert(typeof args[0] === "string" || args[0] instanceof RegExp, "waitForURL() requires a string or RegExp"); - break; - case "waitForTimeout": - assert(typeof args[0] === "number", "waitForTimeout(ms) requires a number"); - break; - case "waitForSelector": - assert(typeof args[0] === "string", "waitForSelector(selector) requires a string"); - break; - case "waitForLoadState": - // Optional state argument - if (args[0] != null) { - assert(typeof args[0] === "string", "waitForLoadState(state) requires a string state"); - } - break; - case "setViewportSize": - assert(typeof args[0] === "object" && args[0] !== null, "setViewportSize({ width, height }) requires an object"); - break; - // Keyboard methods - case "insertText": - assert(typeof args[0] === "string", "keyboard.insertText(text) requires a string"); - break; - case "down": - case "up": - // Keyboard down/up take a key string - if (args.length > 0) { - assert(typeof args[0] === "string", `keyboard.${method}(key) requires a string key`); - } - break; - // Mouse methods - case "move": - assert(typeof args[0] === "number" && typeof args[1] === "number", "mouse.move(x, y) requires two numbers"); - break; - case "wheel": - assert(typeof args[0] === "number" && typeof args[1] === "number", "mouse.wheel(deltaX, deltaY) requires two numbers"); - break; - // Drag and drop - case "dragTo": - // dragTo takes a locator, which we can't easily validate here - // Playwright will validate it at runtime - break; - // Page methods that take no required arguments - case "reload": - case "goBack": - case "goForward": - case "title": - case "url": - case "content": - case "screenshot": - case "close": - case "bringToFront": - case "waitForFunction": - // These are fine with no args or optional args - break; - default: - // Unknown method - this shouldn't happen if allowlists are correct - break; - } -} -// ============================================================================= -// DATA PLACEHOLDER INTERPOLATION -// ============================================================================= -/** - * Escape a string value for safe insertion into a JavaScript string literal. - * Handles both single and double quotes since scripts may use either. - */ -function escapeForStringLiteral(value) { - return value - .replace(/\\/g, "\\\\") // Escape backslashes first - .replace(/'/g, "\\'") // Escape single quotes - .replace(/"/g, '\\"') // Escape double quotes - .replace(/\n/g, "\\n") // Escape newlines - .replace(/\r/g, "\\r") // Escape carriage returns - .replace(/\t/g, "\\t"); // Escape tabs -} -/** - * Strip inline comments from a line of code. - * Handles // comments while preserving // inside string literals. - * - * Examples: - * - 'page.goto("https://example.com") // comment' → 'page.goto("https://example.com")' - * - 'page.goto("https://example.com")' → 'page.goto("https://example.com")' (URL preserved) - * - "page.fill('input', 'test') // fill" → "page.fill('input', 'test')" - */ -function stripInlineComments(line) { - let inString = null; - let escaped = false; - for (let i = 0; i < line.length; i++) { - const char = line[i]; - if (escaped) { - escaped = false; - continue; - } - if (char === "\\") { - escaped = true; - continue; - } - // Track string state - if (char === '"' || char === "'") { - if (inString === null) { - inString = char; - } - else if (inString === char) { - inString = null; - } - continue; - } - // Check for // comment start (only outside strings) - if (inString === null && char === "/" && line[i + 1] === "/") { - // Found comment start, return everything before it (trimmed) - return line.slice(0, i).trim(); - } - } - return line; -} -/** - * Replace {{run.xxx}} and {{global.xxx}} placeholders in a string with values from the data objects. - * This is done BEFORE parsing to allow dynamic values in scripts. - * - * @param line - The line to interpolate - * @param localValues - Values for {{run.xxx}} placeholders (e.g., {{run.email}}, {{run.extractedOtp}}) - * @param globalValues - Values for {{global.xxx}} placeholders (e.g., {{global.email}}) - */ -function interpolatePlaceholders(line, localValues, globalValues) { - let result = line; - // Replace {{run.xxx}} placeholders - if (localValues) { - result = result.replace(/\{\{run\.(\w+)\}\}/g, (match) => { - if (match in localValues) { - return escapeForStringLiteral(localValues[match]); - } - return match; // Keep original if key not found - }); - } - // Replace {{global.xxx}} placeholders - if (globalValues) { - result = result.replace(/\{\{global\.(\w+)\}\}/g, (match) => { - if (match in globalValues) { - return escapeForStringLiteral(globalValues[match]); - } - return match; // Keep original if key not found - }); - } - return result; -} -// ============================================================================= -// GETTER RESULT LOGGING -// ============================================================================= -/** - * Format a value for logging (handles objects, arrays, strings, etc.) - */ -function formatResultForLog(value) { - if (value === null) - return "null"; - if (value === undefined) - return "undefined"; - if (typeof value === "string") - return `"${value}"`; - if (typeof value === "number" || typeof value === "boolean") - return String(value); - try { - return JSON.stringify(value, null, 2); - } - catch { - return String(value); - } -} -/** - * Log the result of a getter method call. - */ -function logGetterResult(methodPath, result) { - logger_1.logger.debug(`[SecureScriptRunner] ${methodPath} → ${formatResultForLog(result)}`); -} -/** - * Safely execute a user-supplied Playwright script. - * - * The script is parsed as an AST and validated to only contain allowed - * Playwright method chains. User code is NEVER evaluated directly. - * - * @example - * await runSecureScript({ - * page, - * script: 'page.getByRole("button", { name: "Save" }).click()', - * }); - * - * @example - * // Multi-line scripts (each line is executed in order) - * await runSecureScript({ - * page, - * script: ` - * page.getByLabel("Email").fill("test@example.com") - * page.getByLabel("Password").fill("password123") - * page.getByRole("button", { name: "Submit" }).click() - * `, - * }); - */ -async function runSecureScript({ page: pageInput, script, localValues, globalValues, expect: expectFn, }) { - // Resolve to the currently-active page at script start. Scripts are - // short-lived, so we don't re-resolve per-line; if the script itself opens - // a tab, the auto-switch happens for subsequent steps, not within the script. - const page = (0, index_1.resolvePage)(pageInput); - // Variable storage for the script context - const variables = new Map(); - // Track the last result for return value - let lastResult = undefined; - // Split script into lines, strip comments, and filter out empty lines - const lines = script - .split("\n") - .map((line) => line.trim()) - .filter((line) => line && !line.startsWith("//") && !line.startsWith("#")) - .map((line) => stripInlineComments(line)) // Strip inline comments - .filter((line) => line); // Filter out lines that became empty after stripping - if (lines.length === 0) { - throw new Error("[SecureScriptRunner] Script is empty"); - } - for (const rawLine of lines) { - // Interpolate placeholders ({{run.xxx}} and {{global.xxx}}) - const line = interpolatePlaceholders(rawLine, localValues, globalValues); - // Remove trailing semicolons (optional in our DSL) - const cleanLine = line.replace(/;$/, "").trim(); - // Parse as a single JS statement (supporting variable declarations and await) - let ast; - try { - // Use sourceType: 'module' to allow top-level await - ast = (0, acorn_1.parse)(cleanLine, { - ecmaVersion: "latest", - sourceType: "module", - }); - } - catch (parseError) { - throw new Error(`[SecureScriptRunner] Failed to parse line: "${cleanLine}"\nParse error: ${parseError.message}`); - } - assert(ast.type === "Program", "Invalid program"); - assert(ast.body.length === 1, "Only one statement per line is allowed"); - const stmt = ast.body[0]; - // Handle variable declarations: const x = await fetch(...) or const y = await res.json() - if (stmt.type === "VariableDeclaration") { - const varDecl = stmt; - assert(varDecl.declarations.length === 1, "Only one variable per declaration"); - assert(varDecl.kind === "const" || varDecl.kind === "let", "Only const/let declarations allowed"); - const declarator = varDecl.declarations[0]; - assert(declarator.id.type === "Identifier", "Variable name must be identifier"); - const varName = declarator.id.name; - // Validate variable name (no reserved names) - assert(!RESERVED_VARIABLE_NAMES.has(varName), `Cannot use reserved name: ${varName}`); - assert(declarator.init !== null, "Variable must have initializer"); - // Handle await expression in the initializer - let initExpr = declarator.init; - if (initExpr.type === "AwaitExpression") { - initExpr = initExpr.argument; - } - // Check if the initializer is a literal value (string, number, etc.) - // This allows: const url = "{{run.url}}" or const count = 5 - if (isLiteralNode(initExpr)) { - const literalValue = evalSafeLiteral(initExpr); - variables.set(varName, literalValue); - lastResult = literalValue; - continue; - } - // Try computed expression (new URL(...), string concat, etc.) - const computedExpr = parseSafeExpression(initExpr, variables); - if (computedExpr) { - const computedValue = evalSafeExpression(computedExpr, variables); - variables.set(varName, computedValue); - lastResult = computedValue; - continue; - } - // Parse the initializer expression (must be a function call) - const parsedInit = parseAllowedChain(initExpr, variables); - // Execute the initializer and store result - const result = await executeChain(parsedInit, page, variables, expectFn); - variables.set(varName, result); - lastResult = result; - continue; - } - assert(stmt.type === "ExpressionStatement", "Only expression statements or variable declarations are allowed"); - // Handle await expression at the statement level - let exprNode = stmt.expression; - if (exprNode.type === "AwaitExpression") { - exprNode = exprNode.argument; - } - const parsed = parseAllowedChain(exprNode, variables); - lastResult = await executeChain(parsed, page, variables, expectFn); - } - return lastResult; -} -/** - * Execute a parsed chain and return the result. - */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -async function executeChain(parsed, page, variables, expectFn) { - switch (parsed.type) { - case "expect": { - // Handle expect() assertion - assert(expectFn !== undefined, "expect() assertions require passing the 'expect' function to runSecureScript"); - // Build the locator from the steps - let locator = page; - for (const { method, args } of parsed.locatorSteps) { - validateMethodArgs(method, args); - locator = locator[method](...args); - } - // Call expect(locator).assertionMethod(args) or expect(locator).not.assertionMethod(args) - let expectation = expectFn(locator); - if (parsed.negated) { - expectation = expectation.not; - } - const assertion = expectation[parsed.assertionMethod](...parsed.assertionArgs); - // Await if it's a promise (most assertions are async) - if (assertion instanceof Promise) { - await assertion; - } - return undefined; - } - case "expectValue": { - // Handle expect() with a variable value: expect(data.url).toBe(...) - assert(expectFn !== undefined, "expect() assertions require passing the 'expect' function to runSecureScript"); - // Get the variable value - const varValue = variables.get(parsed.variableName); - assert(varValue !== undefined, `Variable "${parsed.variableName}" is not defined`); - // Navigate the property path - let value = varValue; - for (const prop of parsed.propertyPath) { - assert(value !== null && value !== undefined, `Cannot read property "${prop}" of ${value}`); - value = value[prop]; - } - // Call expect(value).assertionMethod(args) or expect(value).not.assertionMethod(args) - let expectation = expectFn(value); - if (parsed.negated) { - expectation = expectation.not; - } - const assertion = expectation[parsed.assertionMethod](...parsed.assertionArgs); - // Await if it's a promise - if (assertion instanceof Promise) { - await assertion; - } - return undefined; - } - case "expectLiteral": { - // Handle expect() with a literal value: expect("string").toBe(...) - assert(expectFn !== undefined, "expect() assertions require passing the 'expect' function to runSecureScript"); - // Call expect(literalValue).assertionMethod(args) or expect(literalValue).not.assertionMethod(args) - let expectation = expectFn(parsed.literalValue); - if (parsed.negated) { - expectation = expectation.not; - } - const assertion = expectation[parsed.assertionMethod](...parsed.assertionArgs); - // Await if it's a promise - if (assertion instanceof Promise) { - await assertion; - } - return undefined; - } - case "pageMethod": { - // Handle page-level methods like goto, reload, etc. - validateMethodArgs(parsed.method, parsed.args); - const result = page[parsed.method](...parsed.args); - const resolvedResult = result instanceof Promise ? await result : result; - // Auto-log getter method results - if (GETTER_METHODS.has(parsed.method)) { - logGetterResult(`page.${parsed.method}()`, resolvedResult); - } - return resolvedResult; - } - case "keyboard": { - // Handle page.keyboard.xxx() methods - validateMethodArgs(parsed.method, parsed.args); - const result = page.keyboard[parsed.method](...parsed.args); - if (result instanceof Promise) { - return await result; - } - return result; - } - case "mouse": { - // Handle page.mouse.xxx() methods - validateMethodArgs(parsed.method, parsed.args); - const result = page.mouse[parsed.method](...parsed.args); - if (result instanceof Promise) { - return await result; - } - return result; - } - case "context": { - // Handle context.xxx() methods (executed as page.context().xxx()) - validateMethodArgs(parsed.method, parsed.args); - const context = page.context(); - const result = context[parsed.method](...parsed.args); - const resolvedResult = result instanceof Promise ? await result : result; - // Auto-log getter method results - if (GETTER_METHODS.has(parsed.method)) { - logGetterResult(`context.${parsed.method}()`, resolvedResult); - } - return resolvedResult; - } - case "browser": { - // Handle browser.xxx() methods (executed as page.context().browser()?.xxx()) - validateMethodArgs(parsed.method, parsed.args); - const browser = page.context().browser(); - assert(browser !== null, "Browser is not available"); - const result = browser[parsed.method](...parsed.args); - const resolvedResult = result instanceof Promise ? await result : result; - // Auto-log getter method results - if (GETTER_METHODS.has(parsed.method)) { - logGetterResult(`browser.${parsed.method}()`, resolvedResult); - } - return resolvedResult; - } - case "console": { - // Handle console.xxx() methods (log, warn, error, info, debug) - const consoleMethod = console[parsed.method]; - consoleMethod(...parsed.args); - return undefined; - } - case "fetch": { - // Handle fetch() calls - const fetchOptions = {}; - if (parsed.options?.method) { - fetchOptions.method = parsed.options.method; - } - if (parsed.options?.headers) { - fetchOptions.headers = parsed.options.headers; - } - if (parsed.options?.body) { - fetchOptions.body = - typeof parsed.options.body === "string" - ? parsed.options.body - : JSON.stringify(parsed.options.body); - } - // DNS rebinding protection: verify resolved IP is not blocked - await validateFetchUrlResolution(parsed.url); - const response = await fetch(parsed.url, fetchOptions); - logger_1.logger.debug(`[SecureScriptRunner] fetch(${parsed.url}) → ${response.status}`); - return response; - } - case "responseMethod": { - // Handle response method calls (res.json(), res.text()) - const response = variables.get(parsed.variableName); - assert(response instanceof Response, `Variable "${parsed.variableName}" is not a Response object`); - const result = await response[parsed.method](...parsed.args); - logger_1.logger.debug(`[SecureScriptRunner] ${parsed.variableName}.${parsed.method}() completed`); - return result; - } - case "variableDeclaration": { - // This case shouldn't be reached since variable declarations are handled earlier - // But include for completeness - const result = await executeChain(parsed.value, page, variables, expectFn); - return result; - } - case "locator": { - // Handle locator chain (page.getByRole().click()) - let cur = page; - const lastStep = parsed.steps[parsed.steps.length - 1]; - for (const { method, args } of parsed.steps) { - validateMethodArgs(method, args); - const result = cur[method](...args); - if (result instanceof Promise) { - cur = await result; - } - else { - cur = result; - } - } - // Auto-log getter method results (last method in chain) - if (lastStep && GETTER_METHODS.has(lastStep.method)) { - const chainPath = parsed.steps.map((s) => `${s.method}()`).join("."); - logGetterResult(`page.${chainPath}`, cur); - } - return cur; - } - default: { - // Exhaustive check - should never reach here - const _exhaustive = parsed; - throw new Error(`Unknown chain type: ${_exhaustive.type}`); - } - } -} -/* eslint-enable @typescript-eslint/no-explicit-any */ -/** - * Validate a script without executing it. - * Useful for pre-validation before saving scripts. - * - * @returns true if valid, throws Error if invalid - */ -function validateScript(script) { - // Track declared variables for validation - const declaredVariables = new Map(); - const lines = script - .split("\n") - .map((line) => line.trim()) - .filter((line) => line && !line.startsWith("//") && !line.startsWith("#")) - .map((line) => stripInlineComments(line)) // Strip inline comments - .filter((line) => line); // Filter out lines that became empty after stripping - if (lines.length === 0) { - throw new Error("[SecureScriptRunner] Script is empty"); - } - for (const line of lines) { - const cleanLine = line.replace(/;$/, "").trim(); - // Note: We can't interpolate placeholders during validation - // because we don't have the data. We'll validate the structure only. - // Replace placeholders with a dummy value for parsing. - // The placeholder is already inside quotes, so we just replace the {{...}} part. - const lineForParsing = cleanLine - .replace(/\{\{run\.\w+\}\}/g, "__PLACEHOLDER__") - .replace(/\{\{global\.\w+\}\}/g, "__PLACEHOLDER__"); - let ast; - try { - // Use sourceType: 'module' to allow top-level await - ast = (0, acorn_1.parse)(lineForParsing, { - ecmaVersion: "latest", - sourceType: "module", - }); - } - catch (parseError) { - throw new Error(`[SecureScriptRunner] Failed to parse line: "${cleanLine}"\nParse error: ${parseError.message}`); - } - assert(ast.type === "Program", "Invalid program"); - assert(ast.body.length === 1, "Only one statement per line is allowed"); - const stmt = ast.body[0]; - // Handle variable declarations - if (stmt.type === "VariableDeclaration") { - const varDecl = stmt; - assert(varDecl.declarations.length === 1, "Only one variable per declaration"); - assert(varDecl.kind === "const" || varDecl.kind === "let", "Only const/let declarations allowed"); - const declarator = varDecl.declarations[0]; - assert(declarator.id.type === "Identifier", "Variable name must be identifier"); - const varName = declarator.id.name; - // Validate variable name (no reserved names) - assert(!RESERVED_VARIABLE_NAMES.has(varName), `Cannot use reserved name: ${varName}`); - assert(declarator.init !== null, "Variable must have initializer"); - // Handle await expression in the initializer - let initExpr = declarator.init; - if (initExpr.type === "AwaitExpression") { - initExpr = initExpr.argument; - } - // Check if the initializer is a literal value - if (isLiteralNode(initExpr)) { - // Validate that it's a safe literal (will throw if not) - evalSafeLiteral(initExpr); - declaredVariables.set(varName, "__PLACEHOLDER__"); - continue; - } - // Try computed expression (validates structure without executing) - const computedExpr = parseSafeExpression(initExpr, declaredVariables); - if (computedExpr) { - declaredVariables.set(varName, "__COMPUTED_PLACEHOLDER__"); - continue; - } - // Parse the initializer expression (this will throw if invalid) - parseAllowedChain(initExpr, declaredVariables); - // Mark variable as declared (with placeholder value for validation) - declaredVariables.set(varName, "__PLACEHOLDER__"); - continue; - } - assert(stmt.type === "ExpressionStatement", "Only expression statements or variable declarations are allowed"); - // Handle await expression at the statement level - let exprNode = stmt.expression; - if (exprNode.type === "AwaitExpression") { - exprNode = exprNode.argument; - } - // This will throw if the chain is invalid - parseAllowedChain(exprNode, declaredVariables); - } - return true; -} diff --git a/dist/utils/tab-manager.d.ts b/dist/utils/tab-manager.d.ts deleted file mode 100644 index 54680da..0000000 --- a/dist/utils/tab-manager.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Page } from "@playwright/test"; -export type TabTarget = "main" | "latest" | number; -export type TabManager = { - active: () => Page; - pages: () => Page[]; - switchTo: (target: TabTarget) => Promise; -}; -export declare const createTabManager: (initialPage: Page) => TabManager; diff --git a/dist/utils/tab-manager.js b/dist/utils/tab-manager.js deleted file mode 100644 index ac13000..0000000 --- a/dist/utils/tab-manager.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.createTabManager = void 0; -const createTabManager = (initialPage) => { - const pages = [initialPage]; - let activeIndex = 0; - const context = initialPage.context(); - context.on("page", (newPage) => { - if (!pages.includes(newPage)) { - pages.push(newPage); - } - // Auto-switch active focus to any newly opened tab so subsequent - // snapshots/actions target it without explicit switching. - activeIndex = pages.indexOf(newPage); - newPage.on("close", () => { - const idx = pages.indexOf(newPage); - if (idx === -1) - return; - pages.splice(idx, 1); - if (activeIndex === idx) { - activeIndex = Math.max(0, pages.length - 1); - } - else if (activeIndex > idx) { - activeIndex -= 1; - } - }); - }); - return { - active: () => pages[activeIndex], - pages: () => [...pages], - switchTo: async (target) => { - let idx; - if (target === "main") - idx = 0; - else if (target === "latest") - idx = pages.length - 1; - else - idx = target; - if (idx < 0 || idx >= pages.length) { - throw new Error(`switchToTab: invalid target ${target}; ${pages.length} tab(s) open.`); - } - activeIndex = idx; - return pages[idx]; - }, - }; -}; -exports.createTabManager = createTabManager;