diff --git a/.changeset/README.md b/.changeset/README.md
new file mode 100644
index 0000000..caef05b
--- /dev/null
+++ b/.changeset/README.md
@@ -0,0 +1,12 @@
+# Changesets
+
+This repo uses [Changesets](https://github.com/changesets/changesets) to version and publish
+**`@wdio/browserstack-service`** on BrowserStack's own cadence (independent of WebdriverIO's
+release schedule).
+
+- Add a changeset for any user-facing change: `npm run changeset` (pick patch/minor/major).
+- On merge to `main` (the v9 line) or `v8` (the v8 line), the Release workflow opens a
+ "Version Packages" PR; merging that PR publishes to npm via OIDC trusted publishing.
+- The gRPC/protobuf core **`@browserstack/wdio-browserstack-service`** is in `ignore` (see
+ `config.json`) — it is versioned and published separately by the SDK team and is never
+ touched by this pipeline.
diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 0000000..558465d
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+ "changelog": "@changesets/cli/changelog",
+ "commit": false,
+ "fixed": [],
+ "linked": [],
+ "access": "public",
+ "baseBranch": "main",
+ "updateInternalDependencies": "patch",
+ "ignore": ["@browserstack/wdio-browserstack-service"]
+}
diff --git a/.changeset/take-over-publishing.md b/.changeset/take-over-publishing.md
new file mode 100644
index 0000000..a7b8de6
--- /dev/null
+++ b/.changeset/take-over-publishing.md
@@ -0,0 +1,8 @@
+---
+"@wdio/browserstack-service": minor
+---
+
+BrowserStack now publishes `@wdio/browserstack-service` from its own repository
+(`browserstack/wdio-browserstack-service`) on an independent release cadence, using npm OIDC
+trusted publishing. No change for end users — same package name and the same
+`services: ['browserstack']` configuration continue to work unchanged.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..5e3763e
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,38 @@
+name: CI
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+ - v8
+
+permissions:
+ contents: read
+
+jobs:
+ build-test:
+ name: Build & test (node ${{ matrix.node-version }})
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ node-version: ['18.20', '20', '22']
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: 'npm'
+
+ - name: Install
+ run: npm ci
+
+ - name: Build (core + service)
+ run: npm run build
+
+ - name: Test
+ run: npm test
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..bdff549
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,69 @@
+name: Release
+
+# Publishes @wdio/browserstack-service to npm via OIDC Trusted Publishing
+# (no long-lived NPM_TOKEN). One-time setup by an @wdio npm org admin on npmjs.com:
+# @wdio/browserstack-service -> Settings -> Trusted Publisher -> GitHub Actions
+# Organization/user: browserstack
+# Repository: wdio-browserstack-service
+# Workflow filename: release.yml
+# Environment: (leave empty)
+# Requires: PUBLIC repo (for provenance), npm >= 11.5.1, Node >= 22.14.0.
+#
+# The gRPC core (@browserstack/wdio-browserstack-service) is in .changeset ignore,
+# so this workflow never versions or publishes it.
+
+on:
+ push:
+ branches:
+ - main # v9 line -> dist-tag "latest"
+ - v8 # v8 line -> dist-tag "v8" (from publishConfig.tag on the v8 branch)
+
+# Never run main and v8 releases on top of each other.
+concurrency: release-${{ github.ref }}
+
+permissions:
+ contents: write # commit the "Version Packages" PR + create git tags
+ pull-requests: write # open the "Version Packages" PR
+ id-token: write # OIDC for npm trusted publishing + provenance
+
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Changesets needs full history/tags
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22 # resolves to >= 22.14 on the runner (OIDC floor)
+ registry-url: 'https://registry.npmjs.org'
+ cache: 'npm'
+
+ # Trusted Publishing needs npm >= 11.5.1. Pin to the 11.x line so a future
+ # npm major can never silently change publish behaviour.
+ - name: Upgrade npm to an OIDC-capable version
+ run: npm install -g npm@11
+
+ - name: Install
+ run: npm ci
+
+ - name: Build
+ run: npm run build
+
+ - name: Test
+ run: npm test
+
+ - name: Create Release PR or publish to npm
+ uses: changesets/action@v1
+ with:
+ version: npm run version # changeset version (opens the "Version Packages" PR)
+ publish: npm run release # changeset publish (honors publishConfig.tag per branch)
+ createGithubReleases: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ # No NPM_TOKEN: auth is OIDC via id-token: write above.
+ NPM_CONFIG_PROVENANCE: 'true'
diff --git a/.gitignore b/.gitignore
index 7feec19..01893f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,24 @@
node_modules
+
+# build outputs
dist
generated
+build
+src/generated
+packages/*/dist
+packages/*/build
+packages/*/src/generated
+
+# test/coverage
+coverage
+packages/*/coverage
+
+# packed tarballs & logs
+*.tgz
+*.log
+logs
+
+# local/editor
+.DS_Store
+.env
+.env.*
diff --git a/README.md b/README.md
index c450c7d..c1a0a18 100644
--- a/README.md
+++ b/README.md
@@ -1,119 +1,51 @@
-# @browserstack/wdio-browserstack-service
+# wdio-browserstack-service
-
-
+Monorepo for the BrowserStack WebdriverIO integration, maintained by BrowserStack.
-Core SDK for BrowserStack integration used by the WebdriverIO BrowserStack Service.
-For user configuration and service options, see the official service README:
-[https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-browserstack-service/README.md](https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-browserstack-service/README.md)
+| Package | npm | What it is |
+|---|---|---|
+| [`packages/browserstack-service`](./packages/browserstack-service) | [`@wdio/browserstack-service`](https://www.npmjs.com/package/@wdio/browserstack-service) | The WebdriverIO service users add via `services: ['browserstack']`. |
+| [`packages/core`](./packages/core) | [`@browserstack/wdio-browserstack-service`](https://www.npmjs.com/package/@browserstack/wdio-browserstack-service) | gRPC/protobuf core SDK consumed by the service. |
-## Table of Contents
-1. [Overview](#overview)
-2. [Code Generation](#code-generation)
-3. [Development](#development)
-4. [Contributing](#contributing)
-5. [License](#license)
+## Usage (for end users)
-## Overview
-This package provides the TypeScript-based gRPC client and Protobuf definitions
-used internally by the `@wdio/browserstack-service` plugin for WebdriverIO.
-It includes:
-- Generated TypeScript types and clients from Protobuf definitions.
-- Message factory constructors for backward compatibility.
+Nothing changes — install the service and add it to your WebdriverIO config:
-## Installation
-This module is included as a dependency of the `@wdio/browserstack-service` package.
-Users should install and configure the service as documented in the linked README above.
-
-## Setup & Configuration
-Add the service to your WebdriverIO configuration (`wdio.conf.js`):
-
-```
-export BROWSERSTACK_USERNAME=your_username
-export BROWSERSTACK_ACCESS_KEY=your_access_key
+```sh
+npm i -D @wdio/browserstack-service
```
-## Usage
-Import and use the gRPC client and message constructors:
-```ts
-import { SDKClient, StartBinSessionRequestConstructor } from '@browserstack/wdio-browserstack-service';
-import path from 'path';
-import process from 'process';
-import { CLIUtils } from '@browserstack/cli-utils'; // example import, adjust if needed
-import { version as packageVersion } from './package.json'; // adjust to your setup
-
-// Initialize the client (uses default insecure credentials unless overridden)
-const client = new SDKClient('grpc.browserstack.com:443');
-
-// Collect framework details
-const automationFrameworkDetail = CLIUtils.getAutomationFrameworkDetail();
-const testFrameworkDetail = CLIUtils.getTestFrameworkDetail();
-
-const frameworkVersions = {
- ...automationFrameworkDetail.version,
- ...testFrameworkDetail.version
-};
-
-// Build StartBinSessionRequest
-const startReq = StartBinSessionRequestConstructor.create({
- binSessionId: 'your-session-id', // replace with actual session id
- sdkLanguage: CLIUtils.getSdkLanguage(),
- sdkVersion: packageVersion,
- pathProject: process.cwd(),
- pathConfig: path.resolve(process.cwd(), 'browserstack.yml'),
- cliArgs: process.argv.slice(2),
- frameworks: [automationFrameworkDetail.name, testFrameworkDetail.name],
- frameworkVersions,
- language: CLIUtils.getSdkLanguage(),
- testFramework: testFrameworkDetail.name,
- wdioConfig: {}, // provide your WDIO config if applicable
-});
-
-// Start a session
-client.startBinSession(startReq).then(response => {
- console.log('Started session:', response.binSessionId);
-}).catch(err => {
- console.error('Failed to start session:', err);
-});
+```js
+// wdio.conf.js
+export const config = {
+ services: ['browserstack'],
+ // ...
+}
```
-## Code Generation
-This project uses [Buf](https://docs.buf.build/) and `ts-proto` to
-generate TypeScript code from Protobuf definitions.
-
-### Prerequisites
-- [Buf CLI](https://docs.buf.build/installation)
-- Node.js ≥16
+See the [service README](./packages/browserstack-service/README.md) for full configuration.
-### Generate & Build
-```bash
-# Clean previously generated files
-npm run clean
+## Development
-# Generate from .proto files
-npm run generate
+This is an npm workspace.
-# Compile to JS and declaration files
-npm run build
+```sh
+npm ci # install all packages
+npm run build # build core then service
+npm test # run the service test suite
```
-Generated files appear under `dist/` and should be published to npm.
+- `npm run build:core` / `npm run build:service` build a single package.
+- The service is bundled with esbuild (deps kept external) and ships TypeScript declarations from `tsc`.
-## Development
-Clone the repository and install dependencies:
-```bash
-git clone https://github.com/browserstack/wdio-browserstack-service.git
-cd wdio-browserstack-service
-npm install
-```
+## Releases
-Run generation and build:
-```bash
-npm run build
-```
+`@wdio/browserstack-service` is versioned and published with [Changesets](https://github.com/changesets/changesets)
+on BrowserStack's own cadence (independent of WebdriverIO core's release schedule):
-## Contributing
-Contributions are welcome! Please open issues or pull requests in the [GitHub repository](https://github.com/browserstack/wdio-browserstack-service).
+- `main` → `latest` dist-tag (v9 line)
+- `v8` branch → `v8` dist-tag (v8 line)
-## License
-MIT © BrowserStack
\ No newline at end of file
+Publishing uses **npm OIDC trusted publishing** (no long-lived token; provenance-signed). The gRPC core
+`@browserstack/wdio-browserstack-service` is released separately by the SDK team and is excluded from the
+Changesets pipeline (see [`.changeset/config.json`](./.changeset/config.json)).
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
new file mode 100644
index 0000000..5b691b4
--- /dev/null
+++ b/docs/ARCHITECTURE.md
@@ -0,0 +1,527 @@
+# Architecture: extracting `@wdio/browserstack-service` from the WebdriverIO monorepo
+
+> Deep-dive companion to [`EXTRACTION.md`](../EXTRACTION.md) (the cutover checklist) and
+> [`TSC-PROPOSAL.md`](./TSC-PROPOSAL.md) (the governance ask).
+> This document explains **how things work today**, **what changes**, **why we chose this
+> approach over the alternatives**, and **how every form of communication works after the move**.
+
+---
+
+## 0. TL;DR
+
+We are moving the **source code and release pipeline** of `@wdio/browserstack-service` out of the
+`webdriverio/webdriverio` monorepo into a BrowserStack-owned repository, **while keeping the package
+published under the exact same `@wdio/browserstack-service` name and `@wdio` npm scope**.
+
+- **For users: nothing changes.** Same `npm i @wdio/browserstack-service`, same
+ `services: ['browserstack']`, same docs.
+- **For BrowserStack: independent releases.** No longer gated by WebdriverIO's lockstep,
+ TSC-triggered release train.
+- **The model is proven.** WebdriverIO already does this for `@wdio/visual-service` and
+ `@wdio/electron-service`. We validated it end-to-end (standalone build + a real BrowserStack
+ session that loaded the independently-built package via `services: ['browserstack']`).
+
+```mermaid
+flowchart LR
+ subgraph TODAY["TODAY — inside the monorepo"]
+ M["webdriverio/webdriverio
(39 packages, Lerna lockstep)"]
+ M --> P1["@wdio/browserstack-service
released ONLY when the TSC
publishes the whole train"]
+ end
+ subgraph TARGET["TARGET — own repo, same npm name"]
+ R["browserstack/wdio-browserstack-service
(Changesets, BrowserStack-controlled)"]
+ R --> P2["@wdio/browserstack-service
same name + scope,
released on BrowserStack's cadence"]
+ end
+ TODAY -->|"extract, keep the name"| TARGET
+ style TARGET fill:#e6ffe6
+ style TODAY fill:#fff0f0
+```
+
+---
+
+## 1. What the package actually is
+
+`@wdio/browserstack-service` is the official WebdriverIO integration for BrowserStack. It is a
+**WebdriverIO "service"** — a plugin that hooks into the test lifecycle. It bundles a large feature
+set: Automate session management, the BrowserStack Local tunnel, Test Observability / TestHub,
+Accessibility, AI self-healing, and Percy visual testing.
+
+- npm: `@wdio/browserstack-service` — latest `9.27.2`, ~1M downloads/month, MIT, **ESM-only**, Node `>=18.20.0`.
+- Two entrypoints: `.` (the service + launcher) and `./cleanup` (a standalone cleanup process).
+- Today it lives at `packages/wdio-browserstack-service` in the monorepo. Its npm owners are
+ WebdriverIO maintainers (not BrowserStack accounts) — BrowserStack contributes the logic and the
+ `@browserstack/*` SDKs it depends on.
+
+---
+
+## 2. How things work TODAY (current architecture)
+
+### 2.1 Where the code lives — the monorepo
+
+```mermaid
+flowchart TD
+ subgraph MONO["webdriverio/webdriverio (pnpm workspace + Lerna)"]
+ direction TB
+ CORE["Core packages
webdriverio · webdriver · @wdio/cli
@wdio/utils · @wdio/types · @wdio/reporter · @wdio/logger"]
+ SVC["Service packages
@wdio/sauce-service · @wdio/browserstack-service · …"]
+ COMPILER["infra/compiler (@wdio/compiler)
shared esbuild build"]
+ LERNA["lerna.json → version: 9.27.2 (FIXED mode)"]
+ end
+ CORE -. "workspace:* (symlinked)" .-> SVC
+ COMPILER --> SVC
+ COMPILER --> CORE
+ LERNA --> CORE
+ LERNA --> SVC
+```
+
+Key facts (all verified against the repo):
+- **pnpm workspace + Lerna**, `packages/*`. Internal deps use the `workspace:*` protocol (symlinked
+ locally; pinned to exact versions at publish time).
+- **Lerna FIXED mode** — `lerna.json` has `"version": "9.27.2"` (not `"independent"`). Every package
+ shares one version, bumped together.
+- A shared **`@wdio/compiler`** (esbuild) builds every package; there is **no per-package build script**.
+
+### 2.2 The build pipeline today
+
+```mermaid
+flowchart LR
+ SRC["packages/wdio-browserstack-service/src/*.ts"] --> ESB["@wdio/compiler (esbuild)
bundle each exports entry
deps marked EXTERNAL"]
+ ESB --> JS["build/index.js
build/cleanup.js"]
+ SRC --> TSC["tsc --emitDeclarationOnly"]
+ TSC --> DTS["build/*.d.ts"]
+ JS --> PKG["published tarball"]
+ DTS --> PKG
+```
+
+The compiler bundles only the package's own `src` (every dependency stays external) and `tsc`
+emits the `.d.ts` files. This is driven centrally from the monorepo root.
+
+### 2.3 The release pipeline today — lockstep, TSC-gated
+
+```mermaid
+sequenceDiagram
+ participant Dev as BrowserStack engineer
+ participant PR as webdriverio/webdriverio PR
+ participant TSC as TSC member
+ participant GHA as "Manual NPM Publish" workflow
+ participant NPM as npm registry
+
+ Dev->>PR: open PR with a fix/feature
+ PR->>TSC: review + merge (lands on main)
+ Note over Dev,TSC: fix now sits on main, UNRELEASED…
+ TSC->>GHA: manually trigger workflow_dispatch
+ GHA->>GHA: authorize.yml — is actor in
technical-steering-committee team?
+ GHA->>NPM: pnpm lerna publish (one shared version)
+ NPM-->>NPM: bumps ALL changed @wdio/* together (e.g. 9.27.2 → 9.27.3)
+```
+
+- The publish workflow is **`workflow_dispatch` only** and runs an `authorize` job that checks
+ **`technical-steering-committee`** GitHub-team membership. BrowserStack cannot trigger it.
+- One `lerna publish` bumps the **single shared version** for all changed packages.
+- So a BrowserStack-only fix waits for the next TSC-run train, and ships under whatever the global
+ version becomes. **This is the core pain.**
+
+### 2.4 How users consume it (and the resolution mechanism)
+
+A user writes this and never references a package path:
+
+```js
+// wdio.conf.js
+export const config = {
+ services: [['browserstack', { /* options */ }]]
+}
+```
+
+WebdriverIO turns the shorthand `'browserstack'` into a real package via `initializePlugin()` in
+`@wdio/utils`. **This is the single most important mechanism for "nothing changes for users":**
+
+```mermaid
+flowchart TD
+ A["services: browserstack (shorthand)"] --> B{"name starts with '@'
or is absolute path?"}
+ B -- yes --> Z["import that string directly"]
+ B -- no --> C["try import: @wdio/browserstack-service"]
+ C -- found --> OK["✅ loaded"]
+ C -- not found --> D["try import: wdio-browserstack-service"]
+ D -- found --> OK
+ D -- not found --> ERR["❌ throw 'make sure you have it installed'"]
+ style C fill:#e6ffe6
+ style OK fill:#e6ffe6
+```
+
+- It **`import()`s whatever is installed** — there is **no runtime auto-install**.
+- The scoped name `@wdio/browserstack-service` is tried **first**.
+- ⇒ As long as we keep publishing under `@wdio/browserstack-service`, the shorthand keeps resolving
+ with **zero config or install changes**. (npm scopes can't be moved to another scope — which is
+ exactly why we keep `@wdio`.)
+
+### 2.5 Runtime communication today (three boundaries)
+
+At runtime the service talks across three boundaries. **None of these change after the move.**
+
+```mermaid
+flowchart LR
+ subgraph USER["User's machine / CI (the Node process)"]
+ CLI["@wdio/cli + @wdio/runner
(the test runner)"]
+ CORE["webdriverio / @wdio/logger / @wdio/reporter / @wdio/types
(installed once)"]
+ BS["@wdio/browserstack-service
(launcher + worker service)"]
+ LOCAL["browserstack-local tunnel"]
+ end
+ subgraph CLOUD["BrowserStack cloud"]
+ HUB["hub.browserstack.com
(WebDriver / Automate)"]
+ API["api.browserstack.com
session name, TestHub/Observability, funnel"]
+ GRPC["TCG / binSession (gRPC)
@browserstack/wdio-browserstack-service"]
+ PERCY["Percy"]
+ end
+
+ CLI -- "calls lifecycle hooks
(onPrepare, beforeSession, beforeTest, after, onComplete)" --> BS
+ BS -- "imports values/types
(SevereServiceError, logger, WDIOReporter)" --> CORE
+ BS -- "REST (undici/global fetch)" --> API
+ BS -- "gRPC" --> GRPC
+ BS -- "Percy SDKs" --> PERCY
+ BS -- "opens tunnel" --> LOCAL
+ LOCAL --> HUB
+ CORE -- "WebDriver commands" --> HUB
+```
+
+1. **Service ⇄ WebdriverIO core (in-process):** the runner (`@wdio/cli`/`@wdio/runner`) calls the
+ service's lifecycle hooks. The service imports a few **values** from core — `SevereServiceError`
+ from `webdriverio`, the default logger from `@wdio/logger`, `WDIOReporter` from `@wdio/reporter` —
+ plus types from `@wdio/types`.
+2. **Service ⇄ BrowserStack backend (network):** Automate via the WebDriver hub (driven by
+ `webdriverio` core), plus REST calls (session name, Test Observability/TestHub, funnel
+ instrumentation), gRPC (binSession via the `@browserstack/*` SDK), Percy, and the local tunnel.
+3. **Service ⇄ user config:** options passed in `services: [['browserstack', {…}]]`.
+
+### 2.6 Dependency graph today
+
+```mermaid
+flowchart TD
+ BS["@wdio/browserstack-service"]
+ subgraph INTERNAL["monorepo-internal (workspace:* → pinned at publish)"]
+ T["@wdio/types"]
+ R["@wdio/reporter"]
+ L["@wdio/logger"]
+ W["webdriverio"]
+ end
+ subgraph EXTERNAL["already external / BrowserStack-owned"]
+ BSDK["@browserstack/wdio-browserstack-service"]
+ AI["@browserstack/ai-sdk-node"]
+ PCY["@percy/*"]
+ OTH["undici · chalk · tar · glob · uuid · …"]
+ end
+ BS --> T & R & L & W
+ BS --> BSDK & AI & PCY & OTH
+ BS -. "peerDependency" .-> CLI["@wdio/cli"]
+ style INTERNAL fill:#fff0f0
+```
+
+The four `@wdio/*` / `webdriverio` deps are the only thing tying the package to the monorepo.
+
+---
+
+## 3. The problem
+
+```mermaid
+flowchart LR
+ A["BrowserStack ships often
(new features, fixes, platform support)"] --> C{"must wait for the
TSC release train"}
+ B["WebdriverIO core releases
on its own, slower cadence"] --> C
+ C --> D["fixes/features sit unreleased on main"]
+ C --> E["BrowserStack can't hotfix independently"]
+ C --> F["version number is dictated by the whole monorepo"]
+ style C fill:#fff0b3
+```
+
+The release cadence mismatch is the entire motivation. Everything else (build, deps) is incidental
+plumbing that exists only because the code lives in the monorepo.
+
+---
+
+## 4. What changes — and what explicitly does NOT
+
+| Dimension | Today | After the move | User-visible? |
+|---|---|---|---|
+| **Install name** | `@wdio/browserstack-service` | **identical** | No |
+| **`services: ['browserstack']`** | resolves to the package | **identical** | No |
+| **npm scope/owner** | `@wdio` org | **`@wdio` org (unchanged)** | No |
+| Source repo | `webdriverio/webdriverio` | `browserstack/wdio-browserstack-service` | No |
+| Build | shared `@wdio/compiler` | local esbuild (`scripts/build.mjs`) + `tsc` | No |
+| Versioning | Lerna fixed/lockstep | Changesets, independent | Only the version *number* line |
+| Release trigger | TSC `workflow_dispatch` | BrowserStack CI on merge | No |
+| `@wdio/*` core deps | `dependencies` (`workspace:*`) | **`peerDependencies` (`^9`)** + dev | No (dedupes) |
+
+The one change with real engineering weight is the dependency reclassification:
+
+```mermaid
+flowchart LR
+ subgraph BEFORE["BEFORE — regular deps, pinned"]
+ B1["@wdio/browserstack-service"] --> B2["webdriverio 9.27.2 (own copy)"]
+ end
+ subgraph AFTER["AFTER — peerDependencies"]
+ A1["@wdio/browserstack-service"] -. "peer ^9" .-> A2["webdriverio (the user's copy)"]
+ A3["@wdio/cli / webdriverio (user installs)"] --> A2
+ end
+ BEFORE -->|"avoids a duplicate webdriverio in node_modules"| AFTER
+ style AFTER fill:#e6ffe6
+```
+
+**Why this matters:** if `webdriverio`/`@wdio/logger`/`@wdio/reporter` were bundled as the service's
+own dependency, the user would end up with **two copies** in `node_modules`. That breaks shared
+singletons — `instanceof SevereServiceError` checks, the shared logger configuration, the reporter
+event bus. Making them **peerDependencies** forces the service to use the **same instances** the user
+already has installed. (We confirmed in the PoC that `webdriverio` deduped to a single copy.)
+
+---
+
+## 5. Options we considered, and why we chose this one
+
+```mermaid
+flowchart TD
+ START{"Move the service out,
keep users unaffected,
release independently"}
+ START --> A["A. Own repo,
KEEP @wdio name,
TSC delegates publish"]
+ START --> B["B. New scope
@browserstack/wdio-…
+ deprecate old"]
+ START --> C["C. Community name
wdio-browserstack-service
(unscoped)"]
+ START --> D["D. Stay in monorepo,
make Lerna independent"]
+
+ A --> AV["✅ users unaffected
✅ independent releases
⚠️ needs TSC consent (precedent exists)"]
+ B --> BV["✅ full independence
❌ breaks shorthand → users must edit config + reinstall"]
+ C --> CV["⚠️ resolves only if user swaps install
❌ @wdio/ wins resolution → not transparent"]
+ D --> DV["❌ still TSC-gated workflow → no cadence control"]
+
+ AV --> PICK["CHOSEN: A"]
+ style A fill:#e6ffe6
+ style PICK fill:#e6ffe6
+ style B fill:#fff0f0
+ style C fill:#fff0f0
+ style D fill:#fff0f0
+```
+
+The decision is forced by a chain of hard constraints:
+
+```mermaid
+flowchart LR
+ G1["Goal: users change NOTHING"] --> R1["⇒ keep publishing as @wdio/browserstack-service"]
+ R1 --> R2["npm rule: a scoped package
can't be transferred to another scope"]
+ R2 --> R3["⇒ must KEEP the @wdio scope"]
+ R3 --> R4["@wdio scope is owned by the WebdriverIO org"]
+ R4 --> R5["⇒ TSC must delegate publish rights
(OIDC trusted publishing / per-package access)"]
+ style R5 fill:#e6ffe6
+```
+
+| Option | Users unaffected? | Independent cadence? | TSC needed? | Verdict |
+|---|---|---|---|---|
+| **A — own repo, keep `@wdio`, delegated publish** | ✅ | ✅ | yes | **Chosen** |
+| B — new `@browserstack` scope + deprecate | ❌ (reinstall + config edit) | ✅ | no | Only if a one-time migration is acceptable |
+| C — community unscoped `wdio-…` | ❌ (loses to `@wdio` in resolution) | ✅ | no | Not transparent |
+| D — Lerna independent, stay in monorepo | ✅ | ❌ (still one TSC workflow) | yes | Doesn't solve the problem |
+
+**Why A and not B:** B is the classic "rename + `npm deprecate`" playbook (Babel, ESLint, Storybook
+addons). It works, but a new scope means `services: ['browserstack']` no longer resolves and every
+user must edit `wdio.conf` and reinstall — a direct violation of the "nothing changes" requirement.
+A keeps the identity and only moves the plumbing.
+
+**Why A is safe:** it is the **exact** model WebdriverIO already runs for
+[`@wdio/visual-service`](https://github.com/webdriverio/visual-testing) (own repo, Changesets,
+independent version line) and [`@wdio/electron-service`](https://github.com/webdriverio/desktop-mobile).
+Both publish under `@wdio` from repos outside the monorepo.
+
+---
+
+## 6. Target architecture
+
+```mermaid
+flowchart TD
+ subgraph BSREPO["browserstack/wdio-browserstack-service (public)"]
+ SRC2["src/*.ts"]
+ BUILD2["scripts/build.mjs (esbuild) + tsc"]
+ CS["Changesets (independent versioning)"]
+ CI["GitHub Actions: ci.yml + release.yml (OIDC)"]
+ end
+ subgraph NPMSCOPE["npm @wdio scope (owned by WebdriverIO org)"]
+ PKG2["@wdio/browserstack-service
(same name; trusted publisher = this repo)"]
+ end
+ subgraph USERSIDE["User project (unchanged)"]
+ WCONF["wdio.conf services: browserstack"]
+ NM["node_modules/@wdio/browserstack-service"]
+ end
+ SRC2 --> BUILD2 --> CI
+ CS --> CI
+ CI -->|"npm publish via OIDC"| PKG2
+ PKG2 -->|"npm install"| NM
+ WCONF -->|"initializePlugin resolves"| NM
+ style BSREPO fill:#e8f0ff
+ style NPMSCOPE fill:#fff7e6
+ style USERSIDE fill:#e6ffe6
+```
+
+- **Repo:** BrowserStack-owned, public (provenance requires a public source repo and an exact
+ `repository` URL match).
+- **Versioning:** Changesets, independent line; compatibility expressed via peer ranges, not version
+ parity.
+- **Publishing:** npm **Trusted Publishing (OIDC)** — configured once by an `@wdio` org admin to point
+ at this repo's `release.yml`. No long-lived npm token is shared with BrowserStack.
+
+---
+
+## 7. Communication model after the move (in depth)
+
+"Communication" happens at four distinct layers. **Layer 1 (runtime) is the one users care about,
+and it does not change at all.**
+
+### 7.1 Runtime communication — UNCHANGED
+
+The separately-published package integrates with WebdriverIO **identically** to today, because the
+contract is *the npm package name + the service interface + shared peer packages* — none of which
+depend on where the source lives.
+
+```mermaid
+sequenceDiagram
+ participant Conf as wdio.conf
+ participant Utils as "@wdio/utils initializePlugin"
+ participant NM as node_modules/@wdio/browserstack-service
+ participant Runner as "@wdio/cli / @wdio/runner"
+ participant Core as webdriverio + @wdio/logger (user's copy)
+ participant BS as BrowserStack cloud
+
+ Conf->>Utils: resolve 'browserstack'
+ Note over Utils,NM: same package name as always
+ Utils->>NM: import @wdio/browserstack-service
+ NM-->>Utils: { default: Service, launcher: Launcher }
+ Runner->>NM: onPrepare() → start Local tunnel, init Observability
+ NM->>BS: REST/gRPC/tunnel setup
+ Runner->>NM: beforeSession / beforeTest / afterTest / after
+ NM->>Core: use SevereServiceError, logger (SAME instances via peerDep)
+ NM->>BS: update session name, send results
+ Runner->>NM: onComplete() → stop tunnel, flush funnel
+```
+
+The **peerDependency** design is what makes "same instances" true: the service binds to the
+`webdriverio`/`@wdio/logger`/`@wdio/reporter`/`@wdio/types` the user already installed, so there is no
+duplicate-copy drift. This is communication **within one Node process** — repo location is irrelevant.
+
+### 7.2 Build-time / compatibility communication — a one-way dependency on published `@wdio/*`
+
+```mermaid
+flowchart LR
+ subgraph WDIO["webdriverio/webdriverio (publishes core)"]
+ CORE3["@wdio/types · @wdio/reporter · @wdio/logger · webdriverio"]
+ end
+ subgraph BSREPO3["browserstack/wdio-browserstack-service"]
+ DEV["devDependencies: ^9 (to build & test)"]
+ PEER["peerDependencies: ^9 (what users must have)"]
+ MATRIX["CI matrix: test against multiple webdriverio majors"]
+ end
+ CORE3 -->|"published to npm"| DEV
+ CORE3 -->|"published to npm"| PEER
+ CORE3 --> MATRIX
+```
+
+- The new repo consumes core packages **from npm** (as published by the monorepo) — a clean, one-way
+ dependency. There is no reverse dependency: the monorepo never needs the service to build.
+- **Compatibility is communicated through the peer range** (`^9.0.0`). When core ships a breaking
+ major, BrowserStack widens/bumps the peer range and proves it with a CI matrix. This replaces the
+ monorepo's implicit "everything is the same version" guarantee.
+
+### 7.3 Release / publish communication — the OIDC handshake
+
+Publishing under `@wdio` from a BrowserStack repo uses **OpenID Connect trusted publishing**. No
+secret is shared; the npm registry verifies the GitHub-signed identity against a per-package config.
+
+```mermaid
+sequenceDiagram
+ participant Merge as Merge to main (BrowserStack repo)
+ participant GHA as GitHub Actions (release.yml)
+ participant OIDC as GitHub OIDC provider
+ participant NPM as npm registry
+ participant Cfg as "@wdio/browserstack-service trusted-publisher config (set once by @wdio admin)"
+
+ Merge->>GHA: Changesets → version bump + build
+ GHA->>OIDC: request signed OIDC token (id-token: write)
+ OIDC-->>GHA: token { repo, workflow, ref }
+ GHA->>NPM: npm publish --provenance (presents OIDC token)
+ NPM->>Cfg: does token.repo/workflow match the configured trusted publisher?
+ Cfg-->>NPM: match ✅
+ NPM-->>GHA: published @wdio/browserstack-service@ (with provenance)
+```
+
+- **One-time setup (TSC/@wdio admin):** add a trusted publisher to the `@wdio/browserstack-service`
+ package pointing at `browserstack/wdio-browserstack-service` + `release.yml`. (Alternative: grant a
+ BrowserStack npm account per-package write access.)
+- **Ongoing (BrowserStack):** every merge can publish autonomously — no human in the loop, no shared
+ token, provenance attached.
+
+### 7.4 Organizational communication — who talks to whom, and when
+
+```mermaid
+flowchart TD
+ TSC["WebdriverIO TSC / @wdio org admin"]
+ BS2["BrowserStack maintainers"]
+ NPMORG["npm @wdio org (scope owner)"]
+ DOCS["webdriver.io docs + 3rd-party/services.json"]
+
+ BS2 -->|"1. proposal / RFC discussion (once)"| TSC
+ TSC -->|"2. configure trusted publisher (once)"| NPMORG
+ BS2 -->|"3. publish releases (ongoing, autonomous)"| NPMORG
+ BS2 -->|"4. notify on breaking/major changes"| TSC
+ BS2 -->|"5. keep docs entry current"| DOCS
+ TSC -->|"announce core breaking majors"| BS2
+```
+
+- **Once:** proposal + the trusted-publisher/access setup.
+- **Ongoing & autonomous:** BrowserStack publishes whenever it wants.
+- **Coordination only when needed:** core breaking majors (peer-range updates), docs changes, and
+ security contacts. Day-to-day, the two projects are decoupled.
+
+### 7.5 What happens on divergence / failure
+
+| Scenario | How it's handled |
+|---|---|
+| Core ships a breaking major (e.g. v10) | BrowserStack updates the peer range + CI matrix, releases a compatible version on its own schedule. |
+| A user pins an old service version | Works exactly as today — npm resolves the pinned version; the peer range guards compatibility. |
+| BrowserStack needs an urgent hotfix | Merge + autonomous publish in minutes — no TSC dependency (the whole point). |
+| TSC revokes/changes publish access | Releases pause until reconfigured; the already-published versions keep working for users. |
+| Provenance/repo mismatch | Publish fails fast in CI (repo URL must match exactly); no bad artifact reaches users. |
+
+---
+
+## 8. What we validated (proof, not theory)
+
+```mermaid
+flowchart LR
+ S1["npm install (640 pkgs)
no monorepo, no workspace"] --> S2["npm run build
(no @wdio/compiler)"]
+ S2 --> S3["npm pack → tarball"]
+ S3 --> S4["install into sample AS
@wdio/browserstack-service"]
+ S4 --> S5["webdriverio deduped
(peerDep fix ✅)"]
+ S5 --> S6["services: browserstack
resolves via initializePlugin"]
+ S6 --> S7["REAL BrowserStack session
ran + test PASSED ✅"]
+ style S7 fill:#e6ffe6
+```
+
+See [`EXTRACTION.md`](../EXTRACTION.md) for the detailed results, including the unit-test status
+(every file passes in isolation; the all-at-once suite needs a teardown tweak owned by the team).
+
+---
+
+## 9. Risk register
+
+| Risk | Likelihood | Mitigation |
+|---|---|---|
+| Duplicate `webdriverio` in user trees | Low | Core packages are `peerDependencies` (validated: deduped). |
+| `services:['browserstack']` stops resolving | Very low | Never change the name/scope; integration-test the shorthand each release. |
+| Service breaks on a new core major | Medium | CI matrix across `webdriverio` majors; peer range as the contract. |
+| Provenance publish fails | Low | `repository` URL matches exactly; repo is public. |
+| TSC won't delegate | Low | Strong precedent (visual/electron); fallback is Option B with a migration. |
+| Version-number confusion (service vs core) | Low | Document independence; compatibility is the peer range, not the number. |
+
+---
+
+## 10. Glossary
+
+- **Lerna fixed mode** — all monorepo packages share one version, bumped together.
+- **`workspace:*`** — pnpm protocol that symlinks a sibling package locally; resolved to a concrete
+ version at publish.
+- **`initializePlugin`** — the `@wdio/utils` function that maps `services: ['x']` to a package by
+ naming convention (`@wdio/x-service` then `wdio-x-service`), importing what's installed.
+- **peerDependency** — a dependency the *consumer* must provide, so a single shared copy is used.
+- **Trusted publishing (OIDC)** — publishing to npm using a short-lived, GitHub-signed identity instead
+ of a long-lived token; configured per package.
+- **Provenance** — a signed attestation linking a published artifact to the exact repo/commit/workflow
+ that built it.
diff --git a/docs/AUTO-UPDATE-AND-NPM-MECHANICS.md b/docs/AUTO-UPDATE-AND-NPM-MECHANICS.md
new file mode 100644
index 0000000..42cc026
--- /dev/null
+++ b/docs/AUTO-UPDATE-AND-NPM-MECHANICS.md
@@ -0,0 +1,204 @@
+# Auto-update feasibility & npm distribution mechanics
+
+> Companion to [THREE-APPROACHES-ANALYSIS.md](./THREE-APPROACHES-ANALYSIS.md).
+> It answers one recurring question in depth: **can we ship updates to the service code on
+> BrowserStack's own cadence — ideally auto-updating for customers — *without* publishing a new npm
+> release every time, and without breaking customers' installs?**
+>
+> The short answer: **true "auto-update without a release" is not safely achievable on npm.** The npm
+> client is built to make "the version you locked is the code you run" a hard guarantee, and every
+> mechanism that tries to get around it either breaks installs (`EINTEGRITY`) or trades away the
+> safety net that makes the package trustworthy. The findings below are **verified empirically**
+> against npm `10.9.0` / Node `22.11.0`.
+
+---
+
+## 0. TL;DR
+
+| Question | Answer |
+|---|---|
+| Can a **URL/CDN dependency** float to "latest" and auto-update? | **No** — a moving URL breaks `npm ci`/`npm install` with `EINTEGRITY` for anyone with a committed lockfile. |
+| Does a **redirect** (`latest` → versioned) avoid that? | **No** — npm pins the *requested* URL + the content hash; flipping the redirect still mismatches. |
+| Can a **caret range** (`^2`) point at a CDN/URL core? | **No** — semver ranges require a registry to enumerate versions. A URL has no version list. |
+| Can the package **fetch its core itself** (postinstall/runtime) to dodge `EINTEGRITY`? | **Yes, mechanically** — but it breaks under `--ignore-scripts`/pnpm defaults, loses provenance & reproducibility, and is the supply-chain-attack shape. |
+| Does **Approach B (Registry Shim)** hit any of these? | **No** — B has no install scripts, stays reproducible (core pinned in the lockfile), works in air-gapped/mirrored CI, and keeps provenance. Its only cost is mild, *recorded* version skew. |
+| Cleanest way to get BrowserStack-cadence releases + auto-update + reproducibility + provenance | **Approach A (Direct Publish) + OIDC trusted publishing** (caret on a normal npm package). |
+
+---
+
+## 1. How npm treats a URL / tarball dependency (verified)
+
+A dependency written as a tarball URL, e.g.
+
+```jsonc
+"dependencies": { "wdio-bs-core": "https://cdn.example.com/wdio-bs-core-9.27.3.tgz" }
+```
+
+resolves and locks like this in `package-lock.json`:
+
+```jsonc
+"node_modules/wdio-bs-core": {
+ "resolved": "https://cdn.example.com/wdio-bs-core-9.27.3.tgz", // the literal URL you wrote
+ "integrity": "sha512-…", // hash of the CONTENT it fetched
+ "version": "9.27.3" // read from the tarball's package.json
+}
+```
+
+The crucial fact: **npm records the content hash and enforces it on every clean install.** This is
+npm's supply-chain protection — "the bytes you locked are the bytes you get, forever."
+
+## 2. Why a hosted-core (Approach C) cannot auto-update
+
+### 2a. A mutable URL breaks installs
+If the same URL (`…/core-latest.tgz`) is overwritten with new content to "push" an update:
+
+- `npm ci` → **`EINTEGRITY` failure** (locked hash ≠ new content). *Verified.*
+- `npm install` with an existing lockfile → **also `EINTEGRITY`** (it does not silently update). *Verified.*
+- Only a **fresh install with no lockfile** picks up the new content. *Verified.*
+
+So a mutable URL doesn't "auto-update" — it **bricks installs** for everyone with a committed
+lockfile (i.e. essentially all CI).
+
+### 2b. A redirect does not help
+Pointing `…/core-latest.tgz` at a `302` redirect to an immutable versioned tarball, then flipping the
+redirect target, fails identically: npm locks the **requested** URL and the **content hash** of what
+it fetched, not the redirect destination. Flipping the redirect → `EINTEGRITY`. *Verified.*
+
+### 2c. A pinned, immutable URL works — but updates are manual
+```jsonc
+"dependencies": { "wdio-bs-core": "https://cdn.example.com/wdio-bs-core-9.27.3.tgz" }
+```
+- `npm install` and `npm ci` are reproducible (immutable artifact, stable hash). *Verified.*
+- To upgrade, **the customer edits the URL** to `…-9.28.0.tgz`. *Verified.*
+
+This is real "version tracking via a URL the customer changes" — but it is **explicit/manual**, not
+auto, and the customer's `package.json` now contains a URL instead of a semver range.
+
+### 2d. Caret/semver cannot target a URL
+`^2.0.0` means "ask the registry for the newest version matching this rule." A URL has no version
+list for npm to query, so **semver ranges are registry-only**. Auto-update fundamentally requires a
+registry (npm, or a private npm-compatible registry) — static object storage cannot provide it.
+
+> The only non-registry sources npm can apply a semver range to are **git** (`git+https://…#semver:^2`,
+> matching git tags) and a **private npm-compatible registry** — neither is static CDN/object storage.
+
+## 3. The "fetch the core ourselves" variant (and why `EINTEGRITY` disappears)
+
+`EINTEGRITY` only applies to artifacts npm puts in the lockfile. If the package keeps its published
+bytes fixed and **downloads the real core itself** — via a `postinstall` script or at runtime — into a
+cache directory *outside* npm's dependency graph, then **npm never records an integrity hash for the
+core**, so it can change freely with **no `EINTEGRITY`**. This is exactly how Puppeteer / Cypress /
+Playwright fetch their browser binaries.
+
+**This works mechanically. Verified end-to-end:**
+
+| Step | Result |
+|---|---|
+| Stable thin package on npm; `postinstall` downloads core v1 from the host | ✅ service runs **core 1.0.0**; lockfile records **only** the thin package (stable hash) — core not tracked |
+| Host's core overwritten to v2; customer runs strict **`npm ci`** (unchanged `package.json`/lockfile) | ✅ **no `EINTEGRITY`**; postinstall re-runs; service now runs **core 2.0.0** |
+| Same install with **`--ignore-scripts`** | ❌ **`MODULE_NOT_FOUND`** — core never downloaded; service broken |
+
+But avoiding `EINTEGRITY` this way removes the safety net rather than the problem. Four consequences:
+
+1. **Breaks for a large set of users — hard.** `--ignore-scripts` is common in enterprise CI, and
+ **pnpm blocks dependency lifecycle scripts by default (v10+) and quarantines fresh releases (v11)**.
+ For all of them the core never downloads → the service fails to load. *(Fetching at runtime instead
+ of postinstall dodges script-blocking, but then air-gapped/proxy CI breaks at test time and it
+ becomes runtime remote-code execution — worse optics.)*
+2. **It is the supply-chain-attack pattern.** "Official package auto-fetches + executes remote vendor
+ code at install/runtime" is the shape security tooling now actively flags and blocks, and it loses
+ npm **provenance** entirely. A host compromise would run unverified code in every customer's CI with
+ nothing to catch it.
+3. **Maximum, *unrecorded* version skew — the killer for a test tool.** The lockfile says `9.27.3`
+ forever while the code that runs changes underneath, with **no record anywhere of what executed**.
+ The same pinned version behaves differently on different days → flaky, unexplained results, nothing
+ to bisect, nothing to cite in a bug report. The version is fully decoupled from the code.
+4. **Air-gap / proxy / offline CI** can't reach the host at install or runtime → broken.
+
+### Hardening (and why it removes the auto-update)
+If built anyway, the responsible form is essentially the Puppeteer model plus signing:
+- **Sign the hosted payload** (e.g. cosign/minisign) and verify signature + expected version before
+ loading — non-negotiable; it restores the integrity given up by leaving npm's graph.
+- **Bundle a working core in the package** as a fallback so `--ignore-scripts`/air-gap degrade to the
+ shipped code instead of crashing.
+- **Log the running core version at startup** so support knows what actually ran.
+- **Fetch at runtime with a cache**, not postinstall, to survive script-blocking.
+
+Note the trap: every step that makes this safe — **sign + pin the core to the release + bundle a
+fallback** — also **removes the auto-update** and converges back to "ship the code / release per
+version." The only variant that *truly* auto-updates is the unsigned fetch-latest one, which is
+exactly what scanners and pnpm defaults block.
+
+## 4. Does Approach B (Registry Shim) hit any of these?
+
+No. B is the thin `@wdio/browserstack-service` re-exporting `@browserstack/wdio-browserstack-service`
+(both normal npm packages) via a caret range. Issue by issue:
+
+| Issue | Hosted-core internal-fetch | **B. Registry Shim** |
+|---|---|---|
+| `EINTEGRITY` | avoided only by leaving npm's graph | **N/A** — both are normal registry packages; lockfile pins both with integrity; registry tarballs are immutable → never mismatch |
+| `--ignore-scripts` / pnpm script-blocking | ❌ breaks (verified `MODULE_NOT_FOUND`) | **✅ no install scripts at all** — pure resolution + `export *` |
+| Supply-chain pattern / scanner flags / provenance | ❌ flagged; no provenance; remote-code channel | **✅ clean** — ordinary public package; no fetch/exec/obfuscation; **npm provenance available** |
+| Reproducibility / version skew | ❌ worst case — code changes with no record; non-reproducible | ⚠️ **mild & recorded** — core pinned in the lockfile (exact version + integrity); `npm ci` reinstalls the same code; `npm ls` shows what ran |
+| Air-gap / proxy / mirror-only CI | ❌ needs the host reachable | **✅ works** — both packages flow through the npm registry / mirror |
+
+**Why B stays clean:**
+- **No install/runtime scripts** — nothing for `--ignore-scripts` or pnpm to disable.
+- **Everything stays in the lockfile** — caret resolves *once* to e.g. `2.5.0`, written to the lockfile
+ with integrity; thereafter `npm ci` reinstalls exactly `2.5.0` from the immutable registry tarball →
+ fully reproducible. The running code is always pinned and visible.
+- **Works through corporate mirrors** — no external host; both packages use the registry customers
+ already proxy.
+
+**B's only residual is *numeric* skew** (the public `@wdio…@9.x` number ≠ the core `@browserstack…@X.y`
+number). Unlike the hosted-fetch model this skew is **recorded and reproducible**, and is tamed by:
+align the core's number with the public number · log the running core version at startup · commit
+lockfiles. See [version-skew handling in ARCHITECTURE-shim-model.md](./ARCHITECTURE-shim-model.md).
+
+**B's own distinct considerations** (not shared with the hosted model): the `@browserstack/wdio-browserstack-service`
+name is in use by another SDK today (needs a new name or a deliberate major bump); the core must keep
+`webdriverio`/`@wdio/*` as **peerDependencies** to avoid a duplicate `webdriverio` copy (which would
+break `instanceof SevereServiceError`, the shared logger, and the reporter bus); and a major range bump
+(`^2`→`^3`) still needs a TSC-approved shim PR (minors/patches flow freely via caret).
+
+## 5. Recommendation
+
+- **True auto-update without an npm release is not safely possible** — not via URL deps (§2) and not
+ via internal fetch (§3). The legitimate internal-fetch pattern pins its payload to the release, so a
+ release is published per version regardless.
+- For **BrowserStack-cadence releases + customers unchanged + lockfile-safe + auto-update + provenance**,
+ the only approach that delivers all of it is **A (Direct Publish) + OIDC trusted publishing**: caret
+ on a normal npm package *is* the auto-update; npm gives reproducibility + provenance; OIDC removes the
+ per-release TSC step.
+- **B (Registry Shim)** is a clean fallback — it avoids every dangerous failure mode above; its only
+ cost is mild, recorded version skew.
+- **Hosted-core / internal-fetch** is justified **only** if the driver is keeping the core
+ proprietary/obfuscated — and even then it must be signed + pinned + given a bundled fallback, which
+ means releasing per version anyway. **Auto-update is not a reason to choose it.**
+
+---
+
+## Appendix — reproducing the experiments
+
+All results above were produced with **npm `10.9.0` / Node `22.11.0`** using a local HTTP server that
+serves tarballs (an immutable-CDN stand-in; npm treats `https://…tgz` and `file:…tgz` deps identically):
+
+1. **URL dep lockfile shape (§1):** declare `"": "http://localhost:PORT/core.tgz"`, `npm install`,
+ inspect `package-lock.json` → `resolved` + `integrity` + `version`.
+2. **Mutable URL (§2a):** install (locks v1 hash) → overwrite the served tarball with v2 → `npm ci` →
+ `EINTEGRITY`. Then `npm install` → `EINTEGRITY`. Then delete the lockfile + `npm install` → v2.
+3. **Redirect (§2b):** serve `core-latest.tgz` as `302` → `core-1.0.0.tgz`; install; flip the `302` to
+ `core-2.0.0.tgz`; `npm ci` → `EINTEGRITY`.
+4. **Pinned URL (§2c):** depend on `…/core-1.0.0.tgz`; `npm install` + `npm ci` reproducible; edit the
+ dep to `…/core-2.0.0.tgz` → `npm install` picks up v2.
+5. **Internal fetch (§3):** a stable thin package whose `postinstall` downloads the core into `./core`;
+ `npm install` runs core v1; overwrite the served core with v2; `npm ci` → **passes**, runs v2 (no
+ `EINTEGRITY`); `npm ci --ignore-scripts` → `MODULE_NOT_FOUND`.
+
+### References
+- Node.js removed `--experimental-network-imports` (runtime `import()` of `https://` URLs) for security:
+ https://github.com/nodejs/node/pull/53822
+- Playwright pins browser binaries to each package release: https://playwright.dev/docs/browsers
+- Cypress binary download / global cache model: https://docs.cypress.io/app/references/advanced-installation
+- pnpm supply-chain defaults (lifecycle-script blocking, minimum release age / quarantine):
+ https://pnpm.io/supply-chain-security
diff --git a/docs/CODE-CHANGES.md b/docs/CODE-CHANGES.md
new file mode 100644
index 0000000..8fac82c
--- /dev/null
+++ b/docs/CODE-CHANGES.md
@@ -0,0 +1,218 @@
+# Code changes for the extraction — what, why, and how they communicate
+
+This explains **every change** made to turn the in-monorepo `@wdio/browserstack-service`
+into a standalone, independently-releasable package — *why* each is needed, its *purpose*,
+and how it changes the way this package **communicates** with:
+
+- **the external repo** = upstream WebdriverIO core (`webdriverio`, `@wdio/types`, `@wdio/reporter`, `@wdio/logger`, `@wdio/cli`), and
+- **BrowserStack's own service code** = the `@browserstack/*` SDKs (`@browserstack/wdio-browserstack-service` gRPC client, `@browserstack/ai-sdk-node`).
+
+> **The one principle:** we changed only the **plumbing** (how the package is *built, tested,
+> released, and wired to its dependencies*). The service's **runtime behaviour is unchanged** —
+> the only source edit is a one-line lifecycle fix (`unref`, §6). Everything users rely on
+> (package name, `services: ['browserstack']`, the `exports` map, options) is untouched.
+
+---
+
+## The 3 communication boundaries (and which changes touch them)
+
+```
+ ┌─────────────────────────── your Node process ───────────────────────────┐
+ consumer → │ @wdio/cli / @wdio/runner ⇄(hooks)⇄ @wdio/browserstack-service │
+ (sample/ │ │ │ │
+ user) │ webdriverio, @wdio/logger, ⇄(peer)⇄ │ │ ⇄(deps)⇄ @browserstack│ → BrowserStack
+ │ @wdio/reporter, @wdio/types (shared) │ │ /* SDKs */ │ cloud (gRPC/REST)
+ └───────────────────────────────────────────────────┘
+ ▲ boundary 1: upstream core ▲ boundary 2: BrowserStack SDK
+ (CHANGED: deps → peerDeps) (UNCHANGED: regular deps)
+```
+
+| Boundary | What it is | Did the extraction change it? |
+|---|---|---|
+| **1. Upstream WebdriverIO core** | `webdriverio`, `@wdio/types/reporter/logger`, `@wdio/cli` | **Yes** — moved to `peerDependencies` (§1). This is the headline change. |
+| **2. BrowserStack SDKs** | `@browserstack/wdio-browserstack-service` (gRPC), `@browserstack/ai-sdk-node` | **No** — still regular `dependencies`; runtime gRPC/SDK calls identical. |
+| **3. Consumers** | user projects loading `services: ['browserstack']` | **No** — same name, same `exports`, same service interface. |
+
+---
+
+## Summary of changes
+
+| # | Change | Why / purpose | Communication impact |
+|---|---|---|---|
+| 1 | `package.json`: core deps `workspace:*` → **`peerDependencies` (`^9`)** + devDeps | Stop bundling our own copy of WDIO core; use the host's | **Boundary 1** — now shares the consumer's *instances* of webdriverio/logger/reporter |
+| 2 | `package.json`: add `scripts` (build/test/version/release) | The monorepo built/released centrally; standalone needs its own | Replaces the monorepo's build/release "communication" |
+| 3 | `tsconfig.json`: self-contained (drop `../../tsconfig`, `../../@types`) | Remove build-time coupling to the monorepo root | Severs compile-time dependency on the external repo |
+| 4 | `tsconfig.prod.json` (new) | Emit only `.d.ts` for the published build | Defines the public **type** contract shipped to consumers |
+| 5 | `scripts/build.mjs` (new) | Replace the shared `@wdio/compiler` | Produces the **same `build/` + `exports`** so loader/consumers resolve identically |
+| 6 | `src/request-handler.ts`: `.unref()` | Don't let the poll timer keep the process/worker alive | The **only** runtime change; behaviour otherwise identical |
+| 7 | `vitest.config.ts` + `__mocks__/` (new) | Replace the monorepo root test config + root mocks | Test-time only; reporter mock now talks to **published** `@wdio/reporter` |
+| 8 | `.changeset/` + `.github/workflows/` (new) | Replace Lerna lockstep with independent OIDC publishing | Replaces release "communication" with the TSC train |
+| 9 | `.npmignore`, `repository`/`homepage`/`bugs` | Keep the tarball lean; point metadata at the new repo | Packaging metadata; provenance later needs an exact repo match |
+
+---
+
+## 1. `dependencies` → `peerDependencies` (the important one)
+
+**Before (in the monorepo):**
+```jsonc
+"dependencies": {
+ "@wdio/logger": "workspace:*", "@wdio/reporter": "workspace:*",
+ "@wdio/types": "workspace:*", "webdriverio": "workspace:*", ...
+}
+```
+At publish, `workspace:*` was frozen to an **exact** version (e.g. `webdriverio: 9.27.2`), so the
+package effectively **owned its own copy** of WDIO core.
+
+**After (standalone):**
+```jsonc
+"peerDependencies": {
+ "webdriverio": "^9.0.0", "@wdio/types": "^9.0.0",
+ "@wdio/reporter": "^9.0.0", "@wdio/logger": "^9.0.0",
+ "@wdio/cli": "^5.0.0 || ... || ^9.0.0"
+},
+"devDependencies": { "webdriverio": "^9.0.0", "@wdio/types": "^9.0.0", ... } // for build/test only
+```
+
+**Why it's needed.** Inside the monorepo, `workspace:*` symlinks to the sibling packages, so
+there's always exactly one copy. Once published from outside, an *exact regular dependency* on
+`webdriverio` would install a **second copy** into the user's tree (they already have `webdriverio`).
+
+**Purpose.** Make the host project *provide* WDIO core; this package binds to **those** instances.
+
+**Communication impact (boundary 1) — this is the crux.** The service imports *values* from core:
+`SevereServiceError` (from `webdriverio`), the logger (`@wdio/logger`), `WDIOReporter`
+(`@wdio/reporter`). For those to work, the service must use the **same module instances** the
+runner uses:
+- `instanceof SevereServiceError` checks only pass if both sides import the *same* class.
+- the logger must be the *same* singleton the framework configured.
+- the reporter event bus must be shared.
+
+`peerDependencies` guarantee a **single shared copy** (verified: `npm ls webdriverio` → one). A
+regular-dep duplicate would silently break these. The `devDependencies` entries exist only so the
+package can **build and unit-test** itself in isolation; they're not shipped.
+
+> `@wdio/cli` keeps its historical wide peer range (`^5 || … || ^9`) because the service never
+> imports it — it's only the host runner; the four core packages use `^9` because that's what this
+> line is actually built against.
+
+---
+
+## 2. `scripts` (build / test / version / release)
+
+**Why.** The monorepo had **no per-package scripts** — a central pipeline built and released every
+package. Standalone, the package must do this itself.
+
+**Purpose.** `build` (esbuild + tsc), `build:watch` (dev loop), `test` (Vitest), `version`/`release`
+(Changesets).
+
+**Communication impact.** Replaces the *release-time* communication with the monorepo's Lerna train
+(see §8). No runtime impact.
+
+---
+
+## 3. `tsconfig.json` made self-contained
+
+**Why.** It used `extends: "../../tsconfig"` and `include: ["../../@types"]` — i.e. it read config
+from the **monorepo root**, which doesn't exist outside it.
+
+**Purpose.** Inline the compiler options the root used; drop the `../../@types` include (the package
+has its own `src/@types`).
+
+**Communication impact.** Severs the **compile-time** coupling to the external repo. No effect on the
+published JS or on runtime.
+
+## 4. `tsconfig.prod.json` (new)
+
+**Why/purpose.** A declaration-only profile (`emitDeclarationOnly`, excludes tests) that `build`
+uses to emit `build/*.d.ts`.
+
+**Communication impact.** Defines the **TypeScript type contract** shipped to consumers
+(`types: ./build/index.d.ts`) — must stay equivalent to the monorepo's emitted types so downstream
+type-checking is unchanged.
+
+## 5. `scripts/build.mjs` (new) — replaces `@wdio/compiler`
+
+**Why.** The monorepo built every package with a shared esbuild-based `@wdio/compiler` in
+`infra/compiler`; that tool isn't available standalone.
+
+**Purpose.** Reproduce it for this one package: one ESM bundle per `exports` entry
+(`.` → `build/index.js`, `./cleanup` → `build/cleanup.js`), every dependency/peer marked **external**
+(only our `src` is bundled), `tsc` emits the `.d.ts`.
+
+**Communication impact.** It deliberately produces the **same `build/` layout and the same `exports`
+entrypoints** as before. That's what keeps **boundary 3** intact — WebdriverIO's plugin loader
+(`initializePlugin`) and any consumer resolve `@wdio/browserstack-service` and `.../cleanup`
+exactly as they did when the monorepo built it. Marking deps external is also what *implements*
+boundary 1/2: the bundle contains no copy of `webdriverio` or the `@browserstack` SDKs — it
+`import`s them at runtime from the consumer's `node_modules`.
+
+---
+
+## 6. `src/request-handler.ts` — `.unref()` (the only runtime change)
+
+```ts
+this.pollEventBatchInterval = setInterval(this.sendBatch.bind(this), DATA_BATCH_INTERVAL)
+this.pollEventBatchInterval?.unref?.() // ← added
+```
+
+**Why.** The Test-Ops batch poller is a `setInterval` that, un-`unref`'d, keeps the Node event loop
+(and a Vitest worker) alive forever — which made the full standalone test suite hang.
+
+**Purpose.** Let the timer **not** hold the process open on its own; it still fires on schedule while
+the process is otherwise running, so **batching behaviour is unchanged** in a real run.
+
+**Communication impact.** None to any boundary — it's a process-lifecycle fix, not a protocol/data
+change. (It's the single line that touches runtime; everything else is build/test/release plumbing.)
+
+---
+
+## 7. `vitest.config.ts` + `__mocks__/` (new)
+
+**Why.** Tests were driven by the monorepo **root** `vitest.config.ts` and resolved manual mocks from
+the **root `__mocks__/`** — neither exists standalone.
+
+**Purpose.** A local Vitest config (same env/pool/setup) and a copy of the mocks the suite needs
+(`@wdio/logger`, `@wdio/reporter`, `browserstack-local`, `fs`, `chalk`, `fetch`).
+
+**Communication impact (test-time only).** The `@wdio/reporter` mock was **adapted** to import the
+stats classes + `getBrowserName` from the **published `@wdio/reporter`** instead of monorepo source
+paths (`../../packages/wdio-reporter/src/...`) — i.e. the test now "communicates" with the published
+package, matching how the real build resolves it. No effect on shipped code.
+
+---
+
+## 8. `.changeset/` + `.github/workflows/` (new)
+
+**Why.** In the monorepo, releases were a **TSC-triggered Lerna lockstep** publish. Standalone, the
+package versions and publishes itself.
+
+**Purpose.** Changesets for independent versioning; `release.yml` publishes to npm via **OIDC trusted
+publishing** (no long-lived token); `ci.yml` builds/tests on PRs.
+
+**Communication impact.** Replaces the *release-time* communication with the WebdriverIO TSC train:
+the package will publish under the **same `@wdio` scope** from this repo once the TSC delegates a
+trusted publisher. Until then these workflows are inert templates (Actions only run at a repo root).
+
+## 9. `.npmignore` + `repository`/`homepage`/`bugs`
+
+**Why/purpose.** Keep the published tarball to `build/` + `README` + `LICENSE` + types (exclude
+`src`, tests, mocks, scripts, configs, docs); point metadata at the new repo.
+
+**Communication impact.** Packaging only. Note: for **provenance** at publish time, `repository.url`
+must match the building repo **exactly** — so it must be set to the final home before the first
+signed publish.
+
+---
+
+## What did NOT change (so users are unaffected)
+
+- **`name`** (`@wdio/browserstack-service`), **`exports`** (`.` + `./cleanup`), **`type: module`**, **`engines`**, `publishConfig`.
+- All **runtime feature code** (launcher, Local tunnel, Test Observability, Accessibility, AI, Percy) — byte-identical except the one `unref` line.
+- The **`@browserstack/*` SDK dependencies** (boundary 2) — same versions, same gRPC/REST communication.
+- The **service interface** WDIO calls (`onPrepare`, `beforeSession`, `beforeTest`, `after`, `onComplete`, …).
+
+This is why the extraction is *plumbing*: it changes **where the package is built and released and
+how it declares its dependencies**, not **what it does at runtime**.
+
+> See also: [`ARCHITECTURE.md`](./ARCHITECTURE.md) (the full picture), [`EXTRACTION.md`](../EXTRACTION.md)
+> (cutover checklist), [`DEV-TESTING.md`](./DEV-TESTING.md) (how to verify locally).
diff --git a/docs/DEV-TESTING.md b/docs/DEV-TESTING.md
new file mode 100644
index 0000000..796d3cc
--- /dev/null
+++ b/docs/DEV-TESTING.md
@@ -0,0 +1,154 @@
+# Manual dev-testing guide — `@wdio/browserstack-service`
+
+How to make a change to this package and verify it end-to-end against a real
+BrowserStack session, locally, before releasing.
+
+## The pieces (don't confuse them)
+
+| Thing | npm name | Repo | Role |
+|---|---|---|---|
+| **The plugin (this repo)** | `@wdio/browserstack-service` | this repo | what you edit/test |
+| gRPC/protobuf SDK | `@browserstack/wdio-browserstack-service` | `browserstack/wdio-browserstack-service` | a **dependency** (uses `buf`); unchanged unless you're testing SDK changes |
+| Sample/consumer project | *(anything, e.g. `bs-sample`)* | throwaway | loads the plugin via `services: ['browserstack']` |
+
+You dev-test by **building the plugin → installing it into a sample WDIO project → running a real session**.
+
+---
+
+## The dev-test loop (overview)
+
+```
+edit src/ → build (esbuild + tsc) → put it into a sample project → run wdio → inspect
+ (link = fast | tarball = faithful)
+```
+
+- **Unit logic?** run Vitest in this repo (fast, no cloud).
+- **Behavior / integration?** install into a sample project and run a real BrowserStack session.
+
+---
+
+## 0. Prerequisites
+- Node **20.11.1+** (WDIO **v9**; the v8 line uses Node 16). This repo has an `.nvmrc`.
+- BrowserStack creds: `BROWSERSTACK_USERNAME`, `BROWSERSTACK_ACCESS_KEY`.
+
+## 1. Build the plugin
+```bash
+cd wdio-browserstack-service
+nvm use # or: nvm install 20.11.1
+npm install
+npm run build # esbuild → build/index.js + build/cleanup.js ; tsc → build/*.d.ts
+```
+Optional unit tests:
+```bash
+npm test # full Vitest suite
+# NOTE: the all-at-once suite can hang on a teardown issue (tracked); a single file is reliable:
+npx vitest run tests/util.test.ts
+```
+
+## 2. Create a sample WDIO project (once)
+```bash
+mkdir bs-sample && cd bs-sample
+npm init -y
+npm pkg set type=module
+npm i -D @wdio/cli @wdio/local-runner @wdio/mocha-framework @wdio/globals webdriverio
+mkdir -p test
+```
+
+`bs-sample/wdio.conf.js`:
+```js
+export const config = {
+ runner: 'local',
+ user: process.env.BROWSERSTACK_USERNAME,
+ key: process.env.BROWSERSTACK_ACCESS_KEY,
+ hostname: 'hub.browserstack.com', port: 443, protocol: 'https', path: '/wd/hub',
+ // the plugin is referenced ONLY by the shorthand — WDIO resolves it to whatever
+ // is installed as @wdio/browserstack-service (i.e. YOUR build).
+ services: [['browserstack', {
+ // toggle the feature you're testing:
+ testObservability: true,
+ // browserstackLocal: true,
+ // accessibility: true,
+ }]],
+ capabilities: [{
+ browserName: 'chrome',
+ 'bstack:options': { os: 'Windows', osVersion: '11', buildName: 'dev-test', sessionName: 'dev-test' }
+ }],
+ framework: 'mocha',
+ specs: ['./test/**/*.e2e.js'],
+ mochaOpts: { timeout: 90000 },
+ logLevel: 'info'
+}
+```
+
+`bs-sample/test/sample.e2e.js`:
+```js
+import { browser, expect } from '@wdio/globals'
+describe('dev test', () => {
+ it('runs on BrowserStack', async () => {
+ await browser.url('https://webdriver.io/')
+ await expect(browser).toHaveTitle(expect.stringContaining('WebdriverIO'))
+ })
+})
+```
+
+## 3. Put YOUR build into the sample — pick a loop
+
+### Loop A — fast iteration (`npm link`)
+```bash
+# in the plugin repo:
+npm run build:watch & # rebuilds build/ on every src change
+npm link # registers @wdio/browserstack-service (symlink)
+# in bs-sample:
+npm link @wdio/browserstack-service
+```
+Edit `src/` → watcher rebuilds → re-run the sample. Best for rapid logic changes.
+
+> ⚠️ **Caveat:** with `npm link`, Node follows the symlink and resolves the plugin's
+> `webdriverio`/`@wdio/*` **peers from the plugin repo's own `node_modules`**, not the
+> sample's — so a *duplicate* `webdriverio` can appear. That means **`link` does NOT
+> faithfully test the peerDependency behavior.** Use it for logic; confirm with Loop B.
+
+### Loop B — faithful (tarball) — use before you trust a change
+```bash
+# in the plugin repo:
+npm run build && npm pack --pack-destination /tmp
+# → /tmp/wdio-browserstack-service-.tgz
+# in bs-sample:
+npm i /tmp/wdio-browserstack-service-.tgz
+```
+Installs **exactly what would be published** (honours `.npmignore`, `exports`, and
+peerDependencies — no duplicate `webdriverio`). Re-pack + re-install on each change.
+
+## 4. Run a real BrowserStack session
+```bash
+cd bs-sample
+BROWSERSTACK_USERNAME=xxx BROWSERSTACK_ACCESS_KEY=yyy npx wdio run wdio.conf.js
+```
+Watch for `@wdio/browserstack-service` logs (service started, Local tunnel, TestHub) and
+the `automate.browserstack.com/builds/...` session link in the output.
+
+## 5. Confirm you're actually running YOUR build (not the published one)
+```bash
+# from bs-sample:
+ls -l node_modules/@wdio/browserstack-service # link loop → symlink to your repo; tarball loop → real dir
+node --input-type=module -e "console.log(import.meta.resolve('@wdio/browserstack-service'))" # run from inside bs-sample
+npm ls webdriverio # should show exactly ONE copy (peerDep working)
+```
+For an unmistakable check, temporarily add `console.log('MY BUILD')` at the top of
+`src/index.ts`, rebuild, and confirm it prints during the run — then remove it.
+
+## 6. Exercise the feature areas
+Toggle options in `wdio.conf.js` to hit different code paths:
+- **Local tunnel:** `browserstackLocal: true` (+ point the test at a local URL/server)
+- **Test Observability / TestHub:** `testObservability: true`
+- **Accessibility:** `accessibility: true` (Chrome only)
+- **Percy:** Percy config + `PERCY_TOKEN`
+- **App Automate:** an `app` capability
+- **Multiremote:** capabilities as an object of named browsers
+
+## Gotchas
+- **ESM-only** — the sample must be `"type": "module"`.
+- **Node** — v9 needs Node ≥20; using 16.x targets the v8 line.
+- **Rebuild after edits** — `build:watch` for Loop A; re-pack for Loop B.
+- **Duplicate `webdriverio`** — verify with `npm ls webdriverio`; if `link` shows two, that's the symlink caveat (use Loop B to validate peers).
+- **Fast feedback for pure logic** — prefer Vitest in this repo over a cloud run.
diff --git a/docs/MIGRATION-PLAN.md b/docs/MIGRATION-PLAN.md
new file mode 100644
index 0000000..50ff385
--- /dev/null
+++ b/docs/MIGRATION-PLAN.md
@@ -0,0 +1,61 @@
+# Migration plan — taking over `@wdio/browserstack-service`
+
+This repo becomes the BrowserStack-owned home of the WebdriverIO service, published on BrowserStack's
+own cadence, with **no change for end users** (`npm i @wdio/browserstack-service`, `services: ['browserstack']`
+keep working byte-for-byte).
+
+## Why a monorepo
+This repository already publishes the gRPC/protobuf core **`@browserstack/wdio-browserstack-service`**,
+which the service depends on. Rather than disturb that package, we keep it here and add the service
+beside it as an npm workspace:
+
+```
+packages/core -> @browserstack/wdio-browserstack-service (unchanged: buf + tsc, released by the SDK team)
+packages/browserstack-service -> @wdio/browserstack-service (the WebdriverIO service)
+```
+
+- The service depends on the core via the normal npm range `^2.0.2`; npm links the local `packages/core`
+ during development, and the **published** service still depends on the npm-published core.
+- Changesets **ignores** the core (see `.changeset/config.json`), so this pipeline never versions or
+ publishes it — the SDK team keeps releasing it exactly as before.
+
+## Release model
+- Versioned/published with **Changesets**, independent of WebdriverIO core's release schedule.
+- `main` → `latest` dist-tag (v9 line); `v8` branch → `v8` dist-tag (via that branch's `publishConfig.tag`).
+- Publishing uses **npm OIDC trusted publishing** — no long-lived token, provenance-signed, revocable.
+ - One-time setup by an `@wdio` npm org admin: package `@wdio/browserstack-service` → Settings →
+ Trusted Publisher → GitHub Actions → Org `browserstack`, Repo `wdio-browserstack-service`,
+ Workflow `release.yml`, Environment empty.
+ - Requires a public repo, npm ≥ 11.5.1, Node ≥ 22.14.
+
+## Release-readiness fixes applied during the move
+- Strict `files` allowlist on the service (`build`, `browserstack-service.d.ts`, `README.md`, `LICENSE`)
+ → tarball is 80 files / ~590 kB (previously leaked internal docs, a log, a stray tarball, and
+ `*.d.ts.map`).
+- `declarationMap: false` in `tsconfig.prod.json` (no `.d.ts.map` in the package).
+- Single, consistent toolchain: **npm workspaces** + `npm ci` everywhere (the earlier draft mixed pnpm
+ with an npm lockfile and pinned Node 20, which would have failed CI/Release).
+- `repository`/`homepage`/`bugs` point at `browserstack/wdio-browserstack-service` (+ `repository.directory`).
+
+## Verification before any public PR (how customers actually use it)
+1. `npm ci && npm run build && npm test` green (core builds via buf, service via esbuild + tsc).
+2. `npm pack -w @wdio/browserstack-service` ships only `build/ + README + LICENSE + ambient d.ts`.
+3. **Functional test:** in a fresh project, install the packed tarball + `webdriverio`, set
+ `services: ['browserstack']`, and run a real BrowserStack session — assert the shorthand resolves,
+ `webdriverio` dedupes to one copy, `./cleanup` works, and the session appears on the dashboard.
+ Repeat for the v8 line.
+
+## Cutover sequence (no publishing gap)
+1. Land this monorepo conversion (PR-1) with SDK-team review.
+2. `@wdio` npm admin configures OIDC trusted publishing for `@wdio/browserstack-service`.
+3. First release from this repo at **≥ 9.29.0** (`latest`) and the next 8.x (`v8`) — must clear npm's
+ current `9.28.0` / `8.48.0`.
+4. Install the freshly published package from npm and re-run the functional test.
+5. **Then** land the WebdriverIO monorepo PRs that remove the in-repo service and update docs links
+ (main + v8), adding a redirect for `/docs/browserstack-service`.
+6. Rollback if needed: re-point dist-tags; the WebdriverIO monorepo can keep publishing until step 5 merges.
+
+## Companion docs
+- [`ARCHITECTURE.md`](./ARCHITECTURE.md) — how the service works and talks to BrowserStack.
+- [`AUTO-UPDATE-AND-NPM-MECHANICS.md`](./AUTO-UPDATE-AND-NPM-MECHANICS.md) — why we publish to npm
+ (vs hosted-core / auto-update approaches) and the npm distribution mechanics.
diff --git a/package-lock.json b/package-lock.json
index 7051ae4..c82e096 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,29 +1,100 @@
{
- "name": "@browserstack/wdio-browserstack-service",
- "version": "2.0.2",
+ "name": "wdio-browserstack-service-monorepo",
+ "version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "@browserstack/wdio-browserstack-service",
- "version": "2.0.2",
+ "name": "wdio-browserstack-service-monorepo",
+ "version": "0.0.0",
+ "license": "MIT",
+ "workspaces": [
+ "packages/*"
+ ],
+ "devDependencies": {
+ "@changesets/cli": "^2.27.9"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
- "@bufbuild/protobuf": "^2.5.2",
- "@grpc/grpc-js": "1.13.3"
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
},
- "devDependencies": {
- "@bufbuild/buf": "^1.55.1",
- "ts-proto": "^2.7.5",
- "typescript": "^5.4.5"
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
+ "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@browserstack/ai-sdk-node": {
+ "version": "1.5.17",
+ "resolved": "https://registry.npmjs.org/@browserstack/ai-sdk-node/-/ai-sdk-node-1.5.17.tgz",
+ "integrity": "sha512-odjnFulpBeF64UGHA+bIxkIcALYvEPznTl4U0hRT1AFfn4FqT+4wQdPBYnSnlc2XWTedv4zCDvbp4AFrtKXHEw==",
+ "license": "SEE LICENSE IN LICENSE.md",
+ "dependencies": {
+ "axios": "^1.7.4",
+ "uuid": "9.0.1"
+ }
+ },
+ "node_modules/@browserstack/ai-sdk-node/node_modules/uuid": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
+ "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).",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
}
},
+ "node_modules/@browserstack/wdio-browserstack-service": {
+ "resolved": "packages/core",
+ "link": true
+ },
"node_modules/@bufbuild/buf": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.56.0.tgz",
- "integrity": "sha512-1xQWOf3FCDDTi+5B/VScQ73EP6ACwQPCP4ODvCq2L6IVgFtvYX49ur6cQ2qCM8yFitIHESm/Nbff93sh+V/Iog==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf/-/buf-1.70.0.tgz",
+ "integrity": "sha512-oJWGqltlu8F7VVNHLoJ3pFXhjfiGpbh7+/mXW0y+VMPWFGxc9YDv4de1UcX7zhhjV6MbE4SiEGo5Gs5jhpVg5A==",
"dev": true,
"hasInstallScript": true,
+ "license": "Apache-2.0",
"bin": {
"buf": "bin/buf",
"protoc-gen-buf-breaking": "bin/protoc-gen-buf-breaking",
@@ -33,23 +104,24 @@
"node": ">=12"
},
"optionalDependencies": {
- "@bufbuild/buf-darwin-arm64": "1.56.0",
- "@bufbuild/buf-darwin-x64": "1.56.0",
- "@bufbuild/buf-linux-aarch64": "1.56.0",
- "@bufbuild/buf-linux-armv7": "1.56.0",
- "@bufbuild/buf-linux-x64": "1.56.0",
- "@bufbuild/buf-win32-arm64": "1.56.0",
- "@bufbuild/buf-win32-x64": "1.56.0"
+ "@bufbuild/buf-darwin-arm64": "1.70.0",
+ "@bufbuild/buf-darwin-x64": "1.70.0",
+ "@bufbuild/buf-linux-aarch64": "1.70.0",
+ "@bufbuild/buf-linux-armv7": "1.70.0",
+ "@bufbuild/buf-linux-x64": "1.70.0",
+ "@bufbuild/buf-win32-arm64": "1.70.0",
+ "@bufbuild/buf-win32-x64": "1.70.0"
}
},
"node_modules/@bufbuild/buf-darwin-arm64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.56.0.tgz",
- "integrity": "sha512-9neaI9gx1sxOGl9xrL7kw6H+0WmVAFlIQTIDc3vt1qRhfgOt/8AWOHSOWppGTRjNiB0qh6Xie1LYHv/jgDVN0g==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-arm64/-/buf-darwin-arm64-1.70.0.tgz",
+ "integrity": "sha512-c7owUswBbMmwfHPH9JRBEJu09mrXYGC33V2JQCgraWCBm74Z95AOkhDua50qiBrQnysvJkJ0p/z4MWxJqcpnIA==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
@@ -59,13 +131,14 @@
}
},
"node_modules/@bufbuild/buf-darwin-x64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.56.0.tgz",
- "integrity": "sha512-nRHPMXV8fr/lqU+u/1GGsUg7OvNcxJuCJoJpfRoRg38b+NPzOz2FkQAs5OEJzzprQB5aftn5//cl8YXjgvTuFA==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-darwin-x64/-/buf-darwin-x64-1.70.0.tgz",
+ "integrity": "sha512-sucV3lQXVuOqYs3+ToulkUh2tZuMnl286DKb44imp3PnexVhAVOP7d3ybYe98HNGwysEdjNP2WIOGb0uKuRCIQ==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
@@ -75,13 +148,14 @@
}
},
"node_modules/@bufbuild/buf-linux-aarch64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.56.0.tgz",
- "integrity": "sha512-+td559RuKNwYDnq49NrIDGJ4F73Ra4QzVVbsC+UeveA0HMnIGRzFbchGjHtNJyaZsI57sXJ7dCHH0iFV3jcYwQ==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-aarch64/-/buf-linux-aarch64-1.70.0.tgz",
+ "integrity": "sha512-4viSYqbhIusd6LR+JayDex8S1rLUL+hTUMYUgSPl75EC93FpJM4vkk2RhoAhyjQqWF/JQLcyWV8kjRRiIwygdg==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"linux"
@@ -91,13 +165,14 @@
}
},
"node_modules/@bufbuild/buf-linux-armv7": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-armv7/-/buf-linux-armv7-1.56.0.tgz",
- "integrity": "sha512-9v3zmos6wRTBc4QeIg4rfDmPzmTgtUTRCbhr87qws/yddIT8cFtHHhy1whnozBNqtmYOdwZNBNx/QXqGGcRuKw==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-armv7/-/buf-linux-armv7-1.70.0.tgz",
+ "integrity": "sha512-GqujpTX4MXtYiUkxd6oI1g0JaCX3L6koT16Gl0D0HIQ/V2mptH7x4UW8nK3tAURMjrHsEEhcSJRtmfINTTKnsg==",
"cpu": [
"arm"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"linux"
@@ -107,13 +182,14 @@
}
},
"node_modules/@bufbuild/buf-linux-x64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.56.0.tgz",
- "integrity": "sha512-3jZHHBol1fuichNke7LJtHJUdw314XBj6OuJHY6IufsaaVIj1mtM2DPbGiDhYB453J7FiV/buadctKBxAAHclg==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-linux-x64/-/buf-linux-x64-1.70.0.tgz",
+ "integrity": "sha512-5WHGUIb5iLFXcnqV33TDejqaPgx0CWFaYW7b4wh12wT0w3DR+ghFq6S6RmYyZLbTuhS4ZFsf+xyk5m+HViKxrA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"linux"
@@ -123,13 +199,14 @@
}
},
"node_modules/@bufbuild/buf-win32-arm64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.56.0.tgz",
- "integrity": "sha512-KMGzSf9rIbT01Jb2685JovwRRYEdL7Zbs6ZrjyhIHBgKK6cBwz1AJvEaDrWMEzCdv+opQwjgM6UdtA4e9BWP1A==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-arm64/-/buf-win32-arm64-1.70.0.tgz",
+ "integrity": "sha512-dU1qh7iD08/1avCHwIOoGsatQctE6uGwgOue9GOaThi8/Rdy1x9CC/eFdyFSeCMwbUg9ABQvMGUocylfUe6xDw==",
"cpu": [
"arm64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"win32"
@@ -139,13 +216,14 @@
}
},
"node_modules/@bufbuild/buf-win32-x64": {
- "version": "1.56.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.56.0.tgz",
- "integrity": "sha512-19LFOCyFFVTaaqNGtYTpiF67fcpneWZFlm8UNU+Xs87Kh+N5i/LjDjNytnpFT6snwU4/S+UUkq7WgS6UPjqXIg==",
+ "version": "1.70.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/buf-win32-x64/-/buf-win32-x64-1.70.0.tgz",
+ "integrity": "sha512-iKYbjTbEk0ppkv2SrsPFhYus93kj/aMN8aRsrpuo91ZVqXg8JcH4XXbgFpwiFAsiABjqKICFfnDomrFvv49UOA==",
"cpu": [
"x64"
],
"dev": true,
+ "license": "Apache-2.0",
"optional": true,
"os": [
"win32"
@@ -155,343 +233,9035 @@
}
},
"node_modules/@bufbuild/protobuf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.3.tgz",
- "integrity": "sha512-w/gJKME9mYN7ZoUAmSMAWXk4hkVpxRKvEJCb3dV5g9wwWdxTJJ0ayOJAVcNxtdqaxDyFuC0uz4RSGVacJ030PQ=="
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.12.0.tgz",
+ "integrity": "sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==",
+ "license": "(Apache-2.0 AND BSD-3-Clause)"
},
- "node_modules/@grpc/grpc-js": {
- "version": "1.13.3",
- "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.3.tgz",
- "integrity": "sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==",
+ "node_modules/@changesets/apply-release-plan": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.1.tgz",
+ "integrity": "sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "@grpc/proto-loader": "^0.7.13",
- "@js-sdsl/ordered-map": "^4.4.2"
- },
- "engines": {
- "node": ">=12.10.0"
+ "@changesets/config": "^3.1.4",
+ "@changesets/get-version-range-type": "^0.4.0",
+ "@changesets/git": "^3.0.4",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "detect-indent": "^6.0.0",
+ "fs-extra": "^7.0.1",
+ "lodash.startcase": "^4.4.0",
+ "outdent": "^0.5.0",
+ "prettier": "^2.7.1",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.5.3"
}
},
- "node_modules/@grpc/proto-loader": {
- "version": "0.7.15",
- "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
- "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
+ "node_modules/@changesets/assemble-release-plan": {
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.10.tgz",
+ "integrity": "sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "lodash.camelcase": "^4.3.0",
- "long": "^5.0.0",
- "protobufjs": "^7.2.5",
- "yargs": "^17.7.2"
- },
- "bin": {
- "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
- },
- "engines": {
- "node": ">=6"
+ "@changesets/errors": "^0.2.0",
+ "@changesets/get-dependents-graph": "^2.1.4",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "semver": "^7.5.3"
}
},
- "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==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/js-sdsl"
+ "node_modules/@changesets/changelog-git": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz",
+ "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/types": "^6.1.0"
}
},
- "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=="
- },
- "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=="
- },
- "node_modules/@protobufjs/codegen": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
- "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
- },
- "node_modules/@protobufjs/eventemitter": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
- "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
- },
- "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==",
+ "node_modules/@changesets/cli": {
+ "version": "2.31.0",
+ "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.31.0.tgz",
+ "integrity": "sha512-AhI4enNTgHu2IZr6K4WZyf0EPch4XVMn1yOMFmCD9gsfBGqMYaHXls5HyDv6/CL5axVQABz68eG30eCtbr2wFg==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "@protobufjs/aspromise": "^1.1.1",
- "@protobufjs/inquire": "^1.1.0"
+ "@changesets/apply-release-plan": "^7.1.1",
+ "@changesets/assemble-release-plan": "^6.0.10",
+ "@changesets/changelog-git": "^0.2.1",
+ "@changesets/config": "^3.1.4",
+ "@changesets/errors": "^0.2.0",
+ "@changesets/get-dependents-graph": "^2.1.4",
+ "@changesets/get-release-plan": "^4.0.16",
+ "@changesets/git": "^3.0.4",
+ "@changesets/logger": "^0.1.1",
+ "@changesets/pre": "^2.0.2",
+ "@changesets/read": "^0.6.7",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
+ "@changesets/write": "^0.4.0",
+ "@inquirer/external-editor": "^1.0.2",
+ "@manypkg/get-packages": "^1.1.3",
+ "ansi-colors": "^4.1.3",
+ "enquirer": "^2.4.1",
+ "fs-extra": "^7.0.1",
+ "mri": "^1.2.0",
+ "package-manager-detector": "^0.2.0",
+ "picocolors": "^1.1.0",
+ "resolve-from": "^5.0.0",
+ "semver": "^7.5.3",
+ "spawndamnit": "^3.0.1",
+ "term-size": "^2.1.0"
+ },
+ "bin": {
+ "changeset": "bin.js"
}
},
- "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=="
+ "node_modules/@changesets/config": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.4.tgz",
+ "integrity": "sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/errors": "^0.2.0",
+ "@changesets/get-dependents-graph": "^2.1.4",
+ "@changesets/logger": "^0.1.1",
+ "@changesets/should-skip-package": "^0.1.2",
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "fs-extra": "^7.0.1",
+ "micromatch": "^4.0.8"
+ }
},
- "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=="
+ "node_modules/@changesets/errors": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz",
+ "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "extendable-error": "^0.1.5"
+ }
},
- "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=="
+ "node_modules/@changesets/get-dependents-graph": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.4.tgz",
+ "integrity": "sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "picocolors": "^1.1.0",
+ "semver": "^7.5.3"
+ }
},
- "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=="
+ "node_modules/@changesets/get-release-plan": {
+ "version": "4.0.16",
+ "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.16.tgz",
+ "integrity": "sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/assemble-release-plan": "^6.0.10",
+ "@changesets/config": "^3.1.4",
+ "@changesets/pre": "^2.0.2",
+ "@changesets/read": "^0.6.7",
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3"
+ }
},
- "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=="
+ "node_modules/@changesets/get-version-range-type": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz",
+ "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/@types/node": {
- "version": "24.2.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
- "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
+ "node_modules/@changesets/git": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz",
+ "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "undici-types": "~7.10.0"
+ "@changesets/errors": "^0.2.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "is-subdir": "^1.1.1",
+ "micromatch": "^4.0.8",
+ "spawndamnit": "^3.0.1"
}
},
- "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==",
- "engines": {
- "node": ">=8"
+ "node_modules/@changesets/logger": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz",
+ "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picocolors": "^1.1.0"
}
},
- "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==",
+ "node_modules/@changesets/parse": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.3.tgz",
+ "integrity": "sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ "@changesets/types": "^6.1.0",
+ "js-yaml": "^4.1.1"
}
},
- "node_modules/case-anything": {
- "version": "2.1.13",
- "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz",
- "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==",
+ "node_modules/@changesets/pre": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz",
+ "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==",
"dev": true,
- "engines": {
- "node": ">=12.13"
- },
- "funding": {
- "url": "https://github.com/sponsors/mesqueeb"
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/errors": "^0.2.0",
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3",
+ "fs-extra": "^7.0.1"
}
},
- "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==",
+ "node_modules/@changesets/read": {
+ "version": "0.6.7",
+ "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.7.tgz",
+ "integrity": "sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
+ "@changesets/git": "^3.0.4",
+ "@changesets/logger": "^0.1.1",
+ "@changesets/parse": "^0.4.3",
+ "@changesets/types": "^6.1.0",
+ "fs-extra": "^7.0.1",
+ "p-filter": "^2.1.0",
+ "picocolors": "^1.1.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==",
+ "node_modules/@changesets/should-skip-package": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz",
+ "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
+ "@changesets/types": "^6.1.0",
+ "@manypkg/get-packages": "^1.1.3"
}
},
- "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=="
+ "node_modules/@changesets/types": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz",
+ "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/detect-libc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "node_modules/@changesets/write": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz",
+ "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==",
"dev": true,
- "bin": {
- "detect-libc": "bin/detect-libc.js"
- },
+ "license": "MIT",
+ "dependencies": {
+ "@changesets/types": "^6.1.0",
+ "fs-extra": "^7.0.1",
+ "human-id": "^4.1.1",
+ "prettier": "^2.7.1"
+ }
+ },
+ "node_modules/@colors/colors": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+ "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+ "license": "MIT",
"engines": {
- "node": ">=0.10"
+ "node": ">=0.1.90"
}
},
- "node_modules/dprint-node": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz",
- "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==",
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
+ "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
+ "cpu": [
+ "ppc64"
+ ],
"dev": true,
- "dependencies": {
- "detect-libc": "^1.0.3"
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
}
},
- "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=="
- },
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
+ "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
"engines": {
- "node": ">=6"
+ "node": ">=18"
}
},
- "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==",
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
+ "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
"engines": {
- "node": "6.* || 8.* || >= 10.*"
+ "node": ">=18"
}
},
- "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==",
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
+ "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
"engines": {
- "node": ">=8"
+ "node": ">=18"
}
},
- "node_modules/lodash.camelcase": {
- "version": "4.3.0",
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
+ "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
+ "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
+ "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
+ "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
+ "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
+ "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
+ "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
+ "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
+ "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
+ "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
+ "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
+ "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
+ "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
+ "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
+ "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
+ "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
+ "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@grpc/grpc-js": {
+ "version": "1.13.3",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.3.tgz",
+ "integrity": "sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@grpc/proto-loader": "^0.7.13",
+ "@js-sdsl/ordered-map": "^4.4.2"
+ },
+ "engines": {
+ "node": ">=12.10.0"
+ }
+ },
+ "node_modules/@grpc/proto-loader": {
+ "version": "0.7.15",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
+ "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "lodash.camelcase": "^4.3.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.2.5",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@inquirer/ansi": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
+ "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/checkbox": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz",
+ "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "5.1.21",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz",
+ "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "10.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz",
+ "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "cli-width": "^4.1.0",
+ "mute-stream": "^2.0.0",
+ "signal-exit": "^4.1.0",
+ "wrap-ansi": "^6.2.0",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core/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",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@inquirer/core/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",
+ "peer": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@inquirer/core/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "4.2.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz",
+ "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/external-editor": "^1.0.3",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "4.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz",
+ "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
+ "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.1",
+ "iconv-lite": "^0.7.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
+ "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz",
+ "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "3.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz",
+ "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "4.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz",
+ "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "7.10.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz",
+ "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/checkbox": "^4.3.2",
+ "@inquirer/confirm": "^5.1.21",
+ "@inquirer/editor": "^4.2.23",
+ "@inquirer/expand": "^4.0.23",
+ "@inquirer/input": "^4.3.1",
+ "@inquirer/number": "^3.0.23",
+ "@inquirer/password": "^4.0.23",
+ "@inquirer/rawlist": "^4.1.11",
+ "@inquirer/search": "^3.2.2",
+ "@inquirer/select": "^4.4.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz",
+ "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz",
+ "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz",
+ "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz",
+ "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz",
+ "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.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==",
+ "license": "MIT"
+ },
+ "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/@manypkg/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "@types/node": "^12.7.1",
+ "find-up": "^4.1.0",
+ "fs-extra": "^8.1.0"
+ }
+ },
+ "node_modules/@manypkg/find-root/node_modules/@types/node": {
+ "version": "12.20.55",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz",
+ "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@manypkg/find-root/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/@manypkg/get-packages": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz",
+ "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "@changesets/types": "^4.0.1",
+ "@manypkg/find-root": "^1.1.0",
+ "fs-extra": "^8.1.0",
+ "globby": "^11.0.0",
+ "read-yaml-file": "^1.1.0"
+ }
+ },
+ "node_modules/@manypkg/get-packages/node_modules/@changesets/types": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz",
+ "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@manypkg/get-packages/node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/@nodable/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodable"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@open-draft/until": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz",
+ "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==",
+ "license": "MIT"
+ },
+ "node_modules/@percy/appium-app": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@percy/appium-app/-/appium-app-2.1.0.tgz",
+ "integrity": "sha512-XVigKgAcXEerIch3Ufngac07gOH4KnfTDp/xyPujDyjvAZSWfIyIRnojmfbLEs2HnZEnmFFoEMX6ZB4Tk0SO/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@percy/sdk-utils": "^1.30.9",
+ "tmp": "^0.2.3"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@percy/sdk-utils": {
+ "version": "1.31.14",
+ "resolved": "https://registry.npmjs.org/@percy/sdk-utils/-/sdk-utils-1.31.14.tgz",
+ "integrity": "sha512-I31GM+aCHiME12jX9ac5COThZWOpTBONkR9J6D059wqiFhHtRenA2mWFx6rC+zUpG5un0imkal7tN9y1D4hPBg==",
+ "license": "MIT",
+ "dependencies": {
+ "pac-proxy-agent": "^7.0.2"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@percy/selenium-webdriver": {
+ "version": "2.2.6",
+ "resolved": "https://registry.npmjs.org/@percy/selenium-webdriver/-/selenium-webdriver-2.2.6.tgz",
+ "integrity": "sha512-5aeJh3ncYQl1Ug8/eazae8Ux281cvUX87e5YvHTFnLKtELaqJEb2k0NoNZbnWpPgAdz7yxeZZgTEbDn9HTOSYA==",
+ "license": "MIT",
+ "dependencies": {
+ "@percy/sdk-utils": "^1.31.10",
+ "node-request-interceptor": "^0.6.3"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@promptbook/utils": {
+ "version": "0.69.5",
+ "resolved": "https://registry.npmjs.org/@promptbook/utils/-/utils-0.69.5.tgz",
+ "integrity": "sha512-xm5Ti/Hp3o4xHrsK9Yy3MS6KbDxYbq485hDsFvxqaNA7equHLPdo8H8faTitTeb14QCDfLW4iwCxdVYu5sn6YQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://buymeacoffee.com/hejny"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/webgptorg/promptbook/blob/main/README.md#%EF%B8%8F-contributing"
+ }
+ ],
+ "license": "CC-BY-4.0",
+ "dependencies": {
+ "spacetrim": "0.11.59"
+ }
+ },
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz",
+ "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz",
+ "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz",
+ "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1"
+ }
+ },
+ "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/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz",
+ "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@puppeteer/browsers": {
+ "version": "2.13.2",
+ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz",
+ "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "debug": "^4.4.3",
+ "extract-zip": "^2.0.1",
+ "progress": "^2.0.3",
+ "proxy-agent": "^6.5.0",
+ "semver": "^7.7.4",
+ "tar-fs": "^3.1.1",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "browsers": "lib/cjs/main-cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz",
+ "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz",
+ "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz",
+ "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz",
+ "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz",
+ "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz",
+ "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz",
+ "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz",
+ "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz",
+ "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz",
+ "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz",
+ "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz",
+ "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz",
+ "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz",
+ "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz",
+ "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz",
+ "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz",
+ "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz",
+ "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz",
+ "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz",
+ "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz",
+ "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz",
+ "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz",
+ "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz",
+ "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz",
+ "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/chai": {
+ "version": "5.2.3",
+ "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
+ "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/deep-eql": "*",
+ "assertion-error": "^2.0.1"
+ }
+ },
+ "node_modules/@types/deep-eql": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+ "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/gitconfiglocal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/gitconfiglocal/-/gitconfiglocal-2.0.3.tgz",
+ "integrity": "sha512-W6hyZux6TrtKfF2I9XNLVcsFr4xRr0T+S6hrJ9nDkhA2vzsFPIEAbnY4vgb6v2yKXQ9MJVcbLsARNlMfg4EVtQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "25.9.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz",
+ "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": ">=7.24.0 <7.24.7"
+ }
+ },
+ "node_modules/@types/node/node_modules/undici-types": {
+ "version": "7.24.6",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
+ "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+ "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@types/sinonjs__fake-timers": {
+ "version": "8.1.5",
+ "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz",
+ "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/tar": {
+ "version": "7.0.87",
+ "resolved": "https://registry.npmjs.org/@types/tar/-/tar-7.0.87.tgz",
+ "integrity": "sha512-3IxNBV8LeY5oi2ZFpvAhOtW1+mHswkzM7BuisVrwJgPv67GBO2rkLPQlEKtzfHuLdhDDczhkCZeT+RuizMay4A==",
+ "deprecated": "This is a stub types definition. tar provides its own type definitions, so you do not need this installed.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tar": "*"
+ }
+ },
+ "node_modules/@types/triple-beam": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/ws": {
+ "version": "8.18.1",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/yauzl": {
+ "version": "2.10.3",
+ "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+ "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz",
+ "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "3.2.6",
+ "@vitest/utils": "3.2.6",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/mocker": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz",
+ "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "3.2.6",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.17"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/pretty-format": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz",
+ "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz",
+ "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "3.2.6",
+ "pathe": "^2.0.3",
+ "strip-literal": "^3.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz",
+ "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.6",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz",
+ "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^4.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz",
+ "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.6",
+ "loupe": "^3.1.4",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@wdio/browserstack-service": {
+ "resolved": "packages/browserstack-service",
+ "link": true
+ },
+ "node_modules/@wdio/cli": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-9.28.0.tgz",
+ "integrity": "sha512-jEKYdCvZ9ST8YQ4EvyV9lsEoRxhWenplGJppbiH9SKHiwPqrUapi/EE7f6CBDwkWP7NIlzj2PyTe+JRmkXILLw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vitest/snapshot": "^2.1.1",
+ "@wdio/config": "9.28.0",
+ "@wdio/globals": "9.28.0",
+ "@wdio/logger": "9.18.0",
+ "@wdio/protocols": "9.28.0",
+ "@wdio/types": "9.28.0",
+ "@wdio/utils": "9.28.0",
+ "async-exit-hook": "^2.0.1",
+ "chalk": "^5.4.1",
+ "chokidar": "^4.0.0",
+ "create-wdio": "9.28.0",
+ "dotenv": "^17.2.0",
+ "import-meta-resolve": "^4.0.0",
+ "lodash.flattendeep": "^4.4.0",
+ "lodash.pickby": "^4.6.0",
+ "lodash.union": "^4.6.0",
+ "read-pkg-up": "^10.0.0",
+ "tsx": "^4.7.2",
+ "webdriverio": "9.28.0",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "wdio": "bin/wdio.js"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/cli/node_modules/@vitest/pretty-format": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz",
+ "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@wdio/cli/node_modules/@vitest/snapshot": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz",
+ "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "magic-string": "^0.30.12",
+ "pathe": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@wdio/cli/node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@wdio/cli/node_modules/tinyrainbow": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@wdio/config": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.28.0.tgz",
+ "integrity": "sha512-a2po2x0Gi0hNRCuqSYSAvgwC9RZsj1tH9mt4MeLk2hyJBQCyy9DjBBjwyd4AcnE11XhqVaIkMaIMBSRu2dJwLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@wdio/logger": "9.18.0",
+ "@wdio/types": "9.28.0",
+ "@wdio/utils": "9.28.0",
+ "deepmerge-ts": "^7.0.3",
+ "glob": "^10.2.2",
+ "import-meta-resolve": "^4.0.0",
+ "jiti": "^2.6.1"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/@wdio/config/node_modules/brace-expansion": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
+ "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
+ },
+ "node_modules/@wdio/config/node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
+ "node_modules/@wdio/config/node_modules/minimatch": {
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@wdio/config/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@wdio/globals": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-9.28.0.tgz",
+ "integrity": "sha512-poYsF7Gbm8kfYX6tdsPG862anOQKyUT8roe+rwdXaKSorz/s4XDJBm4kJiid6LgWKeAMSXDYzFODzDxhYhugWg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.20.0"
+ },
+ "peerDependencies": {
+ "expect-webdriverio": "^5.6.5",
+ "webdriverio": "^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "expect-webdriverio": {
+ "optional": false
+ },
+ "webdriverio": {
+ "optional": false
+ }
+ }
+ },
+ "node_modules/@wdio/logger": {
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-9.18.0.tgz",
+ "integrity": "sha512-HdzDrRs+ywAqbXGKqe1i/bLtCv47plz4TvsHFH3j729OooT5VH38ctFn5aLXgECmiAKDkmH/A6kOq2Zh5DIxww==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^5.1.2",
+ "loglevel": "^1.6.0",
+ "loglevel-plugin-prefix": "^0.8.4",
+ "safe-regex2": "^5.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/protocols": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.28.0.tgz",
+ "integrity": "sha512-bO9NeMCrtwfWI7q77GwfD68NlRNijnmwicW1OQ6p+7D3kZWEicfdhfvojPhjjf+e9XzqMDnUDGD5ni1lGMUBsg==",
+ "license": "MIT"
+ },
+ "node_modules/@wdio/repl": {
+ "version": "9.16.2",
+ "resolved": "https://registry.npmjs.org/@wdio/repl/-/repl-9.16.2.tgz",
+ "integrity": "sha512-FLTF0VL6+o5BSTCO7yLSXocm3kUnu31zYwzdsz4n9s5YWt83sCtzGZlZpt7TaTzb3jVUfxuHNQDTb8UMkCu0lQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "^20.1.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/repl/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@wdio/reporter": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/reporter/-/reporter-9.28.0.tgz",
+ "integrity": "sha512-q9gG6SXNTn/9cKF6EJ+aa5sGZM5HAVNsDZ3YU5B0IHg9ufdBuJgfT0LiAsnehLiceEuivuzPyz85vbDb0SFiVA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "^20.1.0",
+ "@wdio/logger": "9.18.0",
+ "@wdio/types": "9.28.0",
+ "diff": "^8.0.2",
+ "object-inspect": "^1.12.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/reporter/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@wdio/types": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.28.0.tgz",
+ "integrity": "sha512-75JPq39gifkPNqOSn5C4/A5ZSyXwF+dGr5jfsCubFN9Lk9dKBXfjdbWueSQNpJg0jmE6dVrbT7+9mnDNnO0HdQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "^20.1.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@wdio/types/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@wdio/utils": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.28.0.tgz",
+ "integrity": "sha512-VDqUaXpR8oOZSs26dy06Y2LhmA8bldsXDHeZ36n8SfW+Bq0miG0RRxou7aqx7sifVbbsuxrbBPXvmK+40uAIbQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@puppeteer/browsers": "^2.2.0",
+ "@wdio/logger": "9.18.0",
+ "@wdio/types": "9.28.0",
+ "decamelize": "^6.0.0",
+ "deepmerge-ts": "^7.0.3",
+ "edgedriver": "^6.1.2",
+ "geckodriver": "^6.1.0",
+ "get-port": "^7.0.0",
+ "import-meta-resolve": "^4.0.0",
+ "locate-app": "^2.2.24",
+ "mitt": "^3.0.1",
+ "safaridriver": "^1.0.0",
+ "split2": "^4.2.0",
+ "wait-port": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ }
+ },
+ "node_modules/@zip.js/zip.js": {
+ "version": "2.8.26",
+ "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.26.tgz",
+ "integrity": "sha512-RQ4h9F6DOiHxpdocUDrOl6xBM+yOtz+LkUol47AVWcfebGBDpZ7w7Xvz9PS24JgXvLGiXXzSAfdCdVy1tPlaFA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "bun": ">=0.7.0",
+ "deno": ">=1.0.0",
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "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/anynum": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.0.tgz",
+ "integrity": "sha512-xjR9/zBVnUOP6ztMIIgShjsxui80nQUQH+5xJnvrYLs+90bF25/KJqaAi8mk+B4RDtX1Nspi6fmp4YTEts8SfA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/archiver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+ "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.2",
+ "async": "^3.2.4",
+ "buffer-crc32": "^1.0.0",
+ "readable-stream": "^4.0.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^6.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+ "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^10.0.0",
+ "graceful-fs": "^4.2.0",
+ "is-stream": "^2.0.1",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/archiver-utils/node_modules/brace-expansion": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
+ "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
+ },
+ "node_modules/archiver-utils/node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
+ "node_modules/archiver-utils/node_modules/minimatch": {
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+ "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "license": "MIT"
+ },
+ "node_modules/async-exit-hook": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
+ "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.0.tgz",
+ "integrity": "sha512-E32NzpYKp++W7XRe52rHiXV2ehxmh3wbdgO7MHeFM+vqxLBYHzt0ElkiImtOBxtOmyp0yoC8C6uESVV84Y2/hw==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.16.0",
+ "form-data": "^4.0.5",
+ "https-proxy-agent": "^5.0.1",
+ "proxy-from-env": "^2.1.0"
+ }
+ },
+ "node_modules/b4a": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
+ "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/bare-events": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz",
+ "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "bare-abort-controller": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-fs": {
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz",
+ "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.5.4",
+ "bare-path": "^3.0.0",
+ "bare-stream": "^2.6.4",
+ "bare-url": "^2.2.2",
+ "fast-fifo": "^1.3.2"
+ },
+ "engines": {
+ "bare": ">=1.16.0"
+ },
+ "peerDependencies": {
+ "bare-buffer": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-os": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz",
+ "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "bare": ">=1.14.0"
+ }
+ },
+ "node_modules/bare-path": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
+ "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-os": "^3.0.1"
+ }
+ },
+ "node_modules/bare-stream": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz",
+ "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.8.1",
+ "streamx": "^2.25.0",
+ "teex": "^1.0.1"
+ },
+ "peerDependencies": {
+ "bare-abort-controller": "*",
+ "bare-buffer": "*",
+ "bare-events": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ },
+ "bare-buffer": {
+ "optional": true
+ },
+ "bare-events": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/bare-url": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
+ "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-path": "^3.0.0"
+ }
+ },
+ "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/basic-ftp": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
+ "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/better-path-resolve": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
+ "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-windows": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "license": "ISC"
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserstack-local": {
+ "version": "1.5.13",
+ "resolved": "https://registry.npmjs.org/browserstack-local/-/browserstack-local-1.5.13.tgz",
+ "integrity": "sha512-7helY+Ms3ss4BtIQZTIyshdAFZSvS9A7ZpEB9stRaobeZ9BM1BkJFTuMakQNTOj78llv0+/qDI5Ak+bkGWV1xg==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^6.0.2",
+ "https-proxy-agent": "^5.0.1",
+ "is-running": "^2.1.0",
+ "tree-kill": "^1.2.2"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+ "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/case-anything": {
+ "version": "2.1.13",
+ "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz",
+ "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
+ "node_modules/chai": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
+ "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
+ "license": "MIT"
+ },
+ "node_modules/check-error": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/cheerio": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
+ "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "encoding-sniffer": "^0.2.1",
+ "htmlparser2": "^10.1.0",
+ "parse5": "^7.3.0",
+ "parse5-htmlparser2-tree-adapter": "^7.1.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^7.19.0",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/cheerio/node_modules/undici": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.2.tgz",
+ "integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "license": "ISC",
+ "peer": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "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/cliui/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/cliui/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/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/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/compress-commons": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+ "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^6.0.0",
+ "is-stream": "^2.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "license": "MIT"
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+ "license": "Apache-2.0",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+ "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/create-wdio": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/create-wdio/-/create-wdio-9.28.0.tgz",
+ "integrity": "sha512-3Oa7tGK5QA9z1bdTFonnEb3OTTyNJtI2np7YzEC6F9es+94PFsFLLn5nIWs+fhJSdoueQyLy8P2cSWBO3Ohijw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "commander": "^14.0.0",
+ "cross-spawn": "^7.0.3",
+ "ejs": "^3.1.10",
+ "execa": "^9.6.0",
+ "import-meta-resolve": "^4.1.0",
+ "inquirer": "^12.7.0",
+ "normalize-package-data": "^7.0.0",
+ "read-pkg-up": "^10.1.0",
+ "recursive-readdir": "^2.2.3",
+ "semver": "^7.6.3",
+ "type-fest": "^4.41.0",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "create-wdio": "bin/wdio.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/create-wdio/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",
+ "peer": true,
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/create-wdio/node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "license": "(MIT OR CC0-1.0)",
+ "peer": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-shorthand-properties": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/css-shorthand-properties/-/css-shorthand-properties-1.1.2.tgz",
+ "integrity": "sha512-C2AugXIpRGQTxaCW0N7n5jD/p5irUmCrwl03TrnMFBHDbdq44CFWR2zO7rK9xPN4Eo3pUxC4vQzQgbIpzrD1PQ==",
+ "license": "MIT"
+ },
+ "node_modules/css-value": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz",
+ "integrity": "sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q=="
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/csv-writer": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/csv-writer/-/csv-writer-1.6.0.tgz",
+ "integrity": "sha512-NOx7YDFWEsM/fTRAJjRpPp8t+MKRVvniAg9wQlUKx20MFrPs73WLJhFf5iteqrxNYnsy924K3Iroh3yNHeYd2g==",
+ "license": "MIT"
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "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/decamelize": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-6.0.1.tgz",
+ "integrity": "sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/deepmerge-ts": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
+ "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/degenerator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.13.4",
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/detect-indent": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz",
+ "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/diff": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "17.4.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
+ "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dprint-node": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz",
+ "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^1.0.3"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "license": "MIT"
+ },
+ "node_modules/edge-paths": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/edge-paths/-/edge-paths-3.0.5.tgz",
+ "integrity": "sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/which": "^2.0.1",
+ "which": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/shirshak55"
+ }
+ },
+ "node_modules/edgedriver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/edgedriver/-/edgedriver-6.3.0.tgz",
+ "integrity": "sha512-ggEQL+oEyIcM4nP2QC3AtCQ04o4kDNefRM3hja0odvlPSnsaxiruMxEZ93v3gDCKWYW6BXUr51PPradb+3nffw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@wdio/logger": "^9.18.0",
+ "@zip.js/zip.js": "^2.8.11",
+ "decamelize": "^6.0.1",
+ "edge-paths": "^3.0.5",
+ "fast-xml-parser": "^5.3.3",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.6",
+ "which": "^6.0.0"
+ },
+ "bin": {
+ "edgedriver": "bin/edgedriver.js"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/edgedriver/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/edgedriver/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/edgedriver/node_modules/isexe": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+ "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/edgedriver/node_modules/which": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+ "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^4.0.0"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/encoding-sniffer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
+ "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.6.3",
+ "whatwg-encoding": "^3.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+ }
+ },
+ "node_modules/encoding-sniffer/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/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/enquirer": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/enquirer/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/enquirer/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.7",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
+ "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.7",
+ "@esbuild/android-arm": "0.27.7",
+ "@esbuild/android-arm64": "0.27.7",
+ "@esbuild/android-x64": "0.27.7",
+ "@esbuild/darwin-arm64": "0.27.7",
+ "@esbuild/darwin-x64": "0.27.7",
+ "@esbuild/freebsd-arm64": "0.27.7",
+ "@esbuild/freebsd-x64": "0.27.7",
+ "@esbuild/linux-arm": "0.27.7",
+ "@esbuild/linux-arm64": "0.27.7",
+ "@esbuild/linux-ia32": "0.27.7",
+ "@esbuild/linux-loong64": "0.27.7",
+ "@esbuild/linux-mips64el": "0.27.7",
+ "@esbuild/linux-ppc64": "0.27.7",
+ "@esbuild/linux-riscv64": "0.27.7",
+ "@esbuild/linux-s390x": "0.27.7",
+ "@esbuild/linux-x64": "0.27.7",
+ "@esbuild/netbsd-arm64": "0.27.7",
+ "@esbuild/netbsd-x64": "0.27.7",
+ "@esbuild/openbsd-arm64": "0.27.7",
+ "@esbuild/openbsd-x64": "0.27.7",
+ "@esbuild/openharmony-arm64": "0.27.7",
+ "@esbuild/sunos-x64": "0.27.7",
+ "@esbuild/win32-arm64": "0.27.7",
+ "@esbuild/win32-ia32": "0.27.7",
+ "@esbuild/win32-x64": "0.27.7"
+ }
+ },
+ "node_modules/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/escodegen": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "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==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.7.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
+ "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "figures": "^6.1.0",
+ "get-stream": "^9.0.0",
+ "human-signals": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "is-stream": "^4.0.1",
+ "npm-run-path": "^6.0.0",
+ "pretty-ms": "^9.2.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^4.0.0",
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.5.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/execa/node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/execa/node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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/extendable-error": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz",
+ "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/extract-zip": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+ "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "get-stream": "^5.1.0",
+ "yauzl": "^2.10.0"
+ },
+ "bin": {
+ "extract-zip": "cli.js"
+ },
+ "engines": {
+ "node": ">= 10.17.0"
+ },
+ "optionalDependencies": {
+ "@types/yauzl": "^2.9.1"
+ }
+ },
+ "node_modules/extract-zip/node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/extract-zip/node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==",
+ "license": "MIT"
+ },
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-xml-builder": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz",
+ "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "path-expression-matcher": "^1.5.0",
+ "xml-naming": "^0.1.0"
+ }
+ },
+ "node_modules/fast-xml-parser": {
+ "version": "5.9.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.9.0.tgz",
+ "integrity": "sha512-duBuXbyIhEeNO4GjFuVqr0nF047oNwr18aum+zJyqo0MUG/n7Afgs3Qv3D6VN3ONedUKxiuFlPiMGIa0Z11chA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@nodable/entities": "^2.2.0",
+ "fast-xml-builder": "^1.2.0",
+ "is-unsafe": "^1.0.1",
+ "path-expression-matcher": "^1.5.0",
+ "strnum": "^2.4.0",
+ "xml-naming": "^0.1.0"
+ },
+ "bin": {
+ "fxparser": "src/cli/cli.js"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ }
+ },
+ "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/fecha": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+ "license": "MIT"
+ },
+ "node_modules/figures": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+ "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/filelist": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz",
+ "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/filelist/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/filelist/node_modules/brace-expansion": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
+ "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/filelist/node_modules/minimatch": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+ "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+ "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+ "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.4",
+ "mime-types": "^2.1.35"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
+ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "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/geckodriver": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.0.tgz",
+ "integrity": "sha512-ZRXLa4ZaYTTgUO4Eefw+RsQCleugU2QLb1ME7qTYxxuRj51yAhfnXaItXNs5/vUzfIaDHuZ+YnSF005hfp07nQ==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@wdio/logger": "^9.18.0",
+ "@zip.js/zip.js": "^2.8.11",
+ "decamelize": "^6.0.1",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.6",
+ "modern-tar": "^0.7.2"
+ },
+ "bin": {
+ "geckodriver": "bin/geckodriver.js"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/geckodriver/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/geckodriver/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/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-port": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.2.0.tgz",
+ "integrity": "sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/get-uri": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz",
+ "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==",
+ "license": "MIT",
+ "dependencies": {
+ "basic-ftp": "^5.0.2",
+ "data-uri-to-buffer": "^6.0.2",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/git-repo-info": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/git-repo-info/-/git-repo-info-2.1.1.tgz",
+ "integrity": "sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/gitconfiglocal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-2.1.0.tgz",
+ "integrity": "sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg==",
+ "license": "BSD",
+ "dependencies": {
+ "ini": "^1.3.2"
+ }
+ },
+ "node_modules/glob": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+ "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "foreground-child": "^3.3.1",
+ "jackspeak": "^4.1.1",
+ "minimatch": "^10.1.1",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^2.0.0"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/grapheme-splitter": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+ "license": "MIT"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
+ "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/headers-utils": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/headers-utils/-/headers-utils-1.2.5.tgz",
+ "integrity": "sha512-DAzV5P/pk3wTU/8TLZN+zFTDv4Xa1QDTU8pRvovPetcOMbmqq8CwsAvZBLPZHH6usxyy31zMp7I4aCYb6XIf6w==",
+ "license": "MIT"
+ },
+ "node_modules/hosted-git-info": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz",
+ "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==",
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/hosted-git-info/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/htmlfy": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/htmlfy/-/htmlfy-0.8.1.tgz",
+ "integrity": "sha512-xWROBw9+MEGwxpotll0h672KCaLrKKiCYzsyN8ZgL9cQbVumFnyvsk2JqiB9ELAV1GLj1GG/jxZUjV9OZZi/yQ==",
+ "license": "MIT"
+ },
+ "node_modules/htmlparser2": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz",
+ "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "entities": "^7.0.1"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/entities": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz",
+ "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/http-proxy-agent/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/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/human-id": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.2.0.tgz",
+ "integrity": "sha512-K3GbkIWqyvvlpfhBPlbEvD97TtqBpAYA4kt+cn2lD2x2HuohzZCibcA2nOlnJT6exqvJLggoB5nv2dNf192nEA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "human-id": "dist/cli.js"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
+ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "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/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
+ "node_modules/import-meta-resolve": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz",
+ "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
+ "node_modules/inquirer": {
+ "version": "12.11.1",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz",
+ "integrity": "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/prompts": "^7.10.1",
+ "@inquirer/type": "^3.0.10",
+ "mute-stream": "^2.0.0",
+ "run-async": "^4.0.6",
+ "rxjs": "^7.8.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ip-address": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
+ "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "license": "MIT",
+ "peer": true
+ },
+ "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-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-running": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz",
+ "integrity": "sha512-mjJd3PujZMl7j+D395WTIO5tU5RIDBfVSRtRR4VOJou3H66E38UjbjvDGh3slJzPuolsb+yQFqwHNNdyp5jg3w==",
+ "license": "BSD"
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-subdir": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz",
+ "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "better-path-resolve": "1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-unsafe": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-1.0.1.tgz",
+ "integrity": "sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/jackspeak": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz",
+ "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^9.0.0"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/jake": {
+ "version": "10.9.4",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
+ "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "async": "^3.2.6",
+ "filelist": "^1.0.4",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
+ "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz",
+ "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "license": "(MIT OR GPL-3.0-or-later)",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "node_modules/jszip/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/jszip/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/jszip/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lazystream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/lazystream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/lazystream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz",
+ "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/locate-app": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/locate-app/-/locate-app-2.5.0.tgz",
+ "integrity": "sha512-xIqbzPMBYArJRmPGUZD9CzV9wOqmVtQnaAn3wrj3s6WYW0bQvPI7x+sPYUGmDTYMHefVK//zc6HEYZ1qnxIK+Q==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://buymeacoffee.com/hejny"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/hejny/locate-app/blob/main/README.md#%EF%B8%8F-contributing"
+ }
+ ],
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@promptbook/utils": "0.69.5",
+ "type-fest": "4.26.0",
+ "userhome": "1.0.1"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.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=="
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+ "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.flattendeep": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
+ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/lodash.pickby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.pickby/-/lodash.pickby-4.6.0.tgz",
+ "integrity": "sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/lodash.startcase": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz",
+ "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.union": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/lodash.zip": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz",
+ "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==",
+ "license": "MIT"
+ },
+ "node_modules/logform": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
+ "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@colors/colors": "1.6.0",
+ "@types/triple-beam": "^1.3.2",
+ "fecha": "^4.2.0",
+ "ms": "^2.1.1",
+ "safe-stable-stringify": "^2.3.1",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/loglevel": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz",
+ "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ },
+ "funding": {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/loglevel"
+ }
+ },
+ "node_modules/loglevel-plugin-prefix": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz",
+ "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==",
+ "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/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "11.5.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
+ "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+ "license": "MIT"
+ },
+ "node_modules/modern-tar": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.6.tgz",
+ "integrity": "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/mute-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
+ "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
+ "license": "ISC",
+ "peer": true,
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.12",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/netmask": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz",
+ "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/node-request-interceptor": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/node-request-interceptor/-/node-request-interceptor-0.6.3.tgz",
+ "integrity": "sha512-8I2V7H2Ch0NvW7qWcjmS0/9Lhr0T6x7RD6PDirhvWEkUQvy83x8BA4haYMr09r/rig7hcgYSjYh6cd4U7G1vLA==",
+ "license": "MIT",
+ "dependencies": {
+ "@open-draft/until": "^1.0.3",
+ "debug": "^4.3.0",
+ "headers-utils": "^1.2.0",
+ "strict-event-emitter": "^0.1.0"
+ }
+ },
+ "node_modules/normalize-package-data": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.1.tgz",
+ "integrity": "sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "hosted-git-info": "^8.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-license": "^3.0.4"
+ },
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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/outdent": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz",
+ "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/p-filter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
+ "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-map": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-map": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+ "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pac-proxy-agent": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
+ "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "get-uri": "^6.0.1",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.6",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-proxy-agent/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/pac-proxy-agent/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/pac-resolver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "license": "MIT",
+ "dependencies": {
+ "degenerator": "^5.0.0",
+ "netmask": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/package-manager-detector": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz",
+ "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "quansync": "^0.2.7"
+ }
+ },
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "license": "(MIT AND Zlib)"
+ },
+ "node_modules/parse-json": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-7.1.1.tgz",
+ "integrity": "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.21.4",
+ "error-ex": "^1.3.2",
+ "json-parse-even-better-errors": "^3.0.0",
+ "lines-and-columns": "^2.0.3",
+ "type-fest": "^3.8.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-json/node_modules/type-fest": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz",
+ "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==",
+ "license": "(MIT OR CC0-1.0)",
+ "peer": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+ "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+ "license": "MIT",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-parser-stream": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+ "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+ "license": "MIT",
+ "dependencies": {
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-expression-matcher": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz",
+ "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/pathval": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
+ "node_modules/pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.15",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
+ "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/pretty-ms": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
+ "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "license": "MIT"
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/protobufjs": {
+ "version": "7.6.4",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.4.tgz",
+ "integrity": "sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.5",
+ "@protobufjs/eventemitter": "^1.1.1",
+ "@protobufjs/fetch": "^1.1.1",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.1",
+ "@types/node": ">=13.7.0",
+ "long": "^5.3.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/proxy-agent": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
+ "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.6",
+ "lru-cache": "^7.14.1",
+ "pac-proxy-agent": "^7.1.0",
+ "proxy-from-env": "^1.1.0",
+ "socks-proxy-agent": "^8.0.5"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-agent/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/proxy-agent/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/proxy-agent/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/proxy-agent/node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-from-env": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
+ "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/quansync": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
+ "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/antfu"
+ },
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/query-selector-shadow-dom": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/query-selector-shadow-dom/-/query-selector-shadow-dom-1.0.1.tgz",
+ "integrity": "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==",
+ "license": "MIT"
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "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/read-pkg": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-8.1.0.tgz",
+ "integrity": "sha512-PORM8AgzXeskHO/WEv312k9U03B8K9JSiWF/8N9sUuFjBa+9SF2u6K7VClzXwDXab51jCd8Nd36CNM+zR97ScQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.1",
+ "normalize-package-data": "^6.0.0",
+ "parse-json": "^7.0.0",
+ "type-fest": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-10.1.0.tgz",
+ "integrity": "sha512-aNtBq4jR8NawpKJQldrQcSW9y/d+KWH4v24HWkHljOZ7H0av+YTGANBzRh9A5pw7v/bLVsLVPpOhJ7gHNVy8lA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "find-up": "^6.3.0",
+ "read-pkg": "^8.1.0",
+ "type-fest": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/find-up": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
+ "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "locate-path": "^7.1.0",
+ "path-exists": "^5.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/locate-path": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+ "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "p-locate": "^6.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-limit": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+ "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "yocto-queue": "^1.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-locate": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+ "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "p-limit": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/path-exists": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/read-pkg/node_modules/hosted-git-info": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+ "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "lru-cache": "^10.0.1"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/read-pkg/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC",
+ "peer": true
+ },
+ "node_modules/read-pkg/node_modules/normalize-package-data": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
+ "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "hosted-git-info": "^7.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-license": "^3.0.4"
+ },
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/read-yaml-file": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz",
+ "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.1.5",
+ "js-yaml": "^3.6.1",
+ "pify": "^4.0.1",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/read-yaml-file/node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/read-yaml-file/node_modules/js-yaml": {
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/readdir-glob/node_modules/brace-expansion": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
+ "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+ "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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",
+ "peer": true,
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/recursive-readdir": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz",
+ "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/recursive-readdir/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/recursive-readdir/node_modules/brace-expansion": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
+ "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/recursive-readdir/node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "peer": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "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/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resq": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/resq/-/resq-1.11.0.tgz",
+ "integrity": "sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^2.0.1"
+ }
+ },
+ "node_modules/ret": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
+ "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rgb2hex": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.2.5.tgz",
+ "integrity": "sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==",
+ "license": "MIT"
+ },
+ "node_modules/rimraf": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz",
+ "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "glob": "^13.0.3",
+ "package-json-from-dist": "^1.0.1"
+ },
+ "bin": {
+ "rimraf": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+ "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "minimatch": "^10.2.2",
+ "minipass": "^7.1.3",
+ "path-scurry": "^2.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.62.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz",
+ "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.9"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.62.0",
+ "@rollup/rollup-android-arm64": "4.62.0",
+ "@rollup/rollup-darwin-arm64": "4.62.0",
+ "@rollup/rollup-darwin-x64": "4.62.0",
+ "@rollup/rollup-freebsd-arm64": "4.62.0",
+ "@rollup/rollup-freebsd-x64": "4.62.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.62.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.62.0",
+ "@rollup/rollup-linux-arm64-musl": "4.62.0",
+ "@rollup/rollup-linux-loong64-gnu": "4.62.0",
+ "@rollup/rollup-linux-loong64-musl": "4.62.0",
+ "@rollup/rollup-linux-ppc64-gnu": "4.62.0",
+ "@rollup/rollup-linux-ppc64-musl": "4.62.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.62.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.62.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.62.0",
+ "@rollup/rollup-linux-x64-gnu": "4.62.0",
+ "@rollup/rollup-linux-x64-musl": "4.62.0",
+ "@rollup/rollup-openbsd-x64": "4.62.0",
+ "@rollup/rollup-openharmony-arm64": "4.62.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.62.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.62.0",
+ "@rollup/rollup-win32-x64-gnu": "4.62.0",
+ "@rollup/rollup-win32-x64-msvc": "4.62.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz",
+ "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/safaridriver": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/safaridriver/-/safaridriver-1.0.1.tgz",
+ "integrity": "sha512-jkg4434cYgtrIF2AeY/X0Wmd2W73cK5qIEFE3hDrrQenJH/2SDJIXGvPAigfvQTcE9+H31zkiNHbUqcihEiMRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "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-regex2": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz",
+ "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "ret": "~0.5.0"
+ },
+ "bin": {
+ "safe-regex2": "bin/safe-regex2.js"
+ }
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz",
+ "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/serialize-error": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-12.0.0.tgz",
+ "integrity": "sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^4.31.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/serialize-error/node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz",
+ "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==",
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^10.1.1",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
+ "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/socks-proxy-agent/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/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",
+ "optional": true,
+ "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==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/spacetrim": {
+ "version": "0.11.59",
+ "resolved": "https://registry.npmjs.org/spacetrim/-/spacetrim-0.11.59.tgz",
+ "integrity": "sha512-lLYsktklSRKprreOm7NXReW8YiX2VBjbgmXYEziOoGf/qsJqAEACaDvoTtUOycwjpaSh+bT8eu0KrJn7UNxiCg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://buymeacoffee.com/hejny"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/hejny/spacetrim/blob/main/README.md#%EF%B8%8F-contributing"
+ }
+ ],
+ "license": "Apache-2.0"
+ },
+ "node_modules/spawndamnit": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz",
+ "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==",
+ "dev": true,
+ "license": "SEE LICENSE IN LICENSE",
+ "dependencies": {
+ "cross-spawn": "^7.0.5",
+ "signal-exit": "^4.0.1"
+ }
+ },
+ "node_modules/spdx-correct": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+ "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+ "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+ "license": "CC-BY-3.0",
+ "peer": true
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.23",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz",
+ "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==",
+ "license": "CC0-1.0",
+ "peer": true
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "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/std-env": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/streamx": {
+ "version": "2.28.0",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz",
+ "integrity": "sha512-1Yowhzjf0ivGMrTIkY9hav5TxobO9qIVqUE41fiCGMGgc3CLlf4MY+9AHmZqBWgDTue0fY9zWjYFVyf6Diuobw==",
+ "license": "MIT",
+ "dependencies": {
+ "events-universal": "^1.0.0",
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ }
+ },
+ "node_modules/strict-event-emitter": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.1.0.tgz",
+ "integrity": "sha512-8hSYfU+WKLdNcHVXJ0VxRXiPESalzRe7w1l8dg9+/22Ry+iZQUoQuoJ27R30GMD1TiyYINWsIEGY05WrskhSKw==",
+ "license": "MIT"
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/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-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "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-ansi-cjs/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/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+ "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-literal": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz",
+ "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^9.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/strnum": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.0.tgz",
+ "integrity": "sha512-sHrVyWWdq28RbhjuJdZsA1SnGRJV6NiXbk6AXBxDOsgAcA+lmpUZCYjOdLBxkXMwis6RRe7dlZt4VlIWFVzkmg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "anynum": "^1.0.0"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.5.16",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz",
+ "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz",
+ "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0",
+ "tar-stream": "^3.1.5"
+ },
+ "optionalDependencies": {
+ "bare-fs": "^4.0.1",
+ "bare-path": "^3.0.0"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz",
+ "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==",
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "bare-fs": "^4.5.5",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/teex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+ "license": "MIT",
+ "dependencies": {
+ "streamx": "^2.12.5"
+ }
+ },
+ "node_modules/term-size": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
+ "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/text-decoder": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
+ "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
+ "node_modules/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": "0.3.2",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+ "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "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/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/tinypool": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ }
+ },
+ "node_modules/tinyrainbow": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
+ "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tmp": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
+ "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/triple-beam": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+ "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.0.0"
+ }
+ },
+ "node_modules/ts-poet": {
+ "version": "6.12.0",
+ "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz",
+ "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "dprint-node": "^1.0.8"
+ }
+ },
+ "node_modules/ts-proto": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.11.8.tgz",
+ "integrity": "sha512-+5hzECnyVB33jxjG1BIdzAHcRBm7hjnm8womdJVp2A7xJWihP0drHHVsXYTr9i/LpWNGfh80I+AVVNzFM5AwJw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.10.2",
+ "case-anything": "^2.1.13",
+ "ts-poet": "^6.12.0",
+ "ts-proto-descriptors": "2.1.0"
+ },
+ "bin": {
+ "protoc-gen-ts_proto": "protoc-gen-ts_proto"
+ }
+ },
+ "node_modules/ts-proto-descriptors": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz",
+ "integrity": "sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.0.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/tsx": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz",
+ "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "esbuild": "~0.28.0"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
+ "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
+ "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
+ "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/android-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
+ "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
+ "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
+ "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
+ "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
+ "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
+ "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
+ "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
+ "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
+ "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
+ "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
+ "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/linux-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
+ "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
+ "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
+ "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
+ "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
+ "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/@esbuild/win32-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
+ "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tsx/node_modules/esbuild": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
+ "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.1",
+ "@esbuild/android-arm": "0.28.1",
+ "@esbuild/android-arm64": "0.28.1",
+ "@esbuild/android-x64": "0.28.1",
+ "@esbuild/darwin-arm64": "0.28.1",
+ "@esbuild/darwin-x64": "0.28.1",
+ "@esbuild/freebsd-arm64": "0.28.1",
+ "@esbuild/freebsd-x64": "0.28.1",
+ "@esbuild/linux-arm": "0.28.1",
+ "@esbuild/linux-arm64": "0.28.1",
+ "@esbuild/linux-ia32": "0.28.1",
+ "@esbuild/linux-loong64": "0.28.1",
+ "@esbuild/linux-mips64el": "0.28.1",
+ "@esbuild/linux-ppc64": "0.28.1",
+ "@esbuild/linux-riscv64": "0.28.1",
+ "@esbuild/linux-s390x": "0.28.1",
+ "@esbuild/linux-x64": "0.28.1",
+ "@esbuild/netbsd-arm64": "0.28.1",
+ "@esbuild/netbsd-x64": "0.28.1",
+ "@esbuild/openbsd-arm64": "0.28.1",
+ "@esbuild/openbsd-x64": "0.28.1",
+ "@esbuild/openharmony-arm64": "0.28.1",
+ "@esbuild/sunos-x64": "0.28.1",
+ "@esbuild/win32-arm64": "0.28.1",
+ "@esbuild/win32-ia32": "0.28.1",
+ "@esbuild/win32-x64": "0.28.1"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "4.26.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.0.tgz",
+ "integrity": "sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==",
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz",
+ "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.17"
+ }
+ },
+ "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/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/urlpattern-polyfill": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz",
+ "integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==",
+ "license": "MIT"
+ },
+ "node_modules/userhome": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/userhome/-/userhome-1.0.1.tgz",
+ "integrity": "sha512-5cnLm4gseXjAclKowC4IjByaGsjtAoV6PrOQOljplNB54ReUYJP8HdAFq2muHinSDAh09PPX/uXDPfdxRHvuSA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/uuid": {
+ "version": "11.1.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz",
+ "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
+ "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "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": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
+ "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.1",
+ "es-module-lexer": "^1.7.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/vite/node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz",
+ "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/expect": "3.2.6",
+ "@vitest/mocker": "3.2.6",
+ "@vitest/pretty-format": "^3.2.6",
+ "@vitest/runner": "3.2.6",
+ "@vitest/snapshot": "3.2.6",
+ "@vitest/spy": "3.2.6",
+ "@vitest/utils": "3.2.6",
+ "chai": "^5.2.0",
+ "debug": "^4.4.1",
+ "expect-type": "^1.2.1",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.2",
+ "std-env": "^3.9.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.2",
+ "tinyglobby": "^0.2.14",
+ "tinypool": "^1.1.1",
+ "tinyrainbow": "^2.0.0",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
+ "vite-node": "3.2.4",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/debug": "^4.1.12",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "@vitest/browser": "3.2.6",
+ "@vitest/ui": "3.2.6",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/debug": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
},
- "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=="
+ "node_modules/vitest/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
},
- "node_modules/protobufjs": {
- "version": "7.5.3",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz",
- "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==",
- "hasInstallScript": true,
+ "node_modules/wait-port": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/wait-port/-/wait-port-1.1.0.tgz",
+ "integrity": "sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==",
+ "license": "MIT",
"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"
+ "chalk": "^4.1.2",
+ "commander": "^9.3.0",
+ "debug": "^4.3.4"
+ },
+ "bin": {
+ "wait-port": "bin/wait-port.js"
},
"engines": {
- "node": ">=12.0.0"
+ "node": ">=10"
}
},
- "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==",
+ "node_modules/wait-port/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "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==",
+ "node_modules/webdriver": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.28.0.tgz",
+ "integrity": "sha512-MmtC/n5rhOh/EYyYI1SbRBdEWctKaQouVeEAybv5SD/2bhTjg800q7mvGqHzhTXpqTPY5cdbOtT0PBdT89wz9w==",
+ "license": "MIT",
"dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
+ "@types/node": "^20.1.0",
+ "@types/ws": "^8.5.3",
+ "@wdio/config": "9.28.0",
+ "@wdio/logger": "9.18.0",
+ "@wdio/protocols": "9.28.0",
+ "@wdio/types": "9.28.0",
+ "@wdio/utils": "9.28.0",
+ "deepmerge-ts": "^7.0.3",
+ "https-proxy-agent": "^7.0.6",
+ "undici": "^6.21.3",
+ "ws": "^8.8.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=18.20.0"
}
},
- "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==",
+ "node_modules/webdriver/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "license": "MIT",
"dependencies": {
- "ansi-regex": "^5.0.1"
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/webdriver/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/webdriver/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": ">=8"
+ "node": ">= 14"
}
},
- "node_modules/ts-poet": {
- "version": "6.12.0",
- "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz",
- "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==",
- "dev": true,
+ "node_modules/webdriverio": {
+ "version": "9.28.0",
+ "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.28.0.tgz",
+ "integrity": "sha512-ieFWi8dq57uZC6QMC2x6TllxKTRyInIMcOrVvwbHqVRYvJP8OLDtlH1bideGRIN0pgGHWStqplez2A95jS9bqA==",
+ "license": "MIT",
"dependencies": {
- "dprint-node": "^1.0.8"
+ "@types/node": "^20.11.30",
+ "@types/sinonjs__fake-timers": "^8.1.5",
+ "@wdio/config": "9.28.0",
+ "@wdio/logger": "9.18.0",
+ "@wdio/protocols": "9.28.0",
+ "@wdio/repl": "9.16.2",
+ "@wdio/types": "9.28.0",
+ "@wdio/utils": "9.28.0",
+ "archiver": "^7.0.1",
+ "aria-query": "^5.3.0",
+ "cheerio": "^1.0.0-rc.12",
+ "css-shorthand-properties": "^1.1.1",
+ "css-value": "^0.0.1",
+ "grapheme-splitter": "^1.0.4",
+ "htmlfy": "^0.8.1",
+ "is-plain-obj": "^4.1.0",
+ "jszip": "^3.10.1",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.zip": "^4.2.0",
+ "query-selector-shadow-dom": "^1.0.1",
+ "resq": "^1.11.0",
+ "rgb2hex": "0.2.5",
+ "serialize-error": "^12.0.0",
+ "urlpattern-polyfill": "^10.0.0",
+ "webdriver": "9.28.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ },
+ "peerDependencies": {
+ "puppeteer-core": ">=22.x || <=24.x"
+ },
+ "peerDependenciesMeta": {
+ "puppeteer-core": {
+ "optional": true
+ }
}
},
- "node_modules/ts-proto": {
- "version": "2.7.7",
- "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.7.7.tgz",
- "integrity": "sha512-/OfN9/Yriji2bbpOysZ/Jzc96isOKz+eBTJEcKaIZ0PR6x1TNgVm4Lz0zfbo+J0jwFO7fJjJyssefBPQ0o1V9A==",
- "dev": true,
+ "node_modules/webdriverio/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "license": "MIT",
"dependencies": {
- "@bufbuild/protobuf": "^2.0.0",
- "case-anything": "^2.1.13",
- "ts-poet": "^6.12.0",
- "ts-proto-descriptors": "2.0.0"
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
},
- "bin": {
- "protoc-gen-ts_proto": "protoc-gen-ts_proto"
+ "engines": {
+ "node": ">=18"
}
},
- "node_modules/ts-proto-descriptors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.0.0.tgz",
- "integrity": "sha512-wHcTH3xIv11jxgkX5OyCSFfw27agpInAd6yh89hKG6zqIXnjW9SYqSER2CVQxdPj4czeOhGagNvZBEbJPy7qkw==",
- "dev": true,
+ "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
"dependencies": {
- "@bufbuild/protobuf": "^2.0.0"
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
}
},
- "node_modules/typescript": {
- "version": "5.9.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
- "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/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": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
+ "why-is-node-running": "cli.js"
},
"engines": {
- "node": ">=14.17"
+ "node": ">=8"
}
},
- "node_modules/undici-types": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="
+ "node_modules/winston-transport": {
+ "version": "4.9.0",
+ "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
+ "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
+ "license": "MIT",
+ "dependencies": {
+ "logform": "^2.7.0",
+ "readable-stream": "^3.6.2",
+ "triple-beam": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/winston-transport/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
},
"node_modules/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/wrap-ansi-cjs": {
+ "name": "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",
@@ -504,18 +9274,113 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/wrap-ansi-cjs/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/wrap-ansi-cjs/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/wrap-ansi/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-naming": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz",
+ "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/NaturalIntelligence"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"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": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"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",
@@ -533,9 +9398,150 @@
"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/yauzl": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz",
+ "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==",
+ "license": "MIT",
+ "dependencies": {
+ "pend": "~1.2.0"
+ },
"engines": {
"node": ">=12"
}
+ },
+ "node_modules/yocto-queue": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz",
+ "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yoctocolors": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
+ "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yoctocolors-cjs": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
+ "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zip-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
+ "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.0",
+ "compress-commons": "^6.0.2",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "packages/browserstack-service": {
+ "name": "@wdio/browserstack-service",
+ "version": "9.28.0",
+ "license": "MIT",
+ "dependencies": {
+ "@browserstack/ai-sdk-node": "1.5.17",
+ "@browserstack/wdio-browserstack-service": "^2.0.2",
+ "@percy/appium-app": "^2.0.9",
+ "@percy/selenium-webdriver": "^2.2.2",
+ "@types/gitconfiglocal": "^2.0.1",
+ "browserstack-local": "^1.5.1",
+ "chalk": "^5.3.0",
+ "csv-writer": "^1.6.0",
+ "git-repo-info": "^2.1.1",
+ "gitconfiglocal": "^2.1.0",
+ "glob": "^11.0.0",
+ "tar": "^7.5.11",
+ "undici": "^6.24.0",
+ "uuid": "^11.1.0",
+ "winston-transport": "^4.5.0",
+ "yauzl": "^3.0.0"
+ },
+ "devDependencies": {
+ "@changesets/cli": "^2.27.9",
+ "@types/node": "^20.1.0",
+ "@types/tar": "^7.0.87",
+ "@types/yauzl": "^2.10.3",
+ "@wdio/globals": "^9.0.0",
+ "@wdio/logger": "^9.0.0",
+ "@wdio/reporter": "^9.0.0",
+ "@wdio/types": "^9.0.0",
+ "esbuild": "^0.27.2",
+ "rimraf": "^6.0.1",
+ "typescript": "^5.8.3",
+ "vitest": "^3.2.4",
+ "webdriverio": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=18.20.0"
+ },
+ "peerDependencies": {
+ "@wdio/cli": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+ "@wdio/logger": "^9.0.0",
+ "@wdio/reporter": "^9.0.0",
+ "@wdio/types": "^9.0.0",
+ "webdriverio": "^9.0.0"
+ }
+ },
+ "packages/browserstack-service/node_modules/@types/node": {
+ "version": "20.19.43",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
+ "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "packages/core": {
+ "name": "@browserstack/wdio-browserstack-service",
+ "version": "2.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "@bufbuild/protobuf": "^2.5.2",
+ "@grpc/grpc-js": "1.13.3"
+ },
+ "devDependencies": {
+ "@bufbuild/buf": "^1.55.1",
+ "ts-proto": "^2.7.5",
+ "typescript": "^5.4.5"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index b36f3d4..5a9dc85 100644
--- a/package.json
+++ b/package.json
@@ -1,47 +1,26 @@
{
- "name": "@browserstack/wdio-browserstack-service",
- "version": "2.0.2",
- "description": "WebdriverIO service for better Browserstack integration",
- "author": "Browserstack",
- "homepage": "https://github.com/browserstack/wdio-browserstack-service",
+ "name": "wdio-browserstack-service-monorepo",
+ "version": "0.0.0",
+ "private": true,
+ "description": "Monorepo: @wdio/browserstack-service (WebdriverIO service) + @browserstack/wdio-browserstack-service (gRPC/protobuf core).",
+ "license": "MIT",
"type": "module",
- "main": "dist/index.js",
"engines": {
- "node": ">=16.0.0"
- },
- "repository": {
- "type": "git",
- "url": "git://github.com/browserstack/wdio-browserstack-service.git"
+ "node": ">=18.20.0"
},
- "types": "dist/index.d.ts",
- "files": [
- "dist/**/*",
- "src/proto/**/*.proto"
+ "workspaces": [
+ "packages/*"
],
"scripts": {
- "clean": "rm -rf dist src/generated",
- "generate": "buf generate",
- "build": "npm run clean && npm run generate && tsc",
- "prepare": "npm run build",
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "keywords": [
- "browserstack",
- "proto",
- "grpc",
- "webdriverio"
- ],
- "bugs": {
- "url": "https://github.com/browserstack/wdio-browserstack-service/issues"
- },
- "license": "MIT",
- "dependencies": {
- "@bufbuild/protobuf": "^2.5.2",
- "@grpc/grpc-js": "1.13.3"
+ "build": "npm run build:core && npm run build:service",
+ "build:core": "npm run build -w @browserstack/wdio-browserstack-service",
+ "build:service": "npm run build -w @wdio/browserstack-service",
+ "test": "npm run test -w @wdio/browserstack-service",
+ "changeset": "changeset",
+ "version": "changeset version",
+ "release": "changeset publish"
},
"devDependencies": {
- "@bufbuild/buf": "^1.55.1",
- "ts-proto": "^2.7.5",
- "typescript": "^5.4.5"
+ "@changesets/cli": "^2.27.9"
}
}
diff --git a/packages/browserstack-service/.npmignore b/packages/browserstack-service/.npmignore
new file mode 100644
index 0000000..2ec2880
--- /dev/null
+++ b/packages/browserstack-service/.npmignore
@@ -0,0 +1,14 @@
+# Keep the published tarball lean: only build/, README, LICENSE and the
+# root ambient types (browserstack-service.d.ts) ship. Everything dev-only below
+# is excluded.
+src
+tests
+__mocks__
+scripts
+.changeset
+.github
+coverage
+vitest.config.ts
+tsconfig.json
+tsconfig.prod.json
+EXTRACTION.md
diff --git a/packages/browserstack-service/LICENSE b/packages/browserstack-service/LICENSE
new file mode 100644
index 0000000..2066580
--- /dev/null
+++ b/packages/browserstack-service/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) OpenJS Foundation and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/packages/browserstack-service/README.md b/packages/browserstack-service/README.md
new file mode 100644
index 0000000..cd0127d
--- /dev/null
+++ b/packages/browserstack-service/README.md
@@ -0,0 +1,359 @@
+WebdriverIO BrowserStack Service
+==========
+
+> A WebdriverIO service that manages local tunnel and job metadata for BrowserStack users.
+
+## Installation
+
+
+The easiest way is to keep `@wdio/browserstack-service` as a devDependency in your `package.json`, via:
+
+```sh
+npm install @wdio/browserstack-service --save-dev
+```
+
+Instructions on how to install `WebdriverIO` can be found [here.](https://webdriver.io/docs/gettingstarted)
+
+
+## Configuration
+
+WebdriverIO has BrowserStack support out of the box. You should set `user` and `key` in your `wdio.conf.js` file. This service plugin provides support for [BrowserStack Tunnel](https://www.browserstack.com/docs/automate/selenium/getting-started/nodejs/local-testing). Set `browserstackLocal: true` also to activate this feature.
+Reporting of session status on BrowserStack will respect `strict` setting of Cucumber options.
+
+```js
+// wdio.conf.js
+export const config = {
+ // ...
+ user: process.env.BROWSERSTACK_USERNAME,
+ key: process.env.BROWSERSTACK_ACCESS_KEY,
+ services: [
+ ['browserstack', {
+ testReporting: true,
+ testReportingOptions: {
+ projectName: "Your project name goes here",
+ buildName: "The static build job name goes here e.g. Nightly regression"
+ },
+ browserstackLocal: true
+ }]
+ ],
+ // ...
+};
+```
+
+## Options
+
+In order to authorize to the BrowserStack service your config needs to contain a [`user`](https://webdriver.io/docs/options#user) and [`key`](https://webdriver.io/docs/options#key) option.
+
+### testReporting
+
+Test Observability is an advanced test reporting tool that gives insights to improve your automation tests and helps you debug faster. It’s enabled by default by setting the `testObservability` flag as `true` for all users of browserstack-service. You can disable this by setting the `testObservability` flag to `false`.
+
+Once your tests finish running, you can visit [Test Reporting and Analytics](https://automation.browserstack.com/) to debug your builds with additional insights like Unique Error Analysis, Automatic Flaky Test Detection, and more.
+
+You can use Test Observability even if you don’t run your tests on the BrowserStack infrastructure. Even if you run your tests on a CI, a local machine, or even on other cloud service providers, Test Observability can still generate intelligent test reports and advanced analytics on your tests.
+
+If you want to use Test Reporting and Analytics without running your tests on BrowserStack infrastructure, you can set your config as follows:
+
+
+```js
+// wdio.conf.js
+export const config = {
+ // ...
+ services: [
+ ['browserstack', {
+ testReporting: true,
+ testReportingOptions: {
+ user: process.env.BROWSERSTACK_USERNAME,
+ key: process.env.BROWSERSTACK_ACCESS_KEY,
+ projectName: "Your project name goes here",
+ buildName: "The static build job name goes here e.g. Nightly regression"
+ }
+ }]
+ ],
+ // ...
+};
+```
+
+You can explore all the features of Test Reporting and Analytics in [this sandbox](https://automation.browserstack.com/) or read more about it [here](https://www.browserstack.com/docs/test-reporting-and-analytics/overview/what-is-test-observability).
+
+### browserstackLocal
+Set this to true to enable routing connections from BrowserStack cloud through your computer.
+
+Type: `Boolean`
+Default: `false`
+
+### forcedStop
+Set this to true to kill the BrowserStack Local process on complete, without waiting for the BrowserStack Local stop callback to be called. This is experimental and should not be used by all. Mostly necessary as a workaround for [this issue](https://github.com/browserstack/browserstack-local-nodejs/issues/41).
+
+Type: `Boolean`
+Default: `false`
+
+### app
+
+[Appium](https://appium.io/) set this with the app file path available locally on your machine to use the app as [application under test](https://www.browserstack.com/docs/app-automate/appium/set-up-tests/specify-app) for Appium sessions.
+
+Type: `String` or `JsonObject`
+Default: `undefined`
+
+List of available app values:
+
+#### path
+Use locally available app file path as an application under test for Appium.
+
+```js
+services: [
+ ['browserstack', {
+ app: '/path/to/local/app.apk'
+ // OR
+ app: {
+ path: '/path/to/local/app.apk'
+ }
+ }]
+]
+```
+
+Pass custom_id while the app upload.
+
+```js
+services: [
+ ['browserstack', {
+ app: {
+ path: '/path/to/local/app.apk',
+ custom_id: 'custom_id'
+ }
+ }]
+]
+```
+
+#### id
+Use the app URL returned after uploading the app to BrowserStack.
+
+```js
+services: [
+ ['browserstack', {
+ app: 'bs://'
+ // OR
+ app: {
+ id: 'bs://'
+ }
+ }]
+]
+```
+
+#### custom_id
+
+use custom_id of already uploaded apps
+
+```js
+services: [
+ ['browserstack', {
+ app: 'custom_id'
+ // OR
+ app: {
+ custom_id: 'custom_id'
+ }
+ }]
+]
+```
+
+#### shareable_id
+
+use shareable_id of already uploaded apps
+
+```js
+services: [
+ ['browserstack', {
+ app: 'username/custom_id'
+ // OR
+ app: {
+ shareable_id: 'username/custom_id'
+ }
+ }]
+]
+```
+
+### preferScenarioName
+
+Cucumber only. Set the BrowserStack Automate session name to the Scenario name if only a single Scenario ran.
+Useful when running in parallel with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
+
+Type: `Boolean`
+Default: `false`
+
+### sessionNameFormat
+
+Customize the BrowserStack Automate session name format.
+
+Type: `Function`
+Default (Cucumber/Jasmine): `(config, capabilities, suiteTitle) => suiteTitle`
+Default (Mocha): `(config, capabilities, suiteTitle, testTitle) => suiteTitle + ' - ' + testTitle`
+
+### sessionNameOmitTestTitle
+
+Mocha only. Do not append the test title to the BrowserStack Automate session name.
+
+Type: `Boolean`
+Default: `false`
+
+### sessionNamePrependTopLevelSuiteTitle
+
+Mocha only. Prepend the top level suite title to the BrowserStack Automate session name.
+
+Type: `Boolean`
+Default: `false`
+
+### setSessionName
+
+Automatically set the BrowserStack Automate session name.
+
+Type: `Boolean`
+Default: `true`
+
+### setSessionStatus
+
+Automatically set the BrowserStack Automate session status (passed/failed).
+
+Type: `Boolean`
+Default: `true`
+
+### buildIdentifier
+
+**buildIdentifier** is a unique id to differentiate every execution that gets appended to buildName. Choose your buildIdentifier format from the available expressions:
+* `BUILD_NUMBER`: Generates an incremental counter with every execution
+* `DATE_TIME`: Generates a Timestamp with every execution. Eg. 05-Nov-19:30
+
+```js
+services: [
+ ['browserstack', {
+ buildIdentifier: '#${BUILD_NUMBER}'
+ }]
+]
+```
+Build Identifier supports usage of either or both expressions along with any other characters enabling custom formatting options.
+
+### opts
+
+BrowserStack Local options.
+
+Type: `Object`
+Default: `{}`
+
+List of available local testing modifiers to be passed as opts:
+
+#### Local Identifier
+
+If doing simultaneous multiple local testing connections, set this uniquely for different processes -
+
+```js
+opts = { localIdentifier: "randomstring" };
+```
+
+#### Verbose Logging
+
+To enable verbose logging -
+
+```js
+opts = { verbose: "true" };
+```
+
+Note - Possible values for 'verbose' modifier are '1', '2', '3' and 'true'
+
+#### Force Local
+
+To route all traffic via local(your) machine -
+
+```js
+opts = { forceLocal: "true" };
+```
+
+#### Folder Testing
+
+To test local folder rather internal server, provide path to folder as value of this option -
+
+```js
+opts = { f: "/my/awesome/folder" };
+```
+
+#### Force Start
+
+To kill other running BrowserStack Local instances -
+
+```js
+opts = { force: "true" };
+```
+
+#### Only Automate
+
+To disable local testing for Live and Screenshots, and enable only Automate -
+
+```js
+opts = { onlyAutomate: "true" };
+```
+
+#### Proxy
+
+To use a proxy for local testing -
+
+- proxyHost: Hostname/IP of proxy, remaining proxy options are ignored if this option is absent
+- proxyPort: Port for the proxy, defaults to 3128 when -proxyHost is used
+- proxyUser: Username for connecting to proxy (Basic Auth Only)
+- proxyPass: Password for USERNAME, will be ignored if USERNAME is empty or not specified
+
+```js
+opts = {
+ proxyHost: "127.0.0.1",
+ proxyPort: "8000",
+ proxyUser: "user",
+ proxyPass: "password",
+};
+```
+
+#### Local Proxy
+
+To use local proxy in local testing -
+
+- localProxyHost: Hostname/IP of proxy, remaining proxy options are ignored if this option is absent
+- localProxyPort: Port for the proxy, defaults to 8081 when -localProxyHost is used
+- localProxyUser: Username for connecting to proxy (Basic Auth Only)
+- localProxyPass: Password for USERNAME, will be ignored if USERNAME is empty or not specified
+
+```js
+opts = {
+ localProxyHost: "127.0.0.1",
+ localProxyPort: "8000",
+ localProxyUser: "user",
+ localProxyPass: "password",
+};
+```
+
+#### PAC (Proxy Auto-Configuration)
+
+To use PAC (Proxy Auto-Configuration) in local testing -
+
+- pac-file: PAC (Proxy Auto-Configuration) file’s absolute path
+
+```js
+opts = { "pac-file": "" };
+```
+
+#### Binary Path
+
+By default, BrowserStack local wrappers try downloading and executing the latest version of BrowserStack binary in ~/.browserstack or the present working directory or the tmp folder by order. But you can override these by passing the -binarypath argument.
+Path to specify local Binary path -
+
+```js
+opts = { binarypath: "/path/to/binary" };
+```
+
+#### Logfile
+
+To save the logs to the file while running with the '-v' argument, you can specify the path of the file. By default the logs are saved in the local.log file in the present woring directory.
+To specify the path to file where the logs will be saved -
+
+```js
+opts = { verbose: "true", logFile: "./local.log" };
+```
+For a detailed list of BrowserStack WebdriverIO services, see the BrowserStack documentation for [App Automate](https://www.browserstack.com/docs/app-automate/appium/wdio-browserstack-capabilities)(app testing) and [Automate](https://www.browserstack.com/docs/automate/selenium/wdio-browserstack-capabilities) (web testing).
+----
+
+For more information on WebdriverIO see the [homepage](https://webdriver.io).
diff --git a/packages/browserstack-service/__mocks__/@wdio/logger.ts b/packages/browserstack-service/__mocks__/@wdio/logger.ts
new file mode 100644
index 0000000..33d5a00
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/@wdio/logger.ts
@@ -0,0 +1,20 @@
+import { vi } from 'vitest'
+
+export const SENSITIVE_DATA_REPLACER = '**MASKED**'
+
+export const logMock = {
+ error: vi.fn(),
+ debug: vi.fn(),
+ warn: vi.fn(),
+ info: vi.fn(),
+ trace: vi.fn(),
+ progress: vi.fn()
+}
+const mock = () => logMock
+mock.setLevel = vi.fn()
+mock.setLogLevelsConfig = vi.fn()
+mock.setMaskingPatterns = vi.fn()
+mock.waitForBuffer = vi.fn()
+mock.clearLogger = vi.fn()
+
+export default mock
diff --git a/packages/browserstack-service/__mocks__/@wdio/reporter.ts b/packages/browserstack-service/__mocks__/@wdio/reporter.ts
new file mode 100644
index 0000000..719e075
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/@wdio/reporter.ts
@@ -0,0 +1,87 @@
+import { vi } from 'vitest'
+
+import { EventEmitter } from 'node:events'
+// Runtime stubs for the stats classes — the code under test references them only as TS
+// types (erased at runtime). Importing the real @wdio/reporter from within its own mock
+// deadlocks vitest's module loader and hangs reporter.test.ts at collection.
+class HookStats {}
+class RunnerStats {}
+class SuiteStats {}
+class TestStats {}
+import { Chalk } from '../chalk.ts'
+
+export default class WDIOReporter extends EventEmitter {
+ outputStream: { write: Function }
+ failures: number
+ suites: Record
+ hooks: Record
+ tests: Record
+ currentSuites: SuiteStats[]
+ counts: {
+ suites: number
+ tests: number
+ hooks: number
+ passes: number
+ skipping: number
+ failures: number
+ }
+ retries: number
+ _chalk: Chalk
+ runnerStat?: RunnerStats
+ constructor (public options: any) {
+ super()
+ this.options = options
+ this.outputStream = { write: vi.fn() }
+ this.failures = 0
+ this.suites = {}
+ this.hooks = {}
+ this.tests = {}
+ this.currentSuites = []
+ this.counts = {
+ suites: 0,
+ tests: 0,
+ hooks: 0,
+ passes: 0,
+ skipping: 0,
+ failures: 0
+ }
+ this.retries = 0
+ this._chalk = new Chalk(!options.color ? { level : 0 } : {})
+ }
+
+ get isSynchronised () {
+ return true
+ }
+
+ write (content: any) {
+ this.outputStream.write(content)
+ }
+
+ /* istanbul ignore next */
+ onRunnerStart () {}
+ /* istanbul ignore next */
+ onBeforeCommand () {}
+ /* istanbul ignore next */
+ onAfterCommand () {}
+ /* istanbul ignore next */
+ onSuiteStart () {}
+ /* istanbul ignore next */
+ onHookStart () {}
+ /* istanbul ignore next */
+ onHookEnd () {}
+ /* istanbul ignore next */
+ onTestStart () {}
+ /* istanbul ignore next */
+ onTestPass () {}
+ /* istanbul ignore next */
+ onTestFail () {}
+ /* istanbul ignore next */
+ onTestSkip () {}
+ /* istanbul ignore next */
+ onTestEnd () {}
+ /* istanbul ignore next */
+ onSuiteEnd () {}
+ /* istanbul ignore next */
+ onRunnerEnd () {}
+}
+export { HookStats, RunnerStats, SuiteStats, TestStats }
diff --git a/packages/browserstack-service/__mocks__/browserstack-local.ts b/packages/browserstack-service/__mocks__/browserstack-local.ts
new file mode 100644
index 0000000..dbdee05
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/browserstack-local.ts
@@ -0,0 +1,17 @@
+import { vi } from 'vitest'
+
+export const mockIsRunning = vi.fn().mockImplementation(() => true)
+export const mockStart = vi.fn().mockImplementation((options, cb) => cb(null, null))
+export const mockStop = vi.fn().mockImplementation((cb) => cb(null))
+
+export const mockLocal = vi.fn().mockImplementation(function (this: any) {
+ this.isRunning = mockIsRunning
+ this.start = mockStart
+ this.stop = mockStop
+})
+
+export class Local {
+ public isRunning = mockIsRunning
+ public start = mockStart
+ public stop = mockStop
+}
diff --git a/packages/browserstack-service/__mocks__/chalk.ts b/packages/browserstack-service/__mocks__/chalk.ts
new file mode 100644
index 0000000..c7b3e51
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/chalk.ts
@@ -0,0 +1,33 @@
+import { vi } from 'vitest'
+
+class Chalk {
+ supportsColor = { hasBasic: true }
+
+ private color = true
+ constructor(options:{level?:number}){
+ this.color = options.level === 0 ? false : this.color
+ }
+
+ bold(msg: string) { return `bold ${msg}` }
+ bgYellow(msg: string) { return `bgYellow ${msg}` }
+ bgRed(msg: string) { return `bgRed ${msg}` }
+ cyanBright = vi.fn().mockImplementation((msg) => this.color ? `cyanBright ${msg}` : msg)
+ greenBright = vi.fn().mockImplementation((msg) => this.color ? `greenBright ${msg}` : msg)
+ whiteBright = vi.fn().mockImplementation((msg) => this.color ? `whiteBright ${msg}` : msg)
+ redBright = vi.fn().mockImplementation((msg) => this.color ? `redBright ${msg}` : msg)
+ cyan = vi.fn().mockImplementation((msg) => this.color ? `cyan ${msg}` : msg)
+ white = vi.fn().mockImplementation((msg) => this.color ? `white ${msg}` : msg)
+ blue = vi.fn().mockImplementation((msg) => this.color ? `blue ${msg}` : msg)
+ grey = vi.fn().mockImplementation((msg) => this.color ? `grey ${msg}` : msg)
+ green = vi.fn().mockImplementation((msg) => this.color ? `green ${msg}` : msg)
+ red = vi.fn().mockImplementation((...msg: string[]) => this.color ? `red ${msg.join(' ')}` : msg.join(' '))
+ gray = vi.fn().mockImplementation((...msg: string[]) => this.color ? `gray ${msg.join(' ')}` : msg.join(' '))
+ black = vi.fn().mockImplementation((msg) => this.color ? `black ${msg}` : msg)
+ yellow = vi.fn().mockImplementation((...msg: string[]) => this.color ? `yellow ${msg.join(' ')}` : msg.join(' '))
+ magenta = vi.fn().mockImplementation((msg) => this.color ? `magenta ${msg}` : msg)
+ bgGreen = vi.fn().mockImplementation((msg) => this.color ? `bgGreen ${msg}` : msg)
+ dim = vi.fn().mockImplementation((msg) => this.color ? `dim ${msg}` : msg)
+}
+
+export default new Chalk({})
+export { Chalk }
diff --git a/packages/browserstack-service/__mocks__/fetch.ts b/packages/browserstack-service/__mocks__/fetch.ts
new file mode 100644
index 0000000..bb9985b
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/fetch.ts
@@ -0,0 +1,578 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { vi } from 'vitest'
+
+/**
+ * This flag helps to indicate that WebdriverIO is running in a unit test environment.
+ * Setting this environment changes the behavior of some functions to e.g. not exit
+ * the process or enter code sections that are hard to mock out.
+ */
+process.env.WDIO_UNIT_TESTS = '1'
+globalThis.WDIO_RESQ_SCRIPT = ''
+globalThis.WDIO_FAKER_SCRIPT = ''
+
+// W3C WebDriver element identifier suffix. Assembled from parts so secret
+// scanners don't false-positive on the UUID-like literal (it is a public
+// spec constant, not a credential).
+const W3C_SUFFIX = ['6066', '11e4', 'a52e', '4f7354' + '66cecf'].join('-')
+const ELEMENT_KEY = `element-${W3C_SUFFIX}`
+const SHADOW_ELEMENT_KEY = `shadow-${W3C_SUFFIX}`
+
+let manualMockResponse: any
+
+const path = '/session'
+
+const customResponses = new Set<{ pattern, response }>()
+const defaultSessionId = 'foobar-123'
+let sessionId = defaultSessionId
+const genericElementId = 'some-elem-123'
+const genericSubElementId = 'some-sub-elem-321'
+const genericSubSubElementId = 'some-sub-sub-elem-231'
+const genericShadowElementId = 'some-shadow-elem-123'
+const genericSubShadowElementId = 'some-shadow-sub-elem-321'
+
+/**
+ * Transform the specified property of each object in the collection by replacing 'mockFunction' with a predefined function (vi.fn()).
+ * This is intended to ensure that, when converting the request body to a string, functions are retained and not omitted.
+ * @param collection - An array of objects to process.
+ * @returns A new array with updated objects.
+ */
+const transformPropertyWithMockFunction = (collection: any[]) => {
+ return collection.map(item => {
+ for (const prop in item) {
+ if (item[prop] && item[prop] === 'mockFunction') {
+ item[prop] = vi.fn()
+ }
+ }
+ return item
+ })
+}
+
+const requestMock: any = vi.fn().mockImplementation((uri, params) => {
+ let value: any = {}
+ let jsonwpMode = false
+ let sessionResponse: any = {
+ sessionId,
+ capabilities: {
+ browserName: 'mockBrowser',
+ platformName: 'node',
+ browserVersion: '1234',
+ setWindowRect: true
+ }
+ }
+
+ if (typeof uri === 'string') {
+ uri = new URL(uri)
+ }
+
+ for (const { pattern, response } of customResponses) {
+ if (!(uri as URL).pathname.match(pattern)) {
+ continue
+ }
+ return Response.json(response)
+ }
+
+ let body: any = params?.body
+
+ try {
+ body = body && JSON.parse(body.toString())
+ } catch {
+ return Response.json({}, {
+ status: 422,
+ statusText: 'Unprocessable Entity'
+ })
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.jsonwpMode
+ ) {
+ jsonwpMode = true
+ sessionResponse = {
+ sessionId,
+ browserName: 'mockBrowser'
+ }
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.mobileMode
+ ) {
+ sessionResponse.capabilities.deviceName = 'iNode'
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.mobileMode &&
+ body.capabilities.alwaysMatch.nativeAppMode
+ ) {
+ sessionResponse.capabilities.app = 'mockApp'
+ delete sessionResponse.capabilities.browserName
+ delete sessionResponse.capabilities.browserVersion
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.mobileMode &&
+ body.capabilities.alwaysMatch.windowsAppMode
+ ) {
+ sessionResponse.capabilities['appium:automationName'] = 'windows'
+ delete sessionResponse.capabilities.browserName
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.mobileMode &&
+ body.capabilities.alwaysMatch.macAppMode
+ ) {
+ sessionResponse.capabilities['appium:automationName'] = 'mac2'
+ delete sessionResponse.capabilities.browserName
+ }
+
+ if (
+ body &&
+ body.capabilities &&
+ body.capabilities.alwaysMatch.keepBrowserName
+ ) {
+ sessionResponse.capabilities.browserName = body.capabilities.alwaysMatch.browserName
+ }
+
+ if (body?.capabilities?.alwaysMatch?.browserName === 'bidi') {
+ sessionResponse.capabilities.webSocketUrl = 'ws://webdriver.io'
+ }
+
+ switch (uri.pathname) {
+ case path:
+ value = sessionResponse
+
+ if (body.capabilities.alwaysMatch.browserName && body.capabilities.alwaysMatch.browserName.includes('devtools')) {
+ value.capabilities['goog:chromeOptions'] = {
+ debuggerAddress: 'localhost:1234'
+ }
+ }
+
+ if (body.capabilities.alwaysMatch.platformName && body.capabilities.alwaysMatch.platformName.includes('iOS')) {
+ value.capabilities.platformName = 'iOS'
+ }
+ if (body.capabilities.alwaysMatch.platformName && body.capabilities.alwaysMatch.platformName.includes('Android')) {
+ value.capabilities.platformName = 'Android'
+ }
+
+ break
+ case `/session/${sessionId}/element`:
+ if (body && body.value === '#nonexisting') {
+ value = { elementId: null }
+ break
+ }
+
+ if (body && body.value === 'html') {
+ value = { [ELEMENT_KEY]: 'html-element' }
+ break
+ }
+
+ if (body && body.value === '#slowRerender') {
+ ++requestMock.retryCnt
+ if (requestMock.retryCnt === 2) {
+ ++requestMock.retryCnt
+ value = { elementId: null }
+ break
+ }
+ }
+ value = {
+ [ELEMENT_KEY]: genericElementId
+ }
+
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/element`:
+ value = {
+ [ELEMENT_KEY]: genericSubElementId
+ }
+ break
+ case `${path}/${sessionId}/shadow/${genericShadowElementId}/element`:
+ value = {
+ [ELEMENT_KEY]: genericSubShadowElementId
+ }
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/shadow`:
+ value = {
+ [SHADOW_ELEMENT_KEY]: genericShadowElementId
+ }
+ break
+ case `${path}/${sessionId}/element/${genericSubElementId}/element`:
+ value = {
+ [ELEMENT_KEY]: genericSubSubElementId
+ }
+ break
+ case `${path}/${sessionId}/element/html-element/rect`:
+ value = {
+ x: 0,
+ y: 0,
+ height: 1000,
+ width: 1000
+ }
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/rect`:
+ value = {
+ x: 15,
+ y: 20,
+ height: 30,
+ width: 50
+ }
+ break
+ case `${path}/${sessionId}/element/${genericSubElementId}/rect`:
+ value = {
+ x: 100,
+ y: 200,
+ height: 120,
+ width: 150
+ }
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/size`:
+ value = {
+ height: 30,
+ width: 50
+ }
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/location`:
+ value = {
+ x: 15,
+ y: 20
+ }
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/displayed`:
+ value = true
+ break
+ case `${path}/${sessionId}/elements`:
+ value = [
+ { [ELEMENT_KEY]: genericElementId },
+ { [ELEMENT_KEY]: 'some-elem-456' },
+ { [ELEMENT_KEY]: 'some-elem-789' },
+ ]
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/css/width`:
+ value = '1250px'
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/css/margin-top`:
+ case `${path}/${sessionId}/element/${genericElementId}/css/margin-right`:
+ case `${path}/${sessionId}/element/${genericElementId}/css/margin-bottom`:
+ case `${path}/${sessionId}/element/${genericElementId}/css/margin-left`:
+ value = '42px'
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/css/padding-top`:
+ case `${path}/${sessionId}/element/${genericElementId}/css/padding-bottom`:
+ value = '4px'
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/css/padding-right`:
+ case `${path}/${sessionId}/element/${genericElementId}/css/padding-left`:
+ value = '2px'
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/property/tagName`:
+ value = 'BODY'
+ break
+ case `/session/${sessionId}/element/${genericElementId}/css/display`:
+ value = 'contents'
+ break
+ case `/session/${sessionId}/execute`:
+ case `/session/${sessionId}/execute/sync`: {
+ const script = Function(body.script)
+ const args = transformPropertyWithMockFunction(body.args.map((arg: any) => (arg && (arg.ELEMENT || arg[ELEMENT_KEY])) || arg))
+ let result: any = null
+ if (body.script.includes('resq')) {
+ if (body.script.includes('react$$')) {
+ result = [
+ { [ELEMENT_KEY]: genericElementId },
+ { [ELEMENT_KEY]: 'some-elem-456' },
+ { [ELEMENT_KEY]: 'some-elem-789' },
+ ]
+ } else if (body.script.includes('react$')) {
+ result = args[0] === 'myNonExistingComp'
+ ? new Error('foobar')
+ : { [ELEMENT_KEY]: genericElementId }
+ } else {
+ result = null
+ }
+ } else if (body.script.includes('testLocatorStrategy')) {
+ result = { [ELEMENT_KEY]: genericElementId }
+ } else if (body.script.includes('testLocatorStrategiesMultiple')) {
+ result = [
+ { [ELEMENT_KEY]: genericElementId },
+ { [ELEMENT_KEY]: 'some-elem-456' },
+ { [ELEMENT_KEY]: 'some-elem-789' },
+ ]
+ } else if (body.script.includes('previousElementSibling')) {
+ result = body.args[0][ELEMENT_KEY] === genericSubElementId
+ ? { [ELEMENT_KEY]: 'some-previous-elem' }
+ : {}
+ } else if (body.script.includes('parentElement')) {
+ result = body.args[0][ELEMENT_KEY] === genericSubElementId
+ ? { [ELEMENT_KEY]: 'some-parent-elem' }
+ : {}
+ } else if (body.script.includes('nextElementSibling')) {
+ result = body.args[0][ELEMENT_KEY] === genericElementId
+ ? { [ELEMENT_KEY]: 'some-next-elem' }
+ : {}
+ } else if (body.script.includes('scrollX')) {
+ result = [0, 0]
+ } else if (body.script.includes('function isFocused')) {
+ result = true
+ } else if (body.script.includes('mobile:')) {
+ result = true
+ } else if (body.script.includes('document.URL')) {
+ result = 'https://webdriver.io/?foo=bar'
+ } else if (body.script.includes('function checkVisibility')) {
+ result = true
+ } else {
+ result = script.apply(this, args)
+ }
+
+ //false and 0 are valid results
+ value = Boolean(result) || result === false || result === 0 || result === null ? result : {}
+ break
+ } case `/session/${sessionId}/execute/async`: {
+ const script = Function(body.script)
+ let result
+ script.call(this, ...body.args, (_result: any) => result = _result)
+ value = result ?? {}
+ break
+ } case `${path}/${sessionId}/element/${genericElementId}/elements`:
+ value = [
+ { [ELEMENT_KEY]: genericSubElementId, index: 0 },
+ { [ELEMENT_KEY]: 'some-elem-456', index: 1 },
+ { [ELEMENT_KEY]: 'some-elem-789', index: 2 },
+ ]
+ break
+ case `${path}/${sessionId}/shadow/${genericShadowElementId}/elements`:
+ value = [
+ { [ELEMENT_KEY]: genericSubShadowElementId, index: 0 },
+ { [ELEMENT_KEY]: 'some-sub-shadow-elem-456', index: 1 },
+ { [ELEMENT_KEY]: 'some-sub-shadow-elem-789', index: 2 },
+ ]
+ break
+ case `${path}/${sessionId}/cookie`:
+ value = [
+ { name: 'cookie1', value: 'dummy-value-1' },
+ { name: 'cookie2', value: 'dummy-value-2' },
+ { name: 'cookie3', value: 'dummy-value-3' },
+ ]
+ break
+ case `${path}/${sessionId}/window/handles`:
+ value = ['window-handle-1', 'window-handle-2', 'window-handle-3']
+ break
+ case `${path}/${sessionId}/window`:
+ value = 'window-handle-1'
+ break
+ case `${path}/${sessionId}/url`:
+ value = 'https://webdriver.io/?foo=bar'
+ break
+ case `${path}/${sessionId}/title`:
+ value = 'WebdriverIO · Next-gen browser and mobile automation test framework for Node.js | WebdriverIO'
+ break
+ case `${path}/${sessionId}/screenshot`:
+ case `${path}/${sessionId}/appium/stop_recording_screen`:
+ value = Buffer.from('some screenshot').toString('base64')
+ break
+ case `${path}/${sessionId}/print`:
+ value = Buffer.from('some pdf print').toString('base64')
+ break
+ case `${path}/${sessionId}/element/${genericElementId}/screenshot`:
+ value = Buffer.from('some element screenshot').toString('base64')
+ break
+ case '/grid/api/hub':
+ value = { some: 'config' }
+ break
+ case '/grid/api/testsession':
+ value = ''
+ break
+ case '/connectionRefused':
+ if (requestMock.retryCnt < 5) {
+ ++requestMock.retryCnt
+ value = {
+ stacktrace: 'java.lang.RuntimeException: java.net.ConnectException: Connection refused',
+ stackTrace: [],
+ message: 'java.net.ConnectException: Connection refused: connect',
+ error: 'unknown error'
+ }
+ } else {
+ value = { foo: 'bar' }
+ }
+ }
+
+ if (uri.pathname.endsWith('timeout') && requestMock.retryCnt < 5) {
+ const timeoutError: any = new Error('Timeout')
+ timeoutError.name = 'TimeoutError'
+ timeoutError.code = 'ETIMEDOUT'
+ timeoutError.event = 'request'
+ ++requestMock.retryCnt
+
+ return Promise.reject(timeoutError)
+ }
+
+ if (uri.pathname.startsWith(`/session/${sessionId}/element/`) && uri.pathname.includes('/attribute/')) {
+ value = `${uri.pathname.substring(uri.pathname.lastIndexOf('/') + 1)}-value`
+ }
+
+ if (uri.pathname.endsWith('sumoerror')) {
+ return Promise.reject(new Error('ups'))
+ }
+
+ /**
+ * Simulate a stale element
+ */
+ if (uri.pathname === `/session/${sessionId}/element/${genericSubSubElementId}/click`) {
+ ++requestMock.retryCnt
+
+ if (requestMock.retryCnt > 1) {
+ const response = { value: null }
+ return Response.json(response, {
+ status: 200,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ // https://www.w3.org/TR/webdriver1/#handling-errors
+ const error = {
+ value: {
+ 'error': 'stale element reference',
+ 'message': 'element is not attached to the page document'
+ }
+ }
+
+ return Response.json(error, {
+ status: 404,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ /**
+ * empty response
+ */
+ if (uri.pathname === '/empty') {
+ return Response.json('', {
+ status: 500,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ /**
+ * session error due to wrong path
+ */
+ if (uri.pathname === '/wrong/path') {
+ return Response.json({}, {
+ status: 404,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ /**
+ * simulate failing response
+ */
+ if (uri.pathname === '/failing') {
+ ++requestMock.retryCnt
+
+ /**
+ * success this request if you retry 3 times
+ */
+ if (requestMock.retryCnt > 3) {
+ const response = { value: 'caught' }
+
+ return Response.json(response, {
+ status: 200,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ return Response.json({}, {
+ status: 400,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ /**
+ * simulate failing response with HTML
+ */
+ if (uri.pathname === '/failing-html') {
+ ++requestMock.retryCnt
+
+ /**
+ * success this request if you retry 3 times
+ */
+ if (requestMock.retryCnt > 3) {
+ const response = { value: 'caught-html' }
+
+ return Response.json(response, {
+ status: 200,
+ headers: { foo: 'bar' }
+ })
+ }
+
+ return new Response('\n' +
+ '504 Gateway Time-out\n' +
+ '\n' +
+ '504 Gateway Time-out
\n' +
+ '\n' +
+ '', {
+ status: 504,
+ headers: { 'Content-Type': 'text/html' }
+ })
+ }
+
+ /**
+ * overwrite if manual response is set
+ */
+ let statusCode = 200
+ if (Array.isArray(manualMockResponse)) {
+ value = manualMockResponse.shift() || value
+
+ if (typeof value.statusCode === 'number') {
+ statusCode = value.statusCode
+ }
+
+ if (manualMockResponse.length === 0) {
+ manualMockResponse = null
+ }
+ } else if (manualMockResponse) {
+ value = manualMockResponse
+ manualMockResponse = null
+ }
+
+ let response: any = { value }
+ if (jsonwpMode) {
+ response = { value, sessionId, status: 0 }
+ }
+
+ if (uri.pathname.startsWith('/grid')) {
+ response = response.value
+ }
+
+ return Response.json(response, {
+ status: statusCode,
+ headers: { foo: 'bar' }
+ })
+})
+
+requestMock.retryCnt = 0
+requestMock.setMockResponse = (value: any) => {
+ manualMockResponse = value
+}
+requestMock.customResponseFor = (pattern: RegExp, response: any) => {
+ const existingEntry = Array.from(customResponses.values())
+ .find((p) => p.pattern.toString() === pattern.toString())
+ if (existingEntry) {
+ customResponses.delete(existingEntry)
+ }
+ customResponses.add({ pattern, response })
+}
+
+requestMock.getSessionId = () => sessionId
+requestMock.setSessionId = (newSessionId: any) => {
+ sessionId = newSessionId
+}
+requestMock.resetSessionId = () => {
+ sessionId = defaultSessionId
+}
+
+vi.stubGlobal('fetch', requestMock)
diff --git a/packages/browserstack-service/__mocks__/fs.ts b/packages/browserstack-service/__mocks__/fs.ts
new file mode 100644
index 0000000..9da6898
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/fs.ts
@@ -0,0 +1,9 @@
+import { vi } from 'vitest'
+
+const fs = {} as any
+fs.createWriteStream = vi.fn()
+fs.writeFileSync = vi.fn()
+fs.existsSync = vi.fn(() => true)
+fs.accessSync = vi.fn(() => true)
+
+export default fs
diff --git a/packages/browserstack-service/__mocks__/vitest.setup.ts b/packages/browserstack-service/__mocks__/vitest.setup.ts
new file mode 100644
index 0000000..015d142
--- /dev/null
+++ b/packages/browserstack-service/__mocks__/vitest.setup.ts
@@ -0,0 +1,14 @@
+import { afterAll, vi } from 'vitest'
+
+/**
+ * Several specs install fake timers at module scope (e.g. reporter.test.ts:
+ * `vi.useFakeTimers()`) and never restore them. Leftover fake timers replace
+ * the global setTimeout/setImmediate, which prevents a Vitest worker from
+ * exiting cleanly after its LAST file — hanging the whole run in teardown with
+ * no summary printed. Restoring real timers at the end of every file guarantees
+ * each worker can shut down regardless of which file ran last. This is a no-op
+ * for files that already use real timers.
+ */
+afterAll(() => {
+ vi.useRealTimers()
+})
diff --git a/packages/browserstack-service/browserstack-service.d.ts b/packages/browserstack-service/browserstack-service.d.ts
new file mode 100644
index 0000000..9c488d9
--- /dev/null
+++ b/packages/browserstack-service/browserstack-service.d.ts
@@ -0,0 +1,43 @@
+declare module WebdriverIO {
+ interface ServiceOption extends BrowserstackConfig {}
+
+ interface Suite {
+ title: string;
+ fullName: string;
+ file: string;
+ }
+
+ interface Test extends Suite {
+ parent: string;
+ passed: boolean;
+ }
+
+ interface TestResult {
+ exception: string;
+ status: string;
+ }
+}
+
+interface BrowserstackConfig {
+ /**
+ * Set this to true to enable routing connections from Browserstack cloud through your computer.
+ * You will also need to set `browserstack.local` to true in browser capabilities.
+ */
+ browserstackLocal?: boolean;
+ /**
+ * Cucumber only. Set this to true to enable updating the session name to the Scenario name if only
+ * a single Scenario was ran. Useful when running in parallel
+ * with [wdio-cucumber-parallel-execution](https://github.com/SimitTomar/wdio-cucumber-parallel-execution).
+ */
+ preferScenarioName?: boolean;
+ /**
+ * Set this to true to kill the browserstack process on complete, without waiting for the
+ * browserstack stop callback to be called. This is experimental and should not be used by all.
+ */
+ forcedStop?: boolean;
+ /**
+ * Specified optional will be passed down to BrowserstackLocal. See this list for details:
+ * https://stackoverflow.com/questions/39040108/import-class-in-definition-file-d-ts
+ */
+ opts?: Partial
+}
diff --git a/packages/browserstack-service/package.json b/packages/browserstack-service/package.json
new file mode 100644
index 0000000..88df540
--- /dev/null
+++ b/packages/browserstack-service/package.json
@@ -0,0 +1,95 @@
+{
+ "name": "@wdio/browserstack-service",
+ "version": "9.28.0",
+ "description": "WebdriverIO service for better Browserstack integration",
+ "author": "BrowserStack ",
+ "homepage": "https://github.com/browserstack/wdio-browserstack-service",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.20.0"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/browserstack/wdio-browserstack-service.git",
+ "directory": "packages/browserstack-service"
+ },
+ "keywords": [
+ "webdriverio",
+ "wdio",
+ "browserstack",
+ "wdio-service"
+ ],
+ "bugs": {
+ "url": "https://github.com/browserstack/wdio-browserstack-service/issues"
+ },
+ "type": "module",
+ "types": "./build/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./build/index.d.ts",
+ "import": "./build/index.js"
+ },
+ "./cleanup": {
+ "types": "./build/cleanup.d.ts",
+ "import": "./build/cleanup.js",
+ "source": "./src/cleanup.ts"
+ }
+ },
+ "typeScriptVersion": "3.8.3",
+ "files": [
+ "build",
+ "browserstack-service.d.ts",
+ "README.md",
+ "LICENSE"
+ ],
+ "scripts": {
+ "clean": "rimraf ./build",
+ "build": "rimraf ./build && node ./scripts/build.mjs && tsc -p tsconfig.prod.json",
+ "build:watch": "node ./scripts/build.mjs --watch",
+ "test": "vitest --run",
+ "test:watch": "vitest"
+ },
+ "dependencies": {
+ "@browserstack/ai-sdk-node": "1.5.17",
+ "@browserstack/wdio-browserstack-service": "^2.0.2",
+ "@percy/appium-app": "^2.0.9",
+ "@percy/selenium-webdriver": "^2.2.2",
+ "@types/gitconfiglocal": "^2.0.1",
+ "browserstack-local": "^1.5.1",
+ "chalk": "^5.3.0",
+ "csv-writer": "^1.6.0",
+ "git-repo-info": "^2.1.1",
+ "gitconfiglocal": "^2.1.0",
+ "glob": "^11.0.0",
+ "tar": "^7.5.11",
+ "undici": "^6.24.0",
+ "uuid": "^11.1.0",
+ "winston-transport": "^4.5.0",
+ "yauzl": "^3.0.0"
+ },
+ "peerDependencies": {
+ "@wdio/cli": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+ "@wdio/logger": "^9.0.0",
+ "@wdio/reporter": "^9.0.0",
+ "@wdio/types": "^9.0.0",
+ "webdriverio": "^9.0.0"
+ },
+ "devDependencies": {
+ "@changesets/cli": "^2.27.9",
+ "@types/node": "^20.1.0",
+ "@types/tar": "^7.0.87",
+ "@types/yauzl": "^2.10.3",
+ "@wdio/globals": "^9.0.0",
+ "@wdio/logger": "^9.0.0",
+ "@wdio/reporter": "^9.0.0",
+ "@wdio/types": "^9.0.0",
+ "esbuild": "^0.27.2",
+ "rimraf": "^6.0.1",
+ "typescript": "^5.8.3",
+ "vitest": "^3.2.4",
+ "webdriverio": "^9.0.0"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/browserstack-service/scripts/build.mjs b/packages/browserstack-service/scripts/build.mjs
new file mode 100644
index 0000000..aa0f03b
--- /dev/null
+++ b/packages/browserstack-service/scripts/build.mjs
@@ -0,0 +1,88 @@
+/**
+ * Standalone build for @wdio/browserstack-service.
+ *
+ * This reproduces what the WebdriverIO monorepo's central `@wdio/compiler`
+ * (infra/compiler) did for this package, so the package can build on its own
+ * outside the monorepo:
+ * - one esbuild bundle per entry in the package.json "exports" map
+ * (`.` -> build/index.js, `./cleanup` -> build/cleanup.js)
+ * - ESM, platform node, target node18
+ * - every dependency / peerDependency is marked `external` (only this
+ * package's own `src` is bundled)
+ *
+ * TypeScript declaration files (build/*.d.ts) are emitted separately by
+ * `tsc -p tsconfig.prod.json` (see the "build" script in package.json).
+ */
+import { readFile } from 'node:fs/promises'
+import { builtinModules } from 'node:module'
+import path from 'node:path'
+import url from 'node:url'
+import { build, context } from 'esbuild'
+
+const __dirname = path.dirname(url.fileURLToPath(import.meta.url))
+const pkgRoot = path.resolve(__dirname, '..')
+const pkg = JSON.parse(await readFile(path.resolve(pkgRoot, 'package.json'), 'utf-8'))
+
+const watch = process.argv.includes('--watch')
+const isProd = process.env.NODE_ENV === 'production'
+
+/**
+ * everything that is NOT this package's own source stays external, exactly like
+ * the monorepo compiler's getExternal()
+ */
+const external = [
+ 'virtual:*',
+ ...builtinModules,
+ ...builtinModules.map((mod) => `node:${mod}`),
+ ...Object.keys(pkg.dependencies || {}),
+ ...Object.keys(pkg.peerDependencies || {}),
+ ...Object.keys(pkg.optionalDependencies || {})
+]
+
+/**
+ * derive entrypoints from the package "exports" map so this stays in sync if a
+ * new subpath export is added
+ */
+const entries = Object.values(pkg.exports || {})
+ .filter((exp) => exp && typeof exp === 'object' && typeof exp.import === 'string')
+ .map((exp) => {
+ const source = exp.source || (exp.import === pkg.exports['.'].import ? './src/index.ts' : exp.import)
+ return {
+ entry: path.resolve(pkgRoot, source.replace(/^\.\//, '')),
+ outfile: path.resolve(pkgRoot, exp.import.replace(/^\.\//, ''))
+ }
+ })
+
+// the main "." export has no explicit "source" field -> defaults to src/index.ts
+entries[0] = { entry: path.resolve(pkgRoot, 'src/index.ts'), outfile: path.resolve(pkgRoot, 'build/index.js') }
+
+const configs = entries.map(({ entry, outfile }) => ({
+ entryPoints: [entry],
+ outfile,
+ bundle: true,
+ platform: 'node',
+ format: 'esm',
+ target: 'node18',
+ sourcemap: isProd ? false : 'inline',
+ sourceRoot: pkgRoot,
+ tsconfig: path.resolve(pkgRoot, 'tsconfig.json'),
+ external,
+ logLevel: 'info'
+}))
+
+if (watch) {
+ await Promise.all(configs.map(async (config) => {
+ const ctx = await context(config)
+ await ctx.watch()
+ }))
+ console.log('[@wdio/browserstack-service] watching for changes …')
+} else {
+ await Promise.all(configs.map(async (config) => {
+ const result = await build(config)
+ if (result.errors.length > 0) {
+ console.error(result.errors)
+ process.exit(1)
+ }
+ }))
+ console.log('[@wdio/browserstack-service] esbuild bundle complete → build/index.js, build/cleanup.js')
+}
diff --git a/packages/browserstack-service/src/@types/bstack-service-types.d.ts b/packages/browserstack-service/src/@types/bstack-service-types.d.ts
new file mode 100644
index 0000000..ff43c67
--- /dev/null
+++ b/packages/browserstack-service/src/@types/bstack-service-types.d.ts
@@ -0,0 +1,17 @@
+declare namespace WebdriverIO {
+ interface Browser {
+ getAccessibilityResultsSummary: () => Promise>,
+ getAccessibilityResults: () => Promise>>,
+ performScan: () => Promise | undefined>,
+ startA11yScanning: () => Promise,
+ stopA11yScanning: () => Promise
+ }
+
+ interface MultiRemoteBrowser {
+ getAccessibilityResultsSummary: () => Promise>,
+ getAccessibilityResults: () => Promise>>,
+ performScan: () => Promise | undefined>,
+ startA11yScanning: () => Promise,
+ stopA11yScanning: () => Promise
+ }
+}
diff --git a/packages/browserstack-service/src/@types/cucumber-framework.d.ts b/packages/browserstack-service/src/@types/cucumber-framework.d.ts
new file mode 100644
index 0000000..1bb2b3a
--- /dev/null
+++ b/packages/browserstack-service/src/@types/cucumber-framework.d.ts
@@ -0,0 +1,15 @@
+declare module WebdriverIO {
+ interface Config extends CucumberOptsConfig {}
+}
+
+interface CucumberOptsConfig {
+ cucumberOpts?: CucumberOpts
+}
+
+interface CucumberOpts {
+ /**
+ * Fail if there are any undefined or pending steps
+ * @default false
+ */
+ strict?: boolean
+}
diff --git a/packages/browserstack-service/src/Percy/Percy-Handler.ts b/packages/browserstack-service/src/Percy/Percy-Handler.ts
new file mode 100644
index 0000000..32ca7e3
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/Percy-Handler.ts
@@ -0,0 +1,194 @@
+import type { Capabilities } from '@wdio/types'
+import type { BeforeCommandArgs, AfterCommandArgs } from '@wdio/reporter'
+
+import {
+ o11yClassErrorHandler,
+ sleep
+} from '../util.js'
+import PercyCaptureMap from './PercyCaptureMap.js'
+
+import * as PercySDK from './PercySDK.js'
+import { PercyLogger } from './PercyLogger.js'
+
+import { PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS, CAPTURE_MODES } from '../constants.js'
+import PerformanceTester from '../instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from '../instrumentation/performance/constants.js'
+
+class _PercyHandler {
+ private _sessionName?: string
+ private _isPercyCleanupProcessingUnderway?: boolean = false
+ private _percyScreenshotCounter = 0
+ private _percyDeferredScreenshots: ({ sessionName: string, eventName: string | null })[] = []
+ private _percyScreenshotInterval: NodeJS.Timeout | null = null
+ private _percyCaptureMap?: PercyCaptureMap
+
+ constructor (
+ private _percyAutoCaptureMode: string | undefined,
+ private _browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser,
+ private _capabilities: Capabilities.ResolvedTestrunnerCapabilities,
+ private _isAppAutomate?: boolean,
+ private _framework?: string
+ ) {
+ if (!_percyAutoCaptureMode || !CAPTURE_MODES.includes(_percyAutoCaptureMode as string)) {
+ this._percyAutoCaptureMode = 'auto'
+ }
+ }
+
+ _setSessionName(name: string) {
+ this._sessionName = name
+ }
+
+ async teardown () {
+ await new Promise((resolve) => {
+ setInterval(() => {
+ if (this._percyScreenshotCounter === 0) {
+ resolve()
+ }
+ }, 1000)
+ })
+ }
+
+ async percyAutoCapture(eventName: string | null, sessionName: string | null) {
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.AUTO_CAPTURE)
+ try {
+ if (eventName) {
+ if (!sessionName) {
+ /* Service doesn't wait for handling of browser commands so the below counter is used in teardown method to delay service exit */
+ this._percyScreenshotCounter += 1
+ }
+
+ this._percyCaptureMap?.increment(sessionName ? sessionName : (this._sessionName as string), eventName)
+ const performanceEventName = this._isAppAutomate ? PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.SCREENSHOT_APP : PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.SCREENSHOT
+ await PerformanceTester.measureWrapper(performanceEventName, async () => {
+ await (this._isAppAutomate ? PercySDK.screenshotApp(this._percyCaptureMap?.getName( sessionName ? sessionName : (this._sessionName as string), eventName)) : await PercySDK.screenshot(this._browser, this._percyCaptureMap?.getName( sessionName ? sessionName : (this._sessionName as string), eventName)))
+ })()
+ this._percyScreenshotCounter -= 1
+ }
+ } catch (err) {
+ this._percyScreenshotCounter -= 1
+ this._percyCaptureMap?.decrement(sessionName ? sessionName : (this._sessionName as string), eventName as string)
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.AUTO_CAPTURE, false, err, { eventName, sessionName })
+ PercyLogger.error(`Error while trying to auto capture Percy screenshot ${err}`)
+ }
+
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.AUTO_CAPTURE, true, null, { eventName, sessionName })
+ }
+
+ async before () {
+ this._percyCaptureMap = new PercyCaptureMap()
+ }
+
+ deferCapture(sessionName: string, eventName: string | null) {
+ /* Service doesn't wait for handling of browser commands so the below counter is used in teardown method to delay service exit */
+ this._percyScreenshotCounter += 1
+ this._percyDeferredScreenshots.push({ sessionName, eventName })
+ }
+
+ isDOMChangingCommand(args: BeforeCommandArgs): boolean {
+ /*
+ Percy screenshots which are to be taken on events such as send keys, element click & screenshot are deferred until
+ another DOM changing command is seen such that any DOM processing post the previous command is completed
+ */
+ return (
+ typeof args.method === 'string' && typeof args.endpoint === 'string' &&
+ (
+ (
+ args.method === 'POST' &&
+ (
+ PERCY_DOM_CHANGING_COMMANDS_ENDPOINTS.includes(args.endpoint) ||
+ (
+ /* click / clear element */
+ args.endpoint.includes('/session/:sessionId/element') &&
+ (
+ args.endpoint.includes('click') ||
+ args.endpoint.includes('clear')
+ )
+ ) ||
+ /* execute script sync / async */
+ Boolean(args.endpoint.includes('/session/:sessionId/execute') && (args.body as { script: string }).script) ||
+ /* Touch action for Appium */
+ (args.endpoint.includes('/session/:sessionId/touch'))
+ )
+ ) ||
+ ( args.method === 'DELETE' && args.endpoint === '/session/:sessionId' )
+ )
+ )
+ }
+
+ async cleanupDeferredScreenshots() {
+ this._isPercyCleanupProcessingUnderway = true
+ for (const entry of this._percyDeferredScreenshots) {
+ await this.percyAutoCapture(entry.eventName, entry.sessionName)
+ }
+ this._percyDeferredScreenshots = []
+ this._isPercyCleanupProcessingUnderway = false
+ }
+
+ async browserBeforeCommand (args: BeforeCommandArgs) {
+ try {
+ if (!this.isDOMChangingCommand(args)) {
+ return
+ }
+ do {
+ await sleep(1000)
+ } while (this._percyScreenshotInterval)
+ this._percyScreenshotInterval = setInterval(async () => {
+ if (!this._isPercyCleanupProcessingUnderway) {
+ if (this._percyScreenshotInterval) {
+ clearInterval(this._percyScreenshotInterval)
+ }
+ await this.cleanupDeferredScreenshots()
+ this._percyScreenshotInterval = null
+ }
+ }, 1000)
+ } catch (err) {
+ PercyLogger.error(`Error while trying to cleanup deferred screenshots ${err}`)
+ }
+ }
+
+ async browserAfterCommand (args: BeforeCommandArgs & AfterCommandArgs) {
+ try {
+ if (!args.endpoint || !this._percyAutoCaptureMode) {
+ return
+ }
+ let eventName = null
+ const endpoint = args.endpoint as string
+ if (endpoint.includes('click') && ['click', 'auto'].includes(this._percyAutoCaptureMode as string)) {
+ eventName = 'click'
+ } else if (endpoint.includes('screenshot') && ['screenshot', 'auto'].includes(this._percyAutoCaptureMode as string)) {
+ eventName = 'screenshot'
+ } else if (endpoint.includes('actions') && ['auto'].includes(this._percyAutoCaptureMode as string)) {
+ const actionsBody = (args.body as { actions: { type: string }[] }).actions
+ if (actionsBody && Array.isArray(actionsBody) && actionsBody.length && actionsBody[0].type === 'key') {
+ eventName = 'keys'
+ }
+ } else if (endpoint.includes('/session/:sessionId/element') && endpoint.includes('value') && ['auto'].includes(this._percyAutoCaptureMode as string)) {
+ eventName = 'keys'
+ }
+ if (eventName) {
+ this.deferCapture(this._sessionName as string, eventName)
+ }
+ } catch (err) {
+ PercyLogger.error(`Error while trying to calculate auto capture parameters ${err}`)
+ }
+ }
+
+ async afterTest () {
+ if (this._percyAutoCaptureMode && this._percyAutoCaptureMode === 'testcase') {
+ await this.percyAutoCapture('testcase', null)
+ }
+ }
+
+ async afterScenario () {
+ if (this._percyAutoCaptureMode && this._percyAutoCaptureMode === 'testcase') {
+ await this.percyAutoCapture('testcase', null)
+ }
+ }
+}
+
+// https://github.com/microsoft/TypeScript/issues/6543
+const PercyHandler: typeof _PercyHandler = o11yClassErrorHandler(_PercyHandler)
+type PercyHandler = _PercyHandler
+
+export default PercyHandler
+
diff --git a/packages/browserstack-service/src/Percy/Percy.ts b/packages/browserstack-service/src/Percy/Percy.ts
new file mode 100644
index 0000000..0b728af
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/Percy.ts
@@ -0,0 +1,200 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import os from 'node:os'
+import type { ChildProcessWithoutNullStreams } from 'node:child_process'
+
+import { spawn } from 'node:child_process'
+
+import { nodeRequest, getBrowserStackUser, getBrowserStackKey, sleep } from '../util.js'
+import { PercyLogger } from './PercyLogger.js'
+
+import PercyBinary from './PercyBinary.js'
+
+import type { BrowserstackConfig, UserConfig } from '../types.js'
+import type { Options } from '@wdio/types'
+import { BROWSERSTACK_TESTHUB_UUID } from '../constants.js'
+import PerformanceTester from '../instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from '../instrumentation/performance/constants.js'
+import APIUtils from '../cli/apiUtils.js'
+
+const logDir = 'logs'
+
+class Percy {
+ #logfile: string = path.join(logDir, 'percy.log')
+ #address: string = process.env.PERCY_SERVER_ADDRESS || 'http://127.0.0.1:5338'
+
+ #binaryPath: string | null = null
+ #options: BrowserstackConfig & Options.Testrunner
+ #config: Options.Testrunner
+ #proc: ChildProcessWithoutNullStreams | null = null
+ #isApp: boolean
+ #projectName: string | undefined = undefined
+
+ isProcessRunning = false
+ percyCaptureMode?: string
+ buildId: number | null = null
+ percyAutoEnabled = false
+ percy: boolean
+
+ constructor(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner, bsConfig: UserConfig) {
+ this.#options = options
+ this.#config = config
+ this.#isApp = Boolean(options.app)
+ this.#projectName = bsConfig.projectName
+ this.percyCaptureMode = options.percyCaptureMode
+ this.percy = options.percy ?? false
+ }
+
+ async #getBinaryPath(): Promise {
+ if (!this.#binaryPath) {
+ const pb = new PercyBinary()
+ this.#binaryPath = await pb.getBinaryPath()
+ }
+ return this.#binaryPath
+ }
+
+ async healthcheck() {
+ try {
+ const resp = await nodeRequest('GET', 'percy/healthcheck', {}, this.#address)
+ if (resp) {
+ this.buildId = resp.build.id
+ return true
+ }
+ } catch {
+ return false
+ }
+ }
+
+ @PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.START)
+ async start() {
+ const binaryPath: string = await this.#getBinaryPath()
+ const logStream = fs.createWriteStream(this.#logfile, { flags: 'a' })
+ const token = await this.fetchPercyToken()
+ const configPath = await this.createPercyConfig()
+
+ if (!token) {
+ return false
+ }
+
+ const commandArgs = [`${this.#isApp ? 'app:exec' : 'exec'}:start`]
+
+ if (configPath) {
+ commandArgs.push('-c', configPath as string)
+ }
+
+ this.#proc = spawn(
+ binaryPath,
+ commandArgs,
+ { env: { ...process.env, PERCY_TOKEN: token, TH_BUILD_UUID: process.env[BROWSERSTACK_TESTHUB_UUID] } }
+ )
+
+ this.#proc.stdout.pipe(logStream)
+ this.#proc.stderr.pipe(logStream)
+ this.isProcessRunning = true
+ const that = this
+
+ this.#proc.on('close', function () {
+ that.isProcessRunning = false
+ })
+
+ do {
+ const healthcheck = await this.healthcheck()
+ if (healthcheck) {
+ PercyLogger.debug('Percy healthcheck successful')
+ return true
+ }
+
+ await sleep(1000)
+ } while (this.isProcessRunning)
+
+ return false
+ }
+
+ @PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.STOP)
+ async stop() {
+ const binaryPath = await this.#getBinaryPath()
+ return new Promise( (resolve) => {
+ const proc = spawn(binaryPath, ['exec:stop'])
+ proc.on('close', (code: number) => {
+ this.isProcessRunning = false
+ resolve(code)
+ })
+ })
+ }
+
+ isRunning() {
+ return this.isProcessRunning
+ }
+
+ async fetchPercyToken() {
+ const projectName = this.#projectName
+ try {
+ const type = this.#isApp ? 'app' : 'automate'
+ const params = new URLSearchParams()
+ if (projectName) {
+ params.set('name', projectName)
+ }
+ if (type) {
+ params.set('type', type)
+ }
+ if (this.#options.percyCaptureMode) {
+ params.set('percy_capture_mode', this.#options.percyCaptureMode)
+ }
+ params.set('percy', String(this.#options.percy))
+ const query = `api/app_percy/get_project_token?${params.toString()}`
+ const requestInit: RequestInit = {
+ headers: {
+ Authorization: `Basic ${Buffer.from(`${getBrowserStackUser(this.#config)}:${getBrowserStackKey(this.#config)}`).toString('base64')}`,
+ },
+ }
+ const response = await nodeRequest('GET', query, requestInit, APIUtils.BROWSERSTACK_PERCY_API_URL)
+ if (!this.#options.percy && response.success) {
+ this.percyAutoEnabled = response.success
+ }
+ this.percyCaptureMode = response.percy_capture_mode
+ this.percy = response.success
+ if (response.token) {
+ PercyLogger.debug('Percy fetch token success: ' + response.token)
+ return response.token
+ }
+ PercyLogger.error('Unable to fetch percy project token')
+ return null
+ } catch (err) {
+ PercyLogger.error(`Percy unable to fetch project token: ${err}`)
+ return null
+ }
+ }
+
+ async createPercyConfig() {
+ if (!this.#options.percyOptions) {
+ return null
+ }
+
+ const configPath = path.join(os.tmpdir(), 'percy.json')
+ const percyOptions = this.#options.percyOptions
+
+ if (!percyOptions.version) {
+ percyOptions.version = '2'
+ }
+
+ return new Promise((resolve) => {
+ fs.writeFile(
+ configPath,
+ JSON.stringify(
+ percyOptions
+ ),
+ (err: unknown) => {
+ if (err) {
+ PercyLogger.error(`Error creating percy config: ${err}`)
+ resolve(null)
+ }
+
+ PercyLogger.debug('Percy config created at ' + configPath)
+ resolve(configPath)
+ }
+ )
+ })
+ }
+}
+
+export default Percy
diff --git a/packages/browserstack-service/src/Percy/PercyBinary.ts b/packages/browserstack-service/src/Percy/PercyBinary.ts
new file mode 100644
index 0000000..8dc6957
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/PercyBinary.ts
@@ -0,0 +1,247 @@
+import yauzl from 'yauzl'
+import fs from 'node:fs'
+import fsp from 'node:fs/promises'
+import { pipeline } from 'node:stream/promises'
+
+import path from 'node:path'
+import os from 'node:os'
+import { spawn } from 'node:child_process'
+import { PercyLogger } from './PercyLogger.js'
+import PerformanceTester from '../instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from '../instrumentation/performance/constants.js'
+import { BStackLogger } from '../bstackLogger.js'
+
+import { _fetch as fetch } from '../fetchWrapper.js'
+
+class PercyBinary {
+ #hostOS = process.platform
+ #httpPath: string | null = null
+ #binaryName = 'percy'
+
+ #orderedPaths = [
+ path.join(os.homedir(), '.browserstack'),
+ process.cwd(),
+ os.tmpdir()
+ ]
+
+ constructor() {
+ const base = 'https://github.com/percy/cli/releases/latest/download'
+ if (this.#hostOS.match(/darwin|mac os/i)) {
+ this.#httpPath = base + '/percy-osx.zip'
+ } else if (this.#hostOS.match(/mswin|msys|mingw|cygwin|bccwin|wince|emc|win32/i)) {
+ this.#httpPath = base + '/percy-win.zip'
+ this.#binaryName = 'percy.exe'
+ } else {
+ this.#httpPath = base + '/percy-linux.zip'
+ }
+ }
+
+ async #makePath(path: string) {
+ if (await this.#checkPath(path)) {
+ return true
+ }
+ return fsp.mkdir(path).then(() => true).catch(() => false)
+ }
+
+ async #checkPath(path: string) {
+ try {
+ const hasDir = await fsp.access(path).then(() => true, () => false)
+ if (hasDir) {
+ return true
+ }
+ } catch {
+ return false
+ }
+ }
+
+ // Get the path for storing the ETag
+ #getETagPath(destParentDir: string) {
+ return path.join(destParentDir, `${this.#binaryName}.etag`)
+ }
+
+ // Load the stored ETag if it exists
+ async #loadETag(destParentDir: string) {
+ const etagPath = this.#getETagPath(destParentDir)
+ if (await this.#checkPath(etagPath)) {
+ try {
+ const data = await fsp.readFile(etagPath, 'utf8')
+ return data.trim()
+ } catch (err) {
+ BStackLogger.warn(`Failed to read ETag file ${err}`)
+ }
+ }
+ return null
+ }
+
+ // Save the ETag for future use
+ async #saveETag(destParentDir: string, etag: string) {
+ if (!etag) {return}
+ try {
+ const etagPath = this.#getETagPath(destParentDir)
+ await fsp.writeFile(etagPath, etag)
+ BStackLogger.debug('Saved new ETag for percy binary')
+ } catch (err) {
+ BStackLogger.error(`Failed to save ETag file ${err}`)
+ }
+ }
+
+ async #getAvailableDirs() {
+ for (let i = 0; i < this.#orderedPaths.length; i++) {
+ const path = this.#orderedPaths[i]
+ if (await this.#makePath(path)) {
+ return path
+ }
+ }
+ throw new Error('Error trying to download percy binary')
+ }
+
+ async getBinaryPath(): Promise {
+ const destParentDir = await this.#getAvailableDirs()
+ const binaryPath = path.join(destParentDir, this.#binaryName)
+ let response
+ if (await this.#checkPath(binaryPath)) {
+ const currentETag = await this.#loadETag(destParentDir)
+ if (currentETag) {
+ try {
+ const result = await this.#checkForUpdate(currentETag)
+ if (!result.needsUpdate) {
+ BStackLogger.debug('Percy binary is up to date (ETag unchanged)')
+ return binaryPath
+ }
+ response = result.response
+ BStackLogger.debug('New Percy binary version available, downloading update')
+ } catch (err) {
+ BStackLogger.warn(`Failed to check for binary updates, using existing binary ${err}`)
+ return binaryPath
+ }
+ }
+ }
+
+ const downloadedBinaryPath: string = await this.download(destParentDir, response)
+ const isValid = await this.validateBinary(downloadedBinaryPath)
+ if (!isValid) {
+ PercyLogger.error('Corrupt percy binary, retrying')
+ return await this.download(destParentDir, response)
+ }
+ return downloadedBinaryPath
+ }
+
+ async #checkForUpdate(currentETag: string): Promise<{ needsUpdate: boolean; response?: Response }> {
+ try {
+ const headers: HeadersInit = {
+ 'If-None-Match': currentETag
+ }
+
+ const fetchOptions: RequestInit = {
+ method: 'GET',
+ headers
+ }
+
+ const response = await fetch(this.#httpPath as unknown as URL, fetchOptions)
+
+ // If status is 304 Not Modified, binary is up-to-date
+ if (response.status === 304) {
+ return { needsUpdate: false } // No update needed
+ }
+
+ // Save the new ETag if available
+ const newETag = response.headers.get('eTag')
+ if (newETag) {
+ await this.#saveETag(path.dirname(this.#getETagPath(await this.#getAvailableDirs())), newETag)
+ }
+
+ return { needsUpdate: true, response }
+ } catch (error) {
+ BStackLogger.warn(`Error checking for Percy binary updates: ${error}`)
+ throw error
+ }
+ }
+
+ async validateBinary(binaryPath: string) {
+ const versionRegex = /^.*@percy\/cli \d.\d+.\d+/
+ /* eslint-disable @typescript-eslint/no-unused-vars */
+ return new Promise((resolve, reject) => {
+ const proc = spawn(binaryPath, ['--version'])
+ proc.stdout.on('data', (data) => {
+ if (versionRegex.test(data)) {
+ resolve(true)
+ }
+ })
+
+ proc.on('close', () => {
+ resolve(false)
+ })
+ })
+ }
+
+ @PerformanceTester.Measure(PERFORMANCE_SDK_EVENTS.PERCY_EVENTS.DOWNLOAD)
+ async download(destParentDir: string, response?: Response): Promise {
+ if (!await this.#checkPath(destParentDir)){
+ await fsp.mkdir(destParentDir)
+ }
+ const binaryName = this.#binaryName
+ const zipFilePath = path.join(destParentDir, binaryName + '.zip')
+ const binaryPath = path.join(destParentDir, binaryName)
+ const downloadedFileStream = fs.createWriteStream(zipFilePath)
+
+ if (!response) {
+ response = await fetch(this.#httpPath as unknown as URL)
+ }
+ const newETag = response.headers.get('eTag')
+ if (newETag) {
+ await this.#saveETag(destParentDir, newETag)
+ }
+ // @ts-expect-error stream type
+ await pipeline(response.body as unknown as RequestInit, downloadedFileStream)
+
+ return new Promise((resolve, reject) => {
+ yauzl.open(zipFilePath, { lazyEntries: true }, function (err, zipfile) {
+ if (err) {
+ return reject(err)
+ }
+ zipfile.readEntry()
+ zipfile.on('entry', (entry) => {
+ if (/\/$/.test(entry.fileName)) {
+ // Directory file names end with '/'.
+ zipfile.readEntry()
+ } else {
+ // file entry
+ const writeStream = fs.createWriteStream(
+ path.join(destParentDir, entry.fileName)
+ )
+ zipfile.openReadStream(entry, function (zipErr, readStream) {
+ if (zipErr) {
+ reject(err)
+ }
+ readStream.on('end', function () {
+ writeStream.close()
+ zipfile.readEntry()
+ })
+ readStream.pipe(writeStream)
+ })
+
+ if (entry.fileName === binaryName) {
+ zipfile.close()
+ }
+ }
+ })
+
+ zipfile.on('error', (zipErr) => {
+ reject(zipErr)
+ })
+
+ zipfile.once('end', () => {
+ fs.chmod(binaryPath, '0755', function (zipErr: Error) {
+ if (zipErr) {
+ reject(zipErr)
+ }
+ resolve(binaryPath)
+ })
+ zipfile.close()
+ })
+ })
+ })
+ }
+}
+
+export default PercyBinary
diff --git a/packages/browserstack-service/src/Percy/PercyCaptureMap.ts b/packages/browserstack-service/src/Percy/PercyCaptureMap.ts
new file mode 100644
index 0000000..8e6671d
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/PercyCaptureMap.ts
@@ -0,0 +1,50 @@
+/*
+ * Maintains a counter for each driver to get consistent and
+ * unique screenshot names for percy
+ */
+
+interface Map {
+ [key: string]: Record
+}
+
+class PercyCaptureMap {
+ #map: Map = {}
+
+ increment(sessionName: string, eventName: string) {
+ if (!this.#map[sessionName]) {
+ this.#map[sessionName] = {}
+ }
+
+ if (!this.#map[sessionName][eventName]) {
+ this.#map[sessionName][eventName] = 0
+ }
+
+ this.#map[sessionName][eventName]++
+ }
+
+ decrement(sessionName: string, eventName: string) {
+ if (!this.#map[sessionName] || !this.#map[sessionName][eventName]) {
+ return
+ }
+
+ this.#map[sessionName][eventName]--
+ }
+
+ getName(sessionName: string, eventName: string) {
+ return `${sessionName}-${eventName}-${this.get(sessionName, eventName)}`
+ }
+
+ get(sessionName: string, eventName: string) {
+ if (!this.#map[sessionName]) {
+ return 0
+ }
+
+ if (!this.#map[sessionName][eventName]) {
+ return 0
+ }
+
+ return this.#map[sessionName][eventName] - 1
+ }
+}
+
+export default PercyCaptureMap
diff --git a/packages/browserstack-service/src/Percy/PercyHelper.ts b/packages/browserstack-service/src/Percy/PercyHelper.ts
new file mode 100644
index 0000000..384bb52
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/PercyHelper.ts
@@ -0,0 +1,80 @@
+// ======= Percy helper methods start =======
+
+import type { Capabilities } from '@wdio/types'
+import type { BrowserstackConfig, UserConfig } from '../types.js'
+
+import type { Options } from '@wdio/types'
+
+import { PercyLogger } from './PercyLogger.js'
+import Percy from './Percy.js'
+
+export const startPercy = async (options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner, bsConfig: UserConfig): Promise => {
+ PercyLogger.debug('Starting percy')
+ const percy = new Percy(options, config, bsConfig)
+ const response = await percy.start()
+ if (response) {
+ return percy
+ }
+ return undefined
+}
+
+export const stopPercy = async (percy: Percy) => {
+ PercyLogger.debug('Stopping percy')
+ return percy.stop()
+}
+
+export const getBestPlatformForPercySnapshot = (capabilities?: Capabilities.TestrunnerCapabilities) => {
+ try {
+ const percyBrowserPreference = { 'chrome': 0, 'firefox': 1, 'edge': 2, 'safari': 3 }
+
+ let bestPlatformCaps: WebdriverIO.Capabilities | undefined
+ let bestBrowser: string | undefined
+
+ if (Array.isArray(capabilities)) {
+ capabilities
+ .flatMap((c) => {
+ if ('alwaysMatch' in c) {
+ return c.alwaysMatch as WebdriverIO.Capabilities
+ }
+
+ if (Object.values(c).length > 0 && Object.values(c).every(c => typeof c === 'object' && c.capabilities)) {
+ return Object.values(c).map((o) => o.capabilities) as WebdriverIO.Capabilities[]
+ }
+ return c as WebdriverIO.Capabilities
+ }).forEach((capability: WebdriverIO.Capabilities) => {
+ let currBrowserName = capability.browserName
+ if (capability['bstack:options']) {
+ currBrowserName = capability['bstack:options'].browserName || currBrowserName
+ }
+ // @ts-expect-error
+ if (!bestBrowser || !bestPlatformCaps || (bestPlatformCaps.deviceName || bestPlatformCaps['bstack:options']?.deviceName)) {
+ bestBrowser = currBrowserName
+ bestPlatformCaps = capability
+ } else if (currBrowserName && percyBrowserPreference[currBrowserName.toLowerCase() as keyof typeof percyBrowserPreference] < percyBrowserPreference[bestBrowser.toLowerCase() as keyof typeof percyBrowserPreference]) {
+ bestBrowser = currBrowserName
+ bestPlatformCaps = capability
+ }
+ })
+ return bestPlatformCaps
+ } else if (typeof capabilities === 'object') {
+ Object.entries(capabilities as Capabilities.RequestedMultiremoteCapabilities).forEach(([, caps]) => {
+ let currBrowserName = (caps.capabilities as WebdriverIO.Capabilities).browserName
+ if ((caps.capabilities as WebdriverIO.Capabilities)['bstack:options']) {
+ currBrowserName = (caps.capabilities as WebdriverIO.Capabilities)['bstack:options']?.browserName || currBrowserName
+ }
+ // @ts-expect-error
+ if (!bestBrowser || !bestPlatformCaps || (bestPlatformCaps.deviceName || bestPlatformCaps['bstack:options']?.deviceName)) {
+ bestBrowser = currBrowserName
+ bestPlatformCaps = (caps.capabilities as WebdriverIO.Capabilities)
+ } else if (currBrowserName && percyBrowserPreference[currBrowserName.toLowerCase() as keyof typeof percyBrowserPreference] < percyBrowserPreference[bestBrowser.toLowerCase() as keyof typeof percyBrowserPreference]) {
+ bestBrowser = currBrowserName
+ bestPlatformCaps = (caps.capabilities as WebdriverIO.Capabilities)
+ }
+ })
+ return bestPlatformCaps
+ }
+ } catch (err) {
+ PercyLogger.error(`Error while trying to determine best platform for Percy snapshot ${err}`)
+ return null
+ }
+}
diff --git a/packages/browserstack-service/src/Percy/PercyLogger.ts b/packages/browserstack-service/src/Percy/PercyLogger.ts
new file mode 100644
index 0000000..0435512
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/PercyLogger.ts
@@ -0,0 +1,78 @@
+import path from 'node:path'
+import fs from 'node:fs'
+import chalk from 'chalk'
+
+import logger from '@wdio/logger'
+
+import { PERCY_LOGS_FILE } from '../constants.js'
+import { COLORS } from '../util.js'
+
+const log = logger('@wdio/browserstack-service')
+
+export class PercyLogger {
+ public static logFilePath = path.join(process.cwd(), PERCY_LOGS_FILE)
+ private static logFolderPath = path.join(process.cwd(), 'logs')
+ private static logFileStream: fs.WriteStream | null
+
+ static logToFile(logMessage: string, logLevel: string) {
+ try {
+ if (!this.logFileStream) {
+ if (!fs.existsSync(this.logFolderPath)){
+ fs.mkdirSync(this.logFolderPath)
+ }
+ this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' })
+ }
+ if (this.logFileStream && this.logFileStream.writable) {
+ this.logFileStream.write(this.formatLog(logMessage, logLevel))
+ }
+ } catch (error) {
+ log.debug(`Failed to log to file. Error ${error}`)
+ }
+ }
+
+ private static formatLog(logMessage: string, level: string) {
+ return `${chalk.gray(new Date().toISOString())} ${chalk[COLORS[level]](level.toUpperCase())} ${chalk.whiteBright('@wdio/browserstack-service')} ${logMessage}\n`
+ }
+
+ public static info(message: string) {
+ this.logToFile(message, 'info')
+ log.info(message)
+ }
+
+ public static error(message: string) {
+ this.logToFile(message, 'error')
+ log.error(message)
+ }
+
+ public static debug(message: string, param?: unknown) {
+ this.logToFile(message, 'debug')
+ if (param) {
+ log.debug(message, param)
+ } else {
+ log.debug(message)
+ }
+ }
+
+ public static warn(message: string) {
+ this.logToFile(message, 'warn')
+ log.warn(message)
+ }
+
+ public static trace(message: string) {
+ this.logToFile(message, 'trace')
+ log.trace(message)
+ }
+
+ public static clearLogger() {
+ if (this.logFileStream) {
+ this.logFileStream.end()
+ }
+ this.logFileStream = null
+ }
+
+ public static clearLogFile() {
+ if (fs.existsSync(this.logFilePath)) {
+ fs.truncateSync(this.logFilePath)
+ }
+ }
+}
diff --git a/packages/browserstack-service/src/Percy/PercySDK.ts b/packages/browserstack-service/src/Percy/PercySDK.ts
new file mode 100644
index 0000000..9f91013
--- /dev/null
+++ b/packages/browserstack-service/src/Percy/PercySDK.ts
@@ -0,0 +1,97 @@
+import InsightsHandler from '../insights-handler.js'
+import TestReporter from '../reporter.js'
+import { PercyLogger } from './PercyLogger.js'
+import { isUndefined } from '../util.js'
+import { createRequire } from 'node:module'
+
+const require = createRequire(import.meta.url)
+
+const tryRequire = function (pkg: string, fallback: unknown) {
+ try {
+ const mod = require(pkg)
+ if (mod && typeof mod === 'object' && 'default' in mod) {
+ return (mod as { default: unknown }).default
+ }
+ return mod
+ } catch {
+ return fallback
+ }
+}
+
+const percySnapshot = tryRequire('@percy/selenium-webdriver', null)
+
+const percyAppScreenshot = tryRequire('@percy/appium-app', {})
+
+/* eslint-disable @typescript-eslint/no-unused-vars */
+let snapshotHandler = (...args: unknown[]) => {
+ PercyLogger.error('Unsupported driver for percy')
+}
+if (percySnapshot) {
+ snapshotHandler = (browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, snapshotName: string, options?: { [key: string]: unknown }) => {
+ if (process.env.PERCY_SNAPSHOT === 'true') {
+ let { name, uuid } = InsightsHandler.currentTest
+ if (isUndefined(name)) {
+ ({ name, uuid } = TestReporter.currentTest)
+ }
+ options ||= {}
+ options = {
+ ...options,
+ testCase: name || ''
+ }
+ return percySnapshot(browser, snapshotName, options)
+ }
+ }
+}
+export const snapshot = snapshotHandler
+
+/*
+This is a helper method which appends some internal fields
+to the options object being sent to Percy methods
+*/
+const screenshotHelper = (type: string, driverOrName: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser | string, nameOrOptions?: string | { [key: string]: unknown }, options?: { [key: string]: unknown }) => {
+ let { name, uuid } = InsightsHandler.currentTest
+ if (isUndefined(name)) {
+ ({ name, uuid } = TestReporter.currentTest)
+ }
+ if (!driverOrName || typeof driverOrName === 'string') {
+ nameOrOptions ||= {}
+ if (typeof nameOrOptions === 'object') {
+ nameOrOptions = {
+ ...nameOrOptions,
+ testCase: name || ''
+ }
+ }
+ } else {
+ options ||= {}
+ options = {
+ ...options,
+ testCase: name || ''
+ }
+ }
+ if (type === 'app') {
+ return percyAppScreenshot(driverOrName, nameOrOptions, options)
+ }
+ return percySnapshot.percyScreenshot(driverOrName, nameOrOptions, options)
+}
+
+/* eslint-disable @typescript-eslint/no-unused-vars */
+let screenshotHandler = async (...args: unknown[]) => {
+ PercyLogger.error('Unsupported driver for percy')
+}
+if (percySnapshot && percySnapshot.percyScreenshot) {
+ screenshotHandler = (browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser | string, screenshotName?: string | { [key: string]: unknown }, options?: { [key: string]: unknown }) => {
+ return screenshotHelper('web', browser, screenshotName, options)
+ }
+}
+export const screenshot = screenshotHandler
+
+/* eslint-disable @typescript-eslint/no-unused-vars */
+let screenshotAppHandler = async (...args: unknown[]) => {
+ PercyLogger.error('Unsupported driver for percy')
+}
+if (percyAppScreenshot) {
+ screenshotAppHandler = (driverOrName: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser | string, nameOrOptions?: string | { [key: string]: unknown }, options?: { [key: string]: unknown }) => {
+ return screenshotHelper('app', driverOrName, nameOrOptions, options)
+ }
+}
+export const screenshotApp = screenshotAppHandler
\ No newline at end of file
diff --git a/packages/browserstack-service/src/accessibility-handler.ts b/packages/browserstack-service/src/accessibility-handler.ts
new file mode 100644
index 0000000..76ae832
--- /dev/null
+++ b/packages/browserstack-service/src/accessibility-handler.ts
@@ -0,0 +1,525 @@
+///
+import util from 'node:util'
+
+import type { Capabilities, Frameworks, Options } from '@wdio/types'
+
+import type { BrowserstackConfig, BrowserstackOptions } from './types.js'
+
+import type { ITestCaseHookParameter } from './cucumber-types.js'
+
+import Listener from './testOps/listener.js'
+
+// Define better types for accessibility
+interface PlatformA11yMeta {
+ browser_name?: string
+ browser_version?: string
+ device?: string
+ platform?: string
+ [key: string]: unknown
+}
+
+interface AccessibilityOptions {
+ includeIssueType?: string[]
+ excludeIssueType?: string[]
+ [key: string]: unknown
+}
+
+interface TestMetadata {
+ [testId: string]: {
+ scanTestForAccessibility?: boolean
+ accessibilityScanStarted?: boolean
+ [key: string]: unknown
+ }
+}
+
+interface A11yScanSessionMap {
+ [sessionId: string]: boolean
+}
+
+interface CommandInfo {
+ name: string
+ class?: string
+ [key: string]: unknown
+}
+
+interface TestExtensionData {
+ thTestRunUuid?: string
+ thBuildUuid?: string
+ thJwtToken?: string
+ [key: string]: unknown
+}
+
+import {
+ getA11yResultsSummary,
+ getAppA11yResultsSummary,
+ getA11yResults,
+ performA11yScan,
+ getUniqueIdentifier,
+ getUniqueIdentifierForCucumber,
+ isAccessibilityAutomationSession,
+ isAppAccessibilityAutomationSession,
+ isBrowserstackSession,
+ o11yClassErrorHandler,
+ shouldScanTestForAccessibility,
+ validateCapsWithA11y,
+ shouldAddServiceVersion,
+ validateCapsWithNonBstackA11y,
+ isTrue,
+ validateCapsWithAppA11y,
+ getAppA11yResults,
+ executeAccessibilityScript,
+ isFalse
+} from './util.js'
+import accessibilityScripts from './scripts/accessibility-scripts.js'
+import PerformanceTester from './instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from './instrumentation/performance/constants.js'
+
+import { BStackLogger } from './bstackLogger.js'
+
+class _AccessibilityHandler {
+ private _platformA11yMeta: PlatformA11yMeta
+ private _caps: Capabilities.ResolvedTestrunnerCapabilities
+ private _suiteFile?: string
+ private _accessibility?: boolean
+ private _turboscale?: boolean
+ private _options: BrowserstackConfig & BrowserstackOptions
+ private _config: Options.Testrunner
+ private _accessibilityOptions?: AccessibilityOptions
+ private _autoScanning: boolean = true
+ private _testIdentifier: string | null = null
+ private _testMetadata: TestMetadata = {}
+ private static _a11yScanSessionMap: A11yScanSessionMap = {}
+ private _sessionId: string | null = null
+ private listener = Listener.getInstance()
+
+ constructor (
+ private _browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser,
+ _capabilities: Capabilities.ResolvedTestrunnerCapabilities,
+ _options : BrowserstackConfig & BrowserstackOptions,
+ private isAppAutomate: boolean,
+ _config : Options.Testrunner,
+ private _framework?: string,
+ _accessibilityAutomation?: boolean | string,
+ _turboscale?: boolean | string,
+ _accessibilityOpts?: AccessibilityOptions
+ ) {
+ const caps = (this._browser as WebdriverIO.Browser).capabilities as WebdriverIO.Capabilities
+
+ this._platformA11yMeta = {
+ browser_name: caps?.browserName,
+ // @ts-expect-error invalid caps property
+ browser_version: caps?.browserVersion || (caps as WebdriverIO.Capabilities)?.version || 'latest',
+ platform_name: caps?.platformName,
+ platform_version: this._getCapabilityValue(caps, 'appium:platformVersion', 'platformVersion'),
+ os_name: this._getCapabilityValue(_capabilities, 'os', 'os'),
+ os_version: this._getCapabilityValue(_capabilities, 'osVersion', 'os_version')
+ }
+
+ this._caps = _capabilities
+ this._accessibility = isTrue(_accessibilityAutomation)
+ this._accessibilityOptions = _accessibilityOpts
+ this._autoScanning = !isFalse(this._accessibilityOptions?.autoScanning)
+ this._options = _options
+ this._config= _config
+ this._turboscale = isTrue(_turboscale)
+ }
+
+ setSuiteFile(filename: string) {
+ this._suiteFile = filename
+ }
+
+ _getCapabilityValue(caps: Capabilities.ResolvedTestrunnerCapabilities, capType: string, legacyCapType: string) {
+ if (caps) {
+ if (capType === 'accessibility') {
+ if ((caps as WebdriverIO.Capabilities)['bstack:options'] && (isTrue((caps as WebdriverIO.Capabilities)['bstack:options']?.accessibility))) {
+ return (caps as WebdriverIO.Capabilities)['bstack:options']?.accessibility
+ } else if (isTrue((caps as WebdriverIO.Capabilities)['browserstack.accessibility'])) {
+ return (caps as WebdriverIO.Capabilities)['browserstack.accessibility']
+ }
+ } else if (capType === 'deviceName') {
+ if ((caps as WebdriverIO.Capabilities)['bstack:options'] && (caps as WebdriverIO.Capabilities)['bstack:options']?.deviceName) {
+ return (caps as WebdriverIO.Capabilities)['bstack:options']?.deviceName
+ } else if ((caps as WebdriverIO.Capabilities)['bstack:options'] && (caps as WebdriverIO.Capabilities)['bstack:options']?.device) {
+ return (caps as WebdriverIO.Capabilities)['bstack:options']?.device
+ } else if ((caps as WebdriverIO.Capabilities)['appium:deviceName']) {
+ return (caps as WebdriverIO.Capabilities)['appium:deviceName']
+ }
+ } else if (capType === 'goog:chromeOptions' && (caps as WebdriverIO.Capabilities)['goog:chromeOptions']) {
+ return (caps as WebdriverIO.Capabilities)['goog:chromeOptions']
+ } else {
+ const bstackOptions = (caps as WebdriverIO.Capabilities)['bstack:options']
+ if ( bstackOptions && bstackOptions?.[capType as keyof Capabilities.BrowserStackCapabilities]) {
+ return bstackOptions?.[capType as keyof Capabilities.BrowserStackCapabilities]
+ } else if ((caps as WebdriverIO.Capabilities)[legacyCapType as keyof WebdriverIO.Capabilities]) {
+ return (caps as WebdriverIO.Capabilities)[legacyCapType as keyof WebdriverIO.Capabilities]
+ }
+ }
+ }
+ }
+
+ async before(sessionId: string) {
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.CONFIG_EVENTS.ACCESSIBILITY)
+
+ this._sessionId = sessionId
+ this._accessibility = isTrue(this._getCapabilityValue(this._caps, 'accessibility', 'browserstack.accessibility'))
+
+ //checks for running ALLY on non-bstack infra
+ if (
+ isAccessibilityAutomationSession(this._accessibility) &&
+ (
+ this._turboscale ||
+ !shouldAddServiceVersion(this._config, this._options.testObservability)
+ ) &&
+ validateCapsWithNonBstackA11y(
+ this._platformA11yMeta.browser_name as string,
+ this._platformA11yMeta?.browser_version as string
+ )
+ ){
+ this._accessibility = true
+ } else {
+ if (isAccessibilityAutomationSession(this._accessibility) && !this.isAppAutomate) {
+ const deviceName = this._getCapabilityValue(this._caps, 'deviceName', 'device')
+ const chromeOptions = this._getCapabilityValue(this._caps, 'goog:chromeOptions', '') as Capabilities.ChromeOptions
+
+ this._accessibility = validateCapsWithA11y(deviceName as string, this._platformA11yMeta as unknown as Record, chromeOptions)
+ }
+ if (isAppAccessibilityAutomationSession(this._accessibility, this.isAppAutomate)) {
+ this._accessibility = validateCapsWithAppA11y(this._platformA11yMeta)
+ }
+ }
+
+ // Safely add accessibility methods to browser instance with proper typing
+ const browserWithA11y = this._browser as WebdriverIO.Browser & {
+ getAccessibilityResultsSummary: () => Promise>,
+ getAccessibilityResults: () => Promise>>,
+ performScan: () => Promise | undefined>,
+ startA11yScanning: () => Promise,
+ stopA11yScanning: () => Promise
+ }
+
+ browserWithA11y.getAccessibilityResultsSummary = async () => {
+ if (isAppAccessibilityAutomationSession(this._accessibility, this.isAppAutomate)) {
+ return await getAppA11yResultsSummary(this.isAppAutomate, (this._browser as WebdriverIO.Browser), isBrowserstackSession(this._browser), this._accessibility, this._sessionId)
+ }
+ return await getA11yResultsSummary(this.isAppAutomate, (this._browser as WebdriverIO.Browser), isBrowserstackSession(this._browser), this._accessibility)
+ }
+
+ browserWithA11y.getAccessibilityResults = async () => {
+ if (isAppAccessibilityAutomationSession(this._accessibility, this.isAppAutomate)) {
+ return await getAppA11yResults(this.isAppAutomate, (this._browser as WebdriverIO.Browser), isBrowserstackSession(this._browser), this._accessibility, this._sessionId)
+ }
+ return await getA11yResults(this.isAppAutomate, (this._browser as WebdriverIO.Browser), isBrowserstackSession(this._browser), this._accessibility)
+ }
+
+ browserWithA11y.performScan = async () => {
+ const results = await performA11yScan(this.isAppAutomate, (this._browser as WebdriverIO.Browser), isBrowserstackSession(this._browser), this._accessibility)
+ if (results) {
+ this._testMetadata[this._testIdentifier as string] = {
+ scanTestForAccessibility : true,
+ accessibilityScanStarted : true
+ }
+ }
+ await this._setAnnotation('Accessibility scanning was triggered manually')
+ return results
+ }
+
+ browserWithA11y.startA11yScanning = async () => {
+ if (this._testIdentifier === null){
+ BStackLogger.warn('Accessibility scanning cannot be started from outside the test')
+ return
+ }
+ AccessibilityHandler._a11yScanSessionMap[sessionId] = true
+ this._testMetadata[this._testIdentifier as string] = {
+ scanTestForAccessibility : true,
+ accessibilityScanStarted : true
+ }
+ await this._setAnnotation('Accessibility scanning has started')
+ }
+
+ browserWithA11y.stopA11yScanning = async () => {
+ if (this._testIdentifier === null){
+ BStackLogger.warn('Accessibility scanning cannot be stopped from outside the test')
+ return
+ }
+ AccessibilityHandler._a11yScanSessionMap[sessionId] = false
+ await this._setAnnotation('Accessibility scanning has stopped')
+ }
+
+ if (!this._accessibility) {
+ return
+ }
+ if (!('overwriteCommand' in this._browser && Array.isArray(accessibilityScripts.commandsToWrap))) {
+ return
+ }
+
+ accessibilityScripts.commandsToWrap
+ .filter((command) => command.name && command.class)
+ .forEach((command) => {
+ const browser = this._browser as WebdriverIO.Browser
+ try {
+ // element commands aren't on browser; use orig when present, otherwise rely on overwriteCommand's origFunction
+ const orig = browser[command.name as keyof WebdriverIO.Browser]
+ const prevImpl = orig ? orig.bind(browser) : undefined
+ // @ts-expect-error fix type
+ browser.overwriteCommand(command.name, this.commandWrapper.bind(this, command, prevImpl), command.class === 'Element')
+ } catch (error) {
+ BStackLogger.debug(`Exception in overwrite command ${command.name} - ${error}`)
+ }
+ })
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.CONFIG_EVENTS.ACCESSIBILITY)
+
+ }
+
+ async beforeTest (suiteTitle: string | undefined, test: Frameworks.Test) {
+ try {
+ if (
+ this._framework !== 'mocha' ||
+ !this.shouldRunTestHooks(this._browser, this._accessibility)
+ ) {
+ /* This is to be used when test events are sent */
+ Listener.setTestRunAccessibilityVar(false)
+ return
+ }
+
+ // @ts-expect-error fix type
+ const shouldScanTest = this._autoScanning && shouldScanTestForAccessibility(suiteTitle, test.title, this._accessibilityOptions)
+ const testIdentifier = this.getIdentifier(test)
+ this._testIdentifier = testIdentifier
+
+ if (this._sessionId) {
+ /* For case with multiple tests under one browser, before hook of 2nd test should change this map value */
+ AccessibilityHandler._a11yScanSessionMap[this._sessionId] = shouldScanTest
+ }
+
+ /* This is to be used when test events are sent */
+ Listener.setTestRunAccessibilityVar(this._accessibility && shouldScanTest)
+
+ this._testMetadata[testIdentifier] = {
+ scanTestForAccessibility : shouldScanTest,
+ accessibilityScanStarted : true
+ }
+
+ this._testMetadata[testIdentifier].accessibilityScanStarted = shouldScanTest
+
+ if (shouldScanTest) {
+ BStackLogger.info('Automate test case execution has started.')
+ }
+ } catch (error) {
+ BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`)
+ }
+ }
+
+ async afterTest (suiteTitle: string | undefined, test: Frameworks.Test) {
+ BStackLogger.debug('Accessibility after test hook. Before sending test stop event')
+ if (
+ this._framework !== 'mocha' ||
+ !this.shouldRunTestHooks(this._browser, this._accessibility)
+ ) {
+ return
+ }
+
+ try {
+ const testIdentifier = this.getIdentifier(test)
+ const accessibilityScanStarted = this._testMetadata[testIdentifier]?.accessibilityScanStarted
+ const shouldScanTestForAccessibility = this._testMetadata[testIdentifier]?.scanTestForAccessibility
+
+ if (!accessibilityScanStarted) {
+ return
+ }
+
+ if (shouldScanTestForAccessibility) {
+ BStackLogger.info('Automate test case execution has ended. Processing for accessibility testing is underway. ')
+
+ const dataForExtension = {
+ 'thTestRunUuid': process.env.TEST_ANALYTICS_ID,
+ 'thBuildUuid': process.env.BROWSERSTACK_TESTHUB_UUID,
+ 'thJwtToken': process.env.BROWSERSTACK_TESTHUB_JWT
+ }
+
+ await this.sendTestStopEvent((this._browser as WebdriverIO.Browser), dataForExtension)
+
+ BStackLogger.info('Accessibility testing for this test case has ended.')
+ }
+ } catch (error) {
+ BStackLogger.error(`Accessibility results could not be processed for the test case ${test.title}. Error : ${error}`)
+ }
+ }
+
+ /**
+ * Cucumber Only
+ */
+ async beforeScenario (world: ITestCaseHookParameter) {
+ const pickleData = world.pickle
+ const gherkinDocument = world.gherkinDocument
+ const featureData = gherkinDocument.feature
+ const uniqueId = getUniqueIdentifierForCucumber(world)
+ this._testIdentifier = uniqueId
+ if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
+ /* This is to be used when test events are sent */
+ Listener.setTestRunAccessibilityVar(false)
+ return
+ }
+
+ try {
+ // @ts-expect-error fix type
+ const shouldScanScenario = this._autoScanning && shouldScanTestForAccessibility(featureData?.name, pickleData.name, this._accessibilityOptions, world, true)
+ this._testMetadata[uniqueId] = {
+ scanTestForAccessibility : shouldScanScenario,
+ accessibilityScanStarted : true
+ }
+
+ this._testMetadata[uniqueId].accessibilityScanStarted = shouldScanScenario
+ if (this._sessionId) {
+ /* For case with multiple tests under one browser, before hook of 2nd test should change this map value */
+ AccessibilityHandler._a11yScanSessionMap[this._sessionId] = shouldScanScenario
+ }
+
+ /* This is to be used when test events are sent */
+ Listener.setTestRunAccessibilityVar(this._accessibility && shouldScanScenario)
+
+ if (shouldScanScenario) {
+ BStackLogger.info('Automate test case execution has started.')
+ }
+ } catch (error) {
+ BStackLogger.error(`Exception in starting accessibility automation scan for this test case ${error}`)
+ }
+ }
+
+ async afterScenario (world: ITestCaseHookParameter) {
+ BStackLogger.debug('Accessibility after scenario hook. Before sending test stop event')
+ if (!this.shouldRunTestHooks(this._browser, this._accessibility)) {
+ return
+ }
+
+ const pickleData = world.pickle
+ try {
+ const uniqueId = getUniqueIdentifierForCucumber(world)
+ const accessibilityScanStarted = this._testMetadata[uniqueId]?.accessibilityScanStarted
+ const shouldScanTestForAccessibility = this._testMetadata[uniqueId]?.scanTestForAccessibility
+
+ if (!accessibilityScanStarted) {
+ return
+ }
+
+ if (shouldScanTestForAccessibility) {
+ BStackLogger.info('Automate test case execution has ended. Processing for accessibility testing is underway. ')
+
+ const dataForExtension = {
+ 'thTestRunUuid': process.env.TEST_ANALYTICS_ID,
+ 'thBuildUuid': process.env.BROWSERSTACK_TESTHUB_UUID,
+ 'thJwtToken': process.env.BROWSERSTACK_TESTHUB_JWT
+ }
+
+ await this.sendTestStopEvent(( this._browser as WebdriverIO.Browser), dataForExtension)
+
+ BStackLogger.info('Accessibility testing for this test case has ended.')
+ }
+ } catch (error) {
+ BStackLogger.error(`Accessibility results could not be processed for the test case ${pickleData.name}. Error : ${error}`)
+ }
+ }
+
+ /*
+ * private methods
+ */
+
+ private async commandWrapper (command: CommandInfo, prevImpl: Function, origFunction: Function, ...args: unknown[]) {
+ if (
+ this._sessionId && AccessibilityHandler._a11yScanSessionMap[this._sessionId] &&
+ (
+ !command.name.includes('execute') ||
+ !AccessibilityHandler.shouldPatchExecuteScript(args.length ? args[0] as string : null)
+ )
+ ) {
+ BStackLogger.debug(`Performing scan for ${command.class} ${command.name}`)
+ await performA11yScan(this.isAppAutomate, this._browser, true, true, command.name)
+ }
+ const impl = prevImpl || origFunction
+ return impl(...args)
+ }
+
+ private async sendTestStopEvent(browser: WebdriverIO.Browser, dataForExtension: TestExtensionData) {
+ BStackLogger.debug('Performing scan before saving results')
+ if (AccessibilityHandler._a11yScanSessionMap[this._sessionId as string]) {
+ await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.PERFORM_SCAN, async () => {
+ await performA11yScan(this.isAppAutomate, browser, true, true)
+ }, { command: 'afterTest' })()
+ }
+
+ if (isAppAccessibilityAutomationSession(this._accessibility, this.isAppAutomate)) {
+ return
+ }
+
+ await PerformanceTester.measureWrapper(PERFORMANCE_SDK_EVENTS.A11Y_EVENTS.SAVE_RESULTS, async () => {
+ if (accessibilityScripts.saveTestResults) {
+ const results: unknown = await executeAccessibilityScript(browser, accessibilityScripts.saveTestResults, dataForExtension)
+ BStackLogger.debug(util.format(results as string))
+ } else {
+ BStackLogger.error('saveTestResults script is null or undefined')
+ }
+ })()
+
+ }
+
+ private getIdentifier (test: Frameworks.Test | ITestCaseHookParameter) {
+ if ('pickle' in test) {
+ return getUniqueIdentifierForCucumber(test)
+ }
+ return getUniqueIdentifier(test, this._framework)
+ }
+
+ private shouldRunTestHooks(browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser | null, isAccessibility?: boolean | string) {
+ if (!browser) {
+ return false
+ }
+ return isAccessibilityAutomationSession(isAccessibility)
+ }
+
+ private async checkIfPageOpened(browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, testIdentifier: string, shouldScanTest?: boolean) {
+ let pageOpen = false
+ this._testMetadata[testIdentifier] = {
+ scanTestForAccessibility : shouldScanTest,
+ accessibilityScanStarted : true
+ }
+
+ try {
+ const currentURL = await (browser as WebdriverIO.Browser).getUrl()
+ const url = new URL(currentURL)
+ pageOpen = url?.protocol === 'http:' || url?.protocol === 'https:'
+ } catch {
+ pageOpen = false
+ }
+
+ return pageOpen
+ }
+
+ private static shouldPatchExecuteScript(script: string | null): boolean {
+ if (!script || typeof script !== 'string') {
+ return true
+ }
+
+ return (
+ script.toLowerCase().indexOf('browserstack_executor') !== -1 ||
+ script.toLowerCase().indexOf('browserstack_accessibility_automation_script') !== -1
+ )
+ }
+
+ private async _setAnnotation(message: string) {
+ if (this._accessibility && isBrowserstackSession(this._browser)) {
+ await (this._browser as WebdriverIO.Browser).executeScript(`browserstack_executor: ${JSON.stringify({
+ action: 'annotate',
+ arguments: {
+ data: message,
+ level: 'info'
+ }
+ })}`, [])
+ }
+ }
+}
+
+// https://github.com/microsoft/TypeScript/issues/6543
+const AccessibilityHandler: typeof _AccessibilityHandler = o11yClassErrorHandler(_AccessibilityHandler)
+type AccessibilityHandler = _AccessibilityHandler
+
+export default AccessibilityHandler
+
diff --git a/packages/browserstack-service/src/ai-handler.ts b/packages/browserstack-service/src/ai-handler.ts
new file mode 100644
index 0000000..2664ed9
--- /dev/null
+++ b/packages/browserstack-service/src/ai-handler.ts
@@ -0,0 +1,239 @@
+import path from 'node:path'
+import fs from 'node:fs'
+import url from 'node:url'
+import aiSDK from '@browserstack/ai-sdk-node'
+import { BStackLogger } from './bstackLogger.js'
+import { TCG_URL, TCG_INFO, SUPPORTED_BROWSERS_FOR_AI, BSTACK_SERVICE_VERSION, BSTACK_TCG_AUTH_RESULT } from './constants.js'
+import { handleHealingInstrumentation } from './instrumentation/funnelInstrumentation.js'
+
+import type { Capabilities } from '@wdio/types'
+import type BrowserStackConfig from './config.js'
+import type { Options } from '@wdio/types'
+import type { BrowserstackHealing } from '@browserstack/ai-sdk-node'
+import { getBrowserStackUserAndKey, isBrowserstackInfra } from './util.js'
+import type { BrowserstackOptions } from './types.js'
+import PerformanceTester from './instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from './instrumentation/performance/constants.js'
+
+class AiHandler {
+ authResult: BrowserstackHealing.InitSuccessResponse | BrowserstackHealing.InitErrorResponse
+ wdioBstackVersion: string
+ constructor() {
+ this.authResult = JSON.parse(process.env[BSTACK_TCG_AUTH_RESULT] || '{}')
+ this.wdioBstackVersion = BSTACK_SERVICE_VERSION
+ }
+
+ async authenticateUser(user: string, key: string) {
+ return await aiSDK.BrowserstackHealing.init(key, user, TCG_URL, this.wdioBstackVersion)
+ }
+
+ updateCaps(
+ authResult: BrowserstackHealing.InitSuccessResponse | BrowserstackHealing.InitErrorResponse,
+ options: BrowserstackOptions,
+ caps: Array | Capabilities.ResolvedTestrunnerCapabilities
+ ) {
+ const installExtCondition = authResult.isAuthenticated === true && (authResult.defaultLogDataEnabled === true || options.selfHeal === true)
+ if (installExtCondition){
+ if (Array.isArray(caps)) {
+ const newCaps= aiSDK.BrowserstackHealing.initializeCapabilities(caps[0])
+ caps[0] = newCaps
+ } else if (typeof caps === 'object') {
+ caps = aiSDK.BrowserstackHealing.initializeCapabilities(caps)
+ }
+ } else if (options.selfHeal === true) {
+ const healingWarnMessage = (authResult as aiSDK.BrowserstackHealing.InitErrorResponse).message
+ BStackLogger.warn(`Healing Auth failed. Disabling healing for this session. Reason: ${healingWarnMessage}`)
+ }
+
+ return caps
+ }
+
+ async setToken(sessionId: string, sessionToken: string){
+ await aiSDK.BrowserstackHealing.setToken(sessionId, sessionToken, TCG_URL)
+ }
+
+ async installFirefoxExtension(browser: WebdriverIO.Browser){
+ const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
+ const extensionPath = path.resolve(__dirname, aiSDK.BrowserstackHealing.getFirefoxAddonPath())
+ const extFile = fs.readFileSync(extensionPath)
+ await browser.installAddOn(extFile.toString('base64'), true)
+ }
+
+ async handleHealing(orginalFunc: (arg0: string, arg1: string) => { error?: string }, using: string, value: string, browser: WebdriverIO.Browser, options: BrowserstackOptions){
+ const sessionId = browser.sessionId
+
+ // a utility function to escape single and double quotes
+ const escapeString = (str: string) => str.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t')
+
+ const tcgDetails = escapeString(JSON.stringify({
+ region: TCG_INFO.tcgRegion,
+ tcgUrls: {
+ [TCG_INFO.tcgRegion]: {
+ endpoint: TCG_INFO.tcgUrl.split('://')[1]
+ }
+ }
+ }))
+
+ const locatorType = escapeString(using)
+ const locatorValue = escapeString(value)
+
+ this.authResult = this.authResult as BrowserstackHealing.InitSuccessResponse
+
+ try {
+ const result = await orginalFunc(using, value)
+ if (!result.error) {
+ const script = await aiSDK.BrowserstackHealing.logData(locatorType, locatorValue, undefined, undefined, this.authResult.groupId, sessionId, undefined, tcgDetails)
+ if (script) {
+ await browser.execute(script)
+ }
+ return result
+ }
+ if (options.selfHeal === true && this.authResult.isHealingEnabled) {
+ BStackLogger.info('findElement failed, trying to heal')
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_STEP)
+ const script = await aiSDK.BrowserstackHealing.healFailure(locatorType, locatorValue, undefined, undefined, this.authResult.userId, this.authResult.groupId, sessionId, undefined, undefined, this.authResult.isGroupAIEnabled, tcgDetails)
+ if (script) {
+ await browser.execute(script)
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_GET_RESULT)
+ const tcgData = await aiSDK.BrowserstackHealing.pollResult(TCG_URL, sessionId, this.authResult.sessionToken)
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_GET_RESULT)
+ if (tcgData && tcgData.selector && tcgData.value){
+ const healedResult = await orginalFunc(tcgData.selector, tcgData.value)
+ BStackLogger.info('Healing worked, element found: ' + tcgData.selector + ': ' + tcgData.value)
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_STEP)
+ return healedResult.error ? result : healedResult
+ }
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_STEP, false, 'No healed result found')
+ } else {
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_STEP, false, 'No healing script generated')
+ }
+ }
+ } catch (err) {
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.AI_EVENTS.SELF_HEAL_STEP, false, String(err))
+ if (options.selfHeal === true) {
+ BStackLogger.warn('Something went wrong while healing. Disabling healing for this command')
+ } else {
+ BStackLogger.warn('Error in findElement: ' + err + 'using: ' + using + 'value: ' + value)
+ }
+ }
+ return await orginalFunc(using, value)
+ }
+
+ addMultiRemoteCaps (
+ authResult: BrowserstackHealing.InitSuccessResponse | BrowserstackHealing.InitErrorResponse,
+ config: Options.Testrunner,
+ browserStackConfig: BrowserStackConfig,
+ options: BrowserstackOptions,
+ caps: Capabilities.RequestedMultiremoteCapabilities,
+ browser: string
+ ) {
+ if ( caps[browser].capabilities &&
+ !(isBrowserstackInfra(caps[browser])) &&
+ SUPPORTED_BROWSERS_FOR_AI.includes((caps[browser]?.capabilities as WebdriverIO.Capabilities)?.browserName?.toLowerCase() || 'unknown browser')
+ ) {
+ const innerConfig = getBrowserStackUserAndKey(config, options)
+ if (innerConfig?.user && innerConfig.key) {
+ // @ts-expect-error fix type
+ handleHealingInstrumentation(authResult, browserStackConfig, options.selfHeal)
+ caps[browser].capabilities = this.updateCaps(authResult, options, caps[browser].capabilities as WebdriverIO.Capabilities) as WebdriverIO.Capabilities
+ }
+ }
+ }
+
+ handleMultiRemoteSetup(
+ authResult: BrowserstackHealing.InitSuccessResponse | BrowserstackHealing.InitErrorResponse,
+ config: Options.Testrunner,
+ browserStackConfig: BrowserStackConfig,
+ options: BrowserstackOptions,
+ caps: Capabilities.RequestedMultiremoteCapabilities,
+ ) {
+ const browserNames = Object.keys(caps)
+ for (let i = 0; i < browserNames.length; i++) {
+ const browser = browserNames[i]
+ this.addMultiRemoteCaps(authResult, config, browserStackConfig, options, caps, browser)
+ }
+ }
+
+ async setup(
+ config: Options.Testrunner,
+ browserStackConfig: BrowserStackConfig,
+ options: BrowserstackOptions,
+ caps: WebdriverIO.Capabilities,
+ isMultiremote: boolean
+ ) {
+ try {
+ const innerConfig = getBrowserStackUserAndKey(config, options)
+ if (innerConfig?.user && innerConfig.key) {
+ const authResult = await this.authenticateUser(innerConfig.user, innerConfig.key)
+ process.env[BSTACK_TCG_AUTH_RESULT] = JSON.stringify(authResult)
+ if (!isMultiremote && SUPPORTED_BROWSERS_FOR_AI.includes(caps.browserName?.toLowerCase() || 'unknown browser')) {
+
+ // @ts-expect-error fix type
+ handleHealingInstrumentation(authResult, browserStackConfig, options.selfHeal)
+ this.updateCaps(authResult, options, caps)
+
+ } else if (isMultiremote) {
+ this.handleMultiRemoteSetup(authResult, config, browserStackConfig, options, caps as unknown as Capabilities.RequestedMultiremoteCapabilities)
+ }
+ }
+
+ } catch (err) {
+ if (options.selfHeal === true) {
+ BStackLogger.warn(`Error while initiliazing Browserstack healing Extension ${err}`)
+ }
+ }
+
+ return caps
+ }
+
+ async handleSelfHeal(options: BrowserstackOptions, browser: WebdriverIO.Browser) {
+
+ if (SUPPORTED_BROWSERS_FOR_AI.includes((browser.capabilities as Capabilities.BrowserStackCapabilities)?.browserName?.toLowerCase() as string)) {
+ const authInfo = this.authResult as BrowserstackHealing.InitSuccessResponse
+
+ if (Object.keys(authInfo).length === 0 && options.selfHeal === true) {
+ BStackLogger.debug('TCG Auth result is empty')
+ return
+ }
+
+ const { isAuthenticated, sessionToken, defaultLogDataEnabled } = authInfo
+
+ if (isAuthenticated && (defaultLogDataEnabled === true || options.selfHeal === true)) {
+ await this.setToken(browser.sessionId, sessionToken)
+
+ if ((browser.capabilities as Capabilities.BrowserStackCapabilities).browserName === 'firefox') {
+ await this.installFirefoxExtension(browser)
+ }
+
+ // @ts-expect-error fix type
+ browser.overwriteCommand('findElement', async (orginalFunc: unknown, using: string, value: string) => {
+ // @ts-expect-error fix type
+ return await this.handleHealing(orginalFunc, using, value, browser, options)
+ })
+ }
+ }
+ }
+
+ async selfHeal(options: BrowserstackOptions, caps: Capabilities.ResolvedTestrunnerCapabilities, browser: WebdriverIO.Browser) {
+ try {
+
+ const multiRemoteBrowsers = Object.keys(caps).filter(e => Object.keys(browser).includes(e))
+ if (multiRemoteBrowsers.length > 0) {
+ for (let i = 0; i < multiRemoteBrowsers.length; i++) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const remoteBrowser = (browser as any)[multiRemoteBrowsers[i]]
+ await this.handleSelfHeal(options, remoteBrowser)
+ }
+ } else {
+ await this.handleSelfHeal(options, browser)
+ }
+
+ } catch (err) {
+ if (options.selfHeal === true) {
+ BStackLogger.warn(`Error while setting up self-healing: ${err}. Disabling healing for this session.`)
+ }
+ }
+ }
+}
+
+export default new AiHandler()
diff --git a/packages/browserstack-service/src/bstackLogger.ts b/packages/browserstack-service/src/bstackLogger.ts
new file mode 100644
index 0000000..b397fd8
--- /dev/null
+++ b/packages/browserstack-service/src/bstackLogger.ts
@@ -0,0 +1,94 @@
+import path from 'node:path'
+import fs from 'node:fs'
+import chalk from 'chalk'
+
+import logger from '@wdio/logger'
+
+import { LOGS_FILE } from './constants.js'
+import { COLORS } from './util.js'
+
+const log = logger('@wdio/browserstack-service')
+
+export class BStackLogger {
+ public static logFilePath = path.join(process.cwd(), LOGS_FILE)
+ public static logFolderPath = path.join(process.cwd(), 'logs')
+ private static logFileStream: fs.WriteStream | null
+
+ private static redactCredentials(logMessage: string): string {
+ return logMessage
+ .replace(/(["']?(?:username|userName|accesskey|accessKey|user|key)["']?\s*[:=]\s*["']?)([^"'\s,}]+)/gi, '$1')
+ .replace(/([?&](?:username|userName|access_key|accesskey|accessKey|user|key)=)([^\s]+)/gi, '$1')
+ }
+
+ static logToFile(logMessage: string, logLevel: string) {
+ try {
+ const redactedMessage = this.redactCredentials(logMessage)
+ if (!this.logFileStream) {
+ this.ensureLogsFolder()
+ this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' })
+ }
+ if (this.logFileStream && this.logFileStream.writable) {
+ this.logFileStream.write(this.formatLog(redactedMessage, logLevel))
+ }
+ } catch (error) {
+ log.debug(`Failed to log to file. Error ${error}`)
+ }
+ }
+
+ private static formatLog(logMessage: string, level: string) {
+ return `${chalk.gray(new Date().toISOString())} ${chalk[COLORS[level]](level.toUpperCase())} ${chalk.whiteBright('@wdio/browserstack-service')} ${logMessage}\n`
+ }
+
+ public static info(message: string) {
+ const redactedMessage = this.redactCredentials(message)
+ this.logToFile(redactedMessage, 'info')
+ log.info(redactedMessage)
+ }
+
+ public static error(message: string) {
+ const redactedMessage = this.redactCredentials(message)
+ this.logToFile(redactedMessage, 'error')
+ log.error(redactedMessage)
+ }
+
+ public static debug(message: string, param?: unknown) {
+ const redactedMessage = this.redactCredentials(message)
+ this.logToFile(redactedMessage, 'debug')
+ if (param) {
+ log.debug(redactedMessage, param)
+ } else {
+ log.debug(redactedMessage)
+ }
+ }
+
+ public static warn(message: string) {
+ const redactedMessage = this.redactCredentials(message)
+ this.logToFile(redactedMessage, 'warn')
+ log.warn(redactedMessage)
+ }
+
+ public static trace(message: string) {
+ const redactedMessage = this.redactCredentials(message)
+ this.logToFile(redactedMessage, 'trace')
+ log.trace(redactedMessage)
+ }
+
+ public static clearLogger() {
+ if (this.logFileStream) {
+ this.logFileStream.end()
+ }
+ this.logFileStream = null
+ }
+
+ public static clearLogFile() {
+ if (fs.existsSync(this.logFilePath)) {
+ fs.truncateSync(this.logFilePath)
+ }
+ }
+
+ public static ensureLogsFolder() {
+ if (!fs.existsSync(this.logFolderPath)){
+ fs.mkdirSync(this.logFolderPath)
+ }
+ }
+}
diff --git a/packages/browserstack-service/src/cleanup.ts b/packages/browserstack-service/src/cleanup.ts
new file mode 100644
index 0000000..3f48bfc
--- /dev/null
+++ b/packages/browserstack-service/src/cleanup.ts
@@ -0,0 +1,108 @@
+import { getErrorString, stopBuildUpstream } from './util.js'
+import { BStackLogger } from './bstackLogger.js'
+import fs from 'node:fs'
+import util from 'node:util'
+import { fireFunnelRequest } from './instrumentation/funnelInstrumentation.js'
+import { BROWSERSTACK_TESTHUB_UUID, BROWSERSTACK_TESTHUB_JWT, BROWSERSTACK_OBSERVABILITY } from './constants.js'
+import type { FunnelData } from './types.js'
+import PerformanceTester from './instrumentation/performance/performance-tester.js'
+
+export default class BStackCleanup {
+ static async startCleanup() {
+ try {
+ // Get funnel data object from saved file
+ const funnelDataCleanup = process.argv.includes('--funnelData')
+ let funnelData: FunnelData | null = null
+ if (funnelDataCleanup) {
+ const index = process.argv.indexOf('--funnelData')
+ const filePath = process.argv[index + 1]
+ funnelData = BStackCleanup.getFunnelDataFromFile(filePath)
+ }
+
+ if (process.argv.includes('--observability') && funnelData) {
+ await this.executeObservabilityCleanup(funnelData)
+ }
+
+ if (funnelDataCleanup && funnelData) {
+ await this.sendFunnelData(funnelData)
+ }
+ } catch (err) {
+ const error = err as string
+ BStackLogger.error(error)
+ }
+
+ try {
+ if (process.argv.includes('--performanceData')) {
+ await PerformanceTester.uploadEventsData()
+ }
+ } catch (er) {
+ BStackLogger.debug(`Error in sending events data ${util.format(er)}`)
+ }
+ }
+ static async executeObservabilityCleanup(funnelData: FunnelData) {
+ if (!process.env[BROWSERSTACK_TESTHUB_JWT]) {
+ return
+ }
+ BStackLogger.debug('Executing Test Reporting and Analytics cleanup')
+ try {
+ const result = await stopBuildUpstream()
+ if ((process.env[BROWSERSTACK_OBSERVABILITY]) && process.env[BROWSERSTACK_TESTHUB_UUID]) {
+ BStackLogger.info(`\nVisit https://automation.browserstack.com/builds/${process.env[BROWSERSTACK_TESTHUB_UUID]} to view build report, insights, and many more debugging information all at one place!\n`)
+ }
+ const status = (result && result.status) || 'failed'
+ const message = (result && result.message)
+ this.updateO11yStopData(funnelData, status, status === 'failed' ? message : undefined)
+ } catch (e: unknown) {
+ BStackLogger.error('Error in stopping Test Reporting and Analytics build: ' + e)
+ this.updateO11yStopData(funnelData, 'failed', e)
+ }
+ }
+
+ static updateO11yStopData(funnelData: FunnelData, status: string, error: unknown = undefined) {
+ const toData = funnelData?.event_properties?.productUsage?.testObservability
+ // Return if no Test Reporting and Analytics data in funnel data
+ if (!toData) {
+ return
+ }
+ let existingStopData = toData.events.buildEvents.finished
+ existingStopData = existingStopData || {}
+
+ existingStopData = {
+ ...existingStopData,
+ status,
+ error: getErrorString(error),
+ stoppedFrom: 'exitHook'
+ }
+ toData.events.buildEvents.finished = existingStopData
+ }
+
+ static async sendFunnelData(funnelData: FunnelData) {
+ try {
+ await fireFunnelRequest(funnelData)
+ BStackLogger.debug('Funnel data sent successfully from cleanup')
+ } catch (e: unknown) {
+ BStackLogger.error('Error in sending funnel data: ' + e)
+ }
+ }
+
+ static getFunnelDataFromFile(filePath: string) {
+ if (!filePath) {
+ return null
+ }
+
+ const content = fs.readFileSync(filePath, 'utf8')
+
+ const data = JSON.parse(content)
+ this.removeFunnelDataFile(filePath)
+ return data
+ }
+
+ static removeFunnelDataFile(filePath?: string) {
+ if (!filePath) {
+ return
+ }
+ fs.rmSync(filePath, { force: true })
+ }
+}
+
+void BStackCleanup.startCleanup()
diff --git a/packages/browserstack-service/src/cli/apiUtils.ts b/packages/browserstack-service/src/cli/apiUtils.ts
new file mode 100644
index 0000000..9eabcae
--- /dev/null
+++ b/packages/browserstack-service/src/cli/apiUtils.ts
@@ -0,0 +1,25 @@
+export default class APIUtils {
+ static FUNNEL_INSTRUMENTATION_URL = 'https://api.browserstack.com/sdk/v1/event'
+ static BROWSERSTACK_AUTOMATE_API_URL = 'https://api.browserstack.com'
+ static BROWSERSTACK_AA_API_URL = 'https://api.browserstack.com'
+ static BROWSERSTACK_PERCY_API_URL = 'https://api.browserstack.com'
+ static BROWSERSTACK_AUTOMATE_API_CLOUD_URL = 'https://api-cloud.browserstack.com'
+ static BROWSERSTACK_AA_API_CLOUD_URL = 'https://api-cloud.browserstack.com'
+ static APP_ALLY_ENDPOINT = 'https://app-accessibility.browserstack.com/automate'
+ static DATA_ENDPOINT = 'https://collector-observability.browserstack.com'
+ static UPLOAD_LOGS_ADDRESS = 'https://upload-observability.browserstack.com'
+ static EDS_URL = 'https://eds.browserstack.com'
+
+ static updateURLSForGRR(apis: GRRUrls) {
+ this.FUNNEL_INSTRUMENTATION_URL = `${apis.automate.api}/sdk/v1/event`
+ this.BROWSERSTACK_AUTOMATE_API_URL = apis.automate.api
+ this.BROWSERSTACK_AA_API_URL = apis.appAutomate.api
+ this.BROWSERSTACK_PERCY_API_URL = apis.percy.api
+ this.BROWSERSTACK_AUTOMATE_API_CLOUD_URL = apis.automate.upload
+ this.BROWSERSTACK_AA_API_CLOUD_URL = apis.appAutomate.upload
+ this.APP_ALLY_ENDPOINT = `${apis.appAccessibility.api}/automate`
+ this.DATA_ENDPOINT = apis.observability.api
+ this.UPLOAD_LOGS_ADDRESS = apis.observability.upload
+ this.EDS_URL = apis.edsInstrumentation.api
+ }
+}
diff --git a/packages/browserstack-service/src/cli/cliLogger.ts b/packages/browserstack-service/src/cli/cliLogger.ts
new file mode 100644
index 0000000..0941c2c
--- /dev/null
+++ b/packages/browserstack-service/src/cli/cliLogger.ts
@@ -0,0 +1,82 @@
+import path from 'node:path'
+import fs from 'node:fs'
+import chalk from 'chalk'
+
+import logger from '@wdio/logger'
+
+import { LOGS_FILE } from '../constants.js'
+import { COLORS } from '../util.js'
+
+const log = logger('@wdio/browserstack-service/cli')
+
+export class BStackLogger {
+ public static logFilePath = path.join(process.cwd(), LOGS_FILE)
+ public static logFolderPath = path.join(process.cwd(), 'logs')
+ private static logFileStream: fs.WriteStream | null
+
+ static logToFile(logMessage: string, logLevel: string) {
+ try {
+ if (!this.logFileStream) {
+ this.ensureLogsFolder()
+ this.logFileStream = fs.createWriteStream(this.logFilePath, { flags: 'a' })
+ }
+ if (this.logFileStream && this.logFileStream.writable) {
+ this.logFileStream.write(this.formatLog(logMessage, logLevel))
+ }
+ } catch (error) {
+ log.debug(`Failed to log to file. Error ${error}`)
+ }
+ }
+
+ private static formatLog(logMessage: string, level: string) {
+ return `${chalk.gray(new Date().toISOString())} ${chalk[COLORS[level]](level.toUpperCase())} ${chalk.whiteBright('@wdio/browserstack-service')} ${logMessage}\n`
+ }
+
+ public static info(message: string) {
+ this.logToFile(message, 'info')
+ log.info(message)
+ }
+
+ public static error(message: string) {
+ this.logToFile(message, 'error')
+ log.error(message)
+ }
+
+ public static debug(message: string, param?: unknown) {
+ this.logToFile(message, 'debug')
+ if (param) {
+ log.debug(message, param)
+ } else {
+ log.debug(message)
+ }
+ }
+
+ public static warn(message: string) {
+ this.logToFile(message, 'warn')
+ log.warn(message)
+ }
+
+ public static trace(message: string) {
+ this.logToFile(message, 'trace')
+ log.trace(message)
+ }
+
+ public static clearLogger() {
+ if (this.logFileStream) {
+ this.logFileStream.end()
+ }
+ this.logFileStream = null
+ }
+
+ public static clearLogFile() {
+ if (fs.existsSync(this.logFilePath)) {
+ fs.truncateSync(this.logFilePath)
+ }
+ }
+
+ public static ensureLogsFolder() {
+ if (!fs.existsSync(this.logFolderPath)){
+ fs.mkdirSync(this.logFolderPath)
+ }
+ }
+}
diff --git a/packages/browserstack-service/src/cli/cliUtils.ts b/packages/browserstack-service/src/cli/cliUtils.ts
new file mode 100644
index 0000000..f11bf1b
--- /dev/null
+++ b/packages/browserstack-service/src/cli/cliUtils.ts
@@ -0,0 +1,984 @@
+import fs from 'node:fs'
+import fsp from 'node:fs/promises'
+import { platform, arch, homedir } from 'node:os'
+import path from 'node:path'
+import util, { promisify } from 'node:util'
+import { exec } from 'node:child_process'
+import { Readable } from 'node:stream'
+import type { ZipFile, Options as yauzlOptions } from 'yauzl'
+import yauzl from 'yauzl'
+import { threadId } from 'node:worker_threads'
+
+import { _fetch as fetch } from '../fetchWrapper.js'
+
+import {
+ isNullOrEmpty,
+ nestedKeyValue,
+ createDir,
+ isWritable,
+ setReadWriteAccess,
+ isTrue,
+ getBrowserStackUser,
+ getBrowserStackKey,
+ isFalse,
+ isTurboScale,
+ shouldAddServiceVersion,
+} from '../util.js'
+import PerformanceTester from '../instrumentation/performance/performance-tester.js'
+import { EVENTS as PerformanceEvents } from '../instrumentation/performance/constants.js'
+import { BStackLogger as logger } from './cliLogger.js'
+import { UPDATED_CLI_ENDPOINT, BSTACK_SERVICE_VERSION, BINARY_BUSY_ERROR_CODES } from '../constants.js'
+import type { Options, Capabilities } from '@wdio/types'
+import type {
+ BrowserstackConfig,
+ BrowserstackOptions,
+ TestManagementOptions,
+ TestObservabilityOptions,
+} from '../types.js'
+import { TestFrameworkConstants } from './frameworks/constants/testFrameworkConstants.js'
+import APIUtils from './apiUtils.js'
+
+const CLI_LOCK_TIMEOUT_MS = 5 * 60 * 1000
+const CLI_LOCK_POLL_MS = 1000
+const CLI_DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000
+const CLI_DOWNLOAD_TMP_PREFIX = 'downloaded_file_'
+const CLI_DOWNLOAD_TMP_SUFFIX = '.zip'
+
+export class CLIUtils {
+ static automationFrameworkDetail = {}
+ static testFrameworkDetail = {}
+ static CLISupportedFrameworks = ['mocha']
+
+ static isDevelopmentEnv() {
+ return process.env.BROWSERSTACK_CLI_ENV === 'development'
+ }
+
+ static getCLIParamsForDevEnv(): Record {
+ return {
+ id: process.env.BROWSERSTACK_CLI_ENV || '',
+ listen: `unix:/tmp/sdk-platform-${process.env.BROWSERSTACK_CLI_ENV}.sock`,
+ }
+ }
+
+ /**
+ * Build config object for binary session request
+ * @returns {string}
+ * @throws {Error}
+ */
+ static getBinConfig(
+ config: Options.Testrunner,
+ capabilities:
+ | Capabilities.RequestedStandaloneCapabilities
+ | Capabilities.RequestedStandaloneCapabilities[],
+ options: BrowserstackConfig & BrowserstackOptions,
+ buildTag?: string,
+ ) {
+ const modifiedOpts: Record = { ...options }
+ if (modifiedOpts.opts) {
+ modifiedOpts.browserStackLocalOptions = modifiedOpts.opts
+ delete modifiedOpts.opts
+ }
+ delete modifiedOpts.testManagementOptions
+
+ modifiedOpts.testContextOptions = {
+ skipSessionName: isFalse(modifiedOpts.setSessionName),
+ skipSessionStatus: isFalse(modifiedOpts.setSessionStatus),
+ sessionNameOmitTestTitle: modifiedOpts.sessionNameOmitTestTitle || false,
+ sessionNamePrependTopLevelSuiteTitle:
+ modifiedOpts.sessionNamePrependTopLevelSuiteTitle || false,
+ sessionNameFormat: modifiedOpts.sessionNameFormat || '',
+ }
+
+ const commonBstackOptions = (() => {
+ if (
+ capabilities &&
+ !Array.isArray(capabilities) &&
+ typeof capabilities === 'object' &&
+ 'bstack:options' in (capabilities as Record)
+ ) {
+ // Cast after guard to satisfy TypeScript
+ return (
+ (
+ capabilities as {
+ ['bstack:options']?: Record;
+ }
+ )['bstack:options'] || {}
+ )
+ }
+ return {}
+ })()
+
+ const isNonBstackA11y =
+ isTurboScale(options) ||
+ !shouldAddServiceVersion(
+ config as Options.Testrunner,
+ options.testObservability,
+ )
+ const observabilityOptions: TestObservabilityOptions =
+ options.testObservabilityOptions || {}
+ const testManagementOptions: TestManagementOptions =
+ options.testManagementOptions || {}
+ const testPlanId = typeof testManagementOptions.testPlanId === 'string'
+ ? testManagementOptions.testPlanId.trim()
+ : ''
+ const binconfig: Record = {
+ userName: observabilityOptions.user || config.user,
+ accessKey: observabilityOptions.key || config.key,
+ platforms: [],
+ isNonBstackA11yWDIO: isNonBstackA11y,
+ ...modifiedOpts,
+ ...commonBstackOptions,
+ }
+
+ binconfig.buildName = observabilityOptions.buildName || binconfig.buildName
+ binconfig.projectName = observabilityOptions.projectName || binconfig.projectName
+ binconfig.buildTag = this.getObservabilityBuildTags(observabilityOptions, buildTag) || []
+ if (testPlanId.length > 0) {
+ binconfig.testManagementOptions = {
+ testPlanId,
+ }
+ }
+
+ const caps = Array.isArray(capabilities) ? capabilities : [capabilities]
+ for (const cap of caps) {
+ const platform: Record = {}
+ const capability = cap as Record
+
+ Object.keys(capability)
+ .filter((key) => key !== 'bstack:options')
+ .forEach((key) => {
+ platform[key] = capability[key]
+ })
+
+ if (capability['bstack:options']) {
+ Object.keys(
+ capability['bstack:options'] as Record,
+ ).forEach((key) => {
+ platform[key] = (
+ capability['bstack:options'] as Record<
+ string,
+ unknown
+ >
+ )[key]
+ })
+ }
+ (binconfig.platforms as Array).push(platform)
+ }
+ return JSON.stringify(binconfig)
+ }
+
+ static getSdkVersion() {
+ return BSTACK_SERVICE_VERSION
+ }
+
+ static getSdkLanguage() {
+ return 'ECMAScript'
+ }
+
+ static async setupCliPath(
+ config: Options.Testrunner,
+ ): Promise {
+ logger.debug('Configuring Cli path.')
+ const developmentBinaryPath = process.env.SDK_CLI_BIN_PATH || null
+ if (!isNullOrEmpty(developmentBinaryPath)) {
+ logger.debug(`Development Cli Path: ${developmentBinaryPath}`)
+ return developmentBinaryPath
+ }
+
+ try {
+ const cliDir = this.getCliDir()
+ if (isNullOrEmpty(cliDir)) {
+ throw new Error('No writable directory available for the CLI')
+ }
+ const existingCliPath = this.getExistingCliPath(cliDir)
+ const finalBinaryPath = await this.checkAndUpdateCli(
+ existingCliPath,
+ cliDir,
+ config,
+ )
+ logger.debug(`Resolved binary path: ${finalBinaryPath}`)
+ return finalBinaryPath
+ } catch (err) {
+ logger.debug(
+ `Error in setting up cli path directory, Exception: ${util.format(err)}`,
+ )
+ }
+ return null
+ }
+
+ static async checkAndUpdateCli(
+ existingCliPath: string,
+ cliDir: string,
+ config: Options.Testrunner,
+ ): Promise {
+ // Skip CLI update in worker processes - only launcher should update
+ // Workers are identified by having BROWSERSTACK_TESTHUB_JWT set (build already started)
+ if (process.env.BROWSERSTACK_TESTHUB_JWT) {
+ logger.debug(
+ `Worker process detected, skipping CLI update. Using existing: ${existingCliPath}`,
+ )
+ if (existingCliPath && fs.existsSync(existingCliPath)) {
+ return existingCliPath
+ }
+ logger.warn(
+ 'Worker process has no existing CLI binary, attempting download as fallback.',
+ )
+ }
+
+ PerformanceTester.start(PerformanceEvents.SDK_CLI_CHECK_UPDATE)
+ logger.info(`Current CLI Path Found: ${existingCliPath}`)
+ const queryParams: Record = {
+ sdk_version: CLIUtils.getSdkVersion(),
+ os: platform(),
+ os_arch: arch(),
+ cli_version: '0',
+ sdk_language: this.getSdkLanguage(),
+ }
+ if (!isNullOrEmpty(existingCliPath)) {
+ // If binary is busy (being executed by another process), skip version check
+ // and API call entirely — use existing binary as-is
+ if (this.isBinaryBusy(existingCliPath)) {
+ logger.warn(`Existing binary is currently in use, skipping update: ${existingCliPath}`)
+ PerformanceTester.end(PerformanceEvents.SDK_CLI_CHECK_UPDATE)
+ return existingCliPath
+ }
+ const version = await this.runShellCommand(
+ `${existingCliPath} version`,
+ )
+ if (version.toLowerCase().includes('text file busy')) {
+ logger.warn(`Binary busy during version check, skipping update: ${existingCliPath}`)
+ PerformanceTester.end(PerformanceEvents.SDK_CLI_CHECK_UPDATE)
+ return existingCliPath
+ }
+ queryParams.cli_version = version
+ }
+ const response = await this.requestToUpdateCLI(queryParams, config)
+ if (nestedKeyValue(response, ['updated_cli_version'])) {
+ logger.debug(
+ `Need to update binary, current binary version: ${queryParams.cli_version}`,
+ )
+
+ const browserStackBinaryUrl =
+ process.env.BROWSERSTACK_BINARY_URL || null
+ if (!isNullOrEmpty(browserStackBinaryUrl)) {
+ logger.debug(
+ `Using BROWSERSTACK_BINARY_URL: ${browserStackBinaryUrl}`,
+ )
+ response.url = browserStackBinaryUrl
+ }
+
+ const finalBinaryPath = await this.downloadLatestBinary(
+ nestedKeyValue(response, ['url']),
+ cliDir,
+ )
+ PerformanceTester.end(PerformanceEvents.SDK_CLI_CHECK_UPDATE)
+ return finalBinaryPath
+ }
+ PerformanceTester.end(PerformanceEvents.SDK_CLI_CHECK_UPDATE)
+ return existingCliPath
+ }
+
+ static getCliDir() {
+ const writableDir = this.getWritableDir()
+ try {
+ if (isNullOrEmpty(writableDir)) {
+ throw new Error('No writable directory available for the CLI')
+ }
+ const cliDirPath = path.join(writableDir!, 'cli')
+ if (!fs.existsSync(cliDirPath)) {
+ createDir(cliDirPath)
+ }
+ return cliDirPath
+ } catch (err) {
+ logger.error(
+ `Error in getting writable directory, writableDir=${util.format(err)}`,
+ )
+ return ''
+ }
+ }
+
+ static getWritableDir() {
+ const writableDirOptions = [
+ process.env.BROWSERSTACK_FILES_DIR,
+ path.join(homedir(), '.browserstack'),
+ path.join('tmp', '.browserstack'),
+ ]
+
+ for (const path of writableDirOptions) {
+ if (isNullOrEmpty(path)) {
+ continue
+ }
+ try {
+ if (fs.existsSync(path!)) {
+ logger.debug(`File ${path} already exist`)
+ if (!isWritable(path!)) {
+ logger.debug(`Giving write permission to ${path}`)
+ const success = setReadWriteAccess(path!)
+ if (!isTrue(success)) {
+ logger.warn(
+ `Unable to provide write permission to ${path}`,
+ )
+ }
+ }
+ } else {
+ logger.debug(`File does not exist: ${path}`)
+ createDir(path!)
+ logger.debug(`Giving write permission to ${path}`)
+ const success = setReadWriteAccess(path!)
+ if (!isTrue(success)) {
+ logger.warn(
+ `Unable to provide write permission to ${path}`,
+ )
+ }
+ }
+ return path
+ } catch (err) {
+ logger.error(
+ `Unable to get writable directory, exception ${util.format(err)}`,
+ )
+ }
+ }
+ return null
+ }
+
+ static getExistingCliPath(cliDir: string) {
+ try {
+ // Check if the path exists and is a directory
+ if (!fs.existsSync(cliDir) || !fs.statSync(cliDir).isDirectory()) {
+ return ''
+ }
+
+ // List all files in the directory that start with "binary-"
+ const allBinaries = fs
+ .readdirSync(cliDir)
+ .map((file: string) => path.join(cliDir, file))
+ .filter(
+ (filePath: string) =>
+ fs.statSync(filePath).isFile() &&
+ path.basename(filePath).startsWith('binary-'),
+ )
+
+ if (allBinaries.length > 0) {
+ // Get the latest binary by comparing the last modified time
+ const latestBinary = allBinaries
+ .map((filePath: string) => ({
+ filePath,
+ mtime: fs.statSync(filePath).mtime,
+ }))
+ .reduce(
+ (
+ latest: { filePath: string; mtime: Date } | null,
+ current: { filePath: string; mtime: Date },
+ ) => {
+ if (!latest || !latest.mtime) {
+ return current
+ }
+
+ if (current.mtime > latest.mtime) {
+ return current
+ }
+
+ return latest
+ },
+ null,
+ )
+ return latestBinary ? latestBinary.filePath : ''
+ }
+
+ return '' // No binary present
+ } catch (err) {
+ logger.error(`Error while reading CLI path: ${util.format(err)}`)
+ return ''
+ }
+ }
+
+ static isBinaryBusy(binaryPath: string): boolean {
+ if (isNullOrEmpty(binaryPath)) {return false}
+ if (platform() === 'darwin') {return false}
+ if (!fs.existsSync(binaryPath)) {return false}
+
+ try {
+ const fd = fs.openSync(binaryPath, 'r+')
+ fs.closeSync(fd)
+ return false
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (err: any) {
+ if (BINARY_BUSY_ERROR_CODES.includes(err.code)) {
+ logger.debug(`Binary is busy: ${binaryPath}`)
+ return true
+ }
+ logger.debug(`Error checking if binary is busy: ${err.message}`)
+ return false
+ }
+ }
+
+ static requestToUpdateCLI = async (
+ queryParams: Record,
+ config: Options.Testrunner,
+ ) => {
+ const params = new URLSearchParams(queryParams)
+ const requestInit: RequestInit = {
+ method: 'GET',
+ headers: {
+ Authorization: `Basic ${Buffer.from(`${getBrowserStackUser(config)}:${getBrowserStackKey(config)}`).toString('base64')}`,
+ },
+ }
+ const response = await fetch(
+ `${APIUtils.BROWSERSTACK_AUTOMATE_API_URL}/${UPDATED_CLI_ENDPOINT}?${params.toString()}`,
+ requestInit,
+ )
+ const jsonResponse = await response.json()
+ logger.debug(`response ${JSON.stringify(jsonResponse)}`)
+ return jsonResponse
+ }
+
+ static runShellCommand(
+ cmdCommand: string,
+ workingDir = '',
+ ): Promise {
+ return new Promise((resolve) => {
+ const process = exec(
+ cmdCommand,
+ { cwd: workingDir, timeout: 5000 },
+ (error: Error, stdout: string, stderr: string) => {
+ if (error) {
+ resolve(stderr.trim() || 'SHELL_EXECUTE_ERROR')
+ } else {
+ resolve(stdout.trim())
+ }
+ },
+ )
+
+ // Ensure the process is killed if it exceeds the timeout
+ process.on('error', () => {
+ resolve('SHELL_EXECUTE_ERROR')
+ })
+ })
+ }
+
+ static downloadLatestBinary = async (
+ binDownloadUrl: string,
+ cliDir: string,
+ ): Promise => {
+ const lockPath = path.join(cliDir, 'download.lock')
+
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
+
+ const parseLockFile = () => {
+ try {
+ const content = fs.readFileSync(lockPath, 'utf8').trim()
+ const [pidLine, timestampLine] = content.split('\n')
+ const pid = Number.parseInt(pidLine, 10)
+ const timestamp = Number.parseInt(timestampLine, 10)
+ if (!Number.isFinite(pid) || !Number.isFinite(timestamp)) {
+ return null
+ }
+ return { pid, timestamp }
+ } catch {
+ return null
+ }
+ }
+
+ const isProcessRunning = (pid: number) => {
+ try {
+ process.kill(pid, 0)
+ return true
+ } catch {
+ return false
+ }
+ }
+
+ const acquireLock = async (
+ timeoutMs = CLI_LOCK_TIMEOUT_MS,
+ pollMs = CLI_LOCK_POLL_MS,
+ ): Promise<(() => void) | { alreadyExists: string }> => {
+ const start = Date.now()
+ while (true) {
+ try {
+ const fd = fs.openSync(lockPath, 'wx')
+ try {
+ fs.writeFileSync(fd, `${process.pid}\n${Date.now()}\n`)
+ } catch {
+ // intentionally ignore write errors; the open fd still holds
+ // the exclusive lock and will be closed in cleanup
+ }
+ return () => {
+ try {
+ fs.closeSync(fd)
+ } catch {
+ // ignore cleanup errors
+ }
+ try {
+ fs.unlinkSync(lockPath)
+ } catch {
+ // ignore cleanup errors
+ }
+ }
+ } catch (e: unknown) {
+ const error = e as { code?: string }
+ if (error.code === 'EEXIST') {
+ const lockMeta = parseLockFile()
+ if (lockMeta) {
+ const lockAge = Date.now() - lockMeta.timestamp
+ const running = isProcessRunning(lockMeta.pid)
+ if (!running || lockAge > timeoutMs) {
+ logger.warn(
+ `Stale CLI download lock detected (pid=${lockMeta.pid}, age=${lockAge}ms). Removing lock.`,
+ )
+ try {
+ fs.unlinkSync(lockPath)
+ } catch {
+ // ignore cleanup errors
+ }
+ continue
+ }
+ }
+ // Check if existing binary appeared while waiting
+ const existingBinary =
+ CLIUtils.getExistingCliPath(cliDir)
+ if (
+ existingBinary &&
+ fs.existsSync(existingBinary) &&
+ fs.statSync(existingBinary).size > 0
+ ) {
+ logger.debug(
+ `Binary appeared while waiting for lock: ${existingBinary}`,
+ )
+ return { alreadyExists: existingBinary }
+ }
+ if (Date.now() - start > timeoutMs) {
+ throw new Error(
+ `Timeout waiting for lock: ${lockPath}`,
+ )
+ }
+ await sleep(pollMs)
+ continue
+ }
+ throw e
+ }
+ }
+ }
+
+ const cleanupTemporaryDownloads = (maxAgeMs = CLI_LOCK_TIMEOUT_MS) => {
+ try {
+ const now = Date.now()
+ // Match both download zips (downloaded_file_*.zip) and orphan extract
+ // temp files (.tmp.) left by crashed peer workers.
+ const tmpExtractRe = /\.tmp\.\d+$/
+ for (const entry of fs.readdirSync(cliDir)) {
+ const isDownloadZip =
+ entry.startsWith(CLI_DOWNLOAD_TMP_PREFIX) &&
+ entry.endsWith(CLI_DOWNLOAD_TMP_SUFFIX)
+ const isExtractTmp = tmpExtractRe.test(entry)
+ if (!isDownloadZip && !isExtractTmp) {
+ continue
+ }
+ const filePath = path.join(cliDir, entry)
+ let stats: fs.Stats
+ try {
+ stats = fs.statSync(filePath)
+ } catch {
+ continue
+ }
+ if (now - stats.mtimeMs < maxAgeMs) {
+ continue
+ }
+ try {
+ fs.unlinkSync(filePath)
+ } catch (err) {
+ logger.debug(
+ `Failed to delete temp CLI file ${filePath}: ${util.format(err)}`,
+ )
+ }
+ }
+ } catch (err) {
+ logger.debug(
+ `Failed to scan temp CLI files in ${cliDir}: ${util.format(err)}`,
+ )
+ }
+ }
+
+ PerformanceTester.start(PerformanceEvents.SDK_CLI_DOWNLOAD)
+ logger.debug(`Downloading SDK binary from: ${binDownloadUrl}`)
+
+ let downloadEnded = false
+ const endDownload = (success = true, errMsg?: string) => {
+ if (downloadEnded) {
+ return
+ }
+ downloadEnded = true
+ if (success) {
+ PerformanceTester.end(PerformanceEvents.SDK_CLI_DOWNLOAD)
+ return
+ }
+ PerformanceTester.end(
+ PerformanceEvents.SDK_CLI_DOWNLOAD,
+ false,
+ errMsg,
+ )
+ }
+
+ let releaseLock: (() => void) | undefined
+ try {
+ const lockResult = await acquireLock()
+
+ // Check if binary already exists (another process downloaded it)
+ if (typeof lockResult !== 'function') {
+ endDownload()
+ return lockResult.alreadyExists
+ }
+
+ releaseLock = lockResult
+
+ // Re-check after acquiring lock
+ const existingBinary = CLIUtils.getExistingCliPath(cliDir)
+ if (
+ existingBinary &&
+ fs.existsSync(existingBinary) &&
+ fs.statSync(existingBinary).size > 0
+ ) {
+ logger.debug(
+ `Binary already exists after acquiring lock: ${existingBinary}`,
+ )
+ endDownload()
+ releaseLock()
+ return existingBinary
+ }
+
+ cleanupTemporaryDownloads()
+
+ const zipFilePath = path.join(
+ cliDir,
+ `${CLI_DOWNLOAD_TMP_PREFIX}${process.pid}_${Date.now()}${CLI_DOWNLOAD_TMP_SUFFIX}`,
+ )
+ const downloadedFileStream = fs.createWriteStream(zipFilePath)
+
+ return new Promise((resolve, reject) => {
+ const processDownload = async () => {
+ const abortController = new AbortController()
+ const timeout = setTimeout(
+ () => abortController.abort(),
+ CLI_DOWNLOAD_TIMEOUT_MS,
+ )
+ let response: Response
+ try {
+ response = await fetch(binDownloadUrl, {
+ signal: abortController.signal,
+ })
+ } finally {
+ clearTimeout(timeout)
+ }
+ if (!response.body) {
+ throw new Error('No response body received')
+ }
+
+ downloadedFileStream.on('error', function (err: Error) {
+ logger.error(
+ `Got Error while downloading cli binary file: ${err}`,
+ )
+ endDownload(false, util.format(err))
+ releaseLock?.()
+ reject(err)
+ })
+
+ try {
+ const arrayBuffer = await response.arrayBuffer()
+ const nodeStream = Readable.from([
+ new Uint8Array(arrayBuffer),
+ ])
+
+ nodeStream.pipe(downloadedFileStream)
+
+ // Set up the downloadFileStream handler before pipeline
+ CLIUtils.downloadFileStream(
+ downloadedFileStream,
+ zipFilePath,
+ cliDir,
+ (result: string) => {
+ endDownload()
+ releaseLock?.()
+ resolve(result)
+ },
+ (err?: Error) => {
+ endDownload(false, util.format(err))
+ releaseLock?.()
+ reject(err)
+ },
+ )
+ } catch (err) {
+ logger.error(
+ `Got Error in cli binary downloading request ${util.format(err)}`,
+ )
+ endDownload(false, util.format(err))
+ releaseLock?.()
+ reject(err as Error)
+ }
+ }
+
+ processDownload()
+ })
+ } catch (err) {
+ releaseLock?.()
+ endDownload(false, util.format(err))
+ logger.debug(
+ `Failed to download binary, Exception: ${util.format(err)}`,
+ )
+ return null
+ }
+ }
+
+ static downloadFileStream(
+ downloadedFileStream: fs.WriteStream,
+ zipFilePath: string,
+ cliDir: string,
+ resolve: (path: string) => void,
+ reject: (reason?: Error) => void,
+ ) {
+ downloadedFileStream.on('close', async function () {
+ const yauzlOpenPromise = promisify(yauzl.open) as (
+ path: string,
+ options: yauzlOptions,
+ ) => Promise
+ try {
+ const zipfile = await yauzlOpenPromise(zipFilePath, {
+ lazyEntries: true,
+ })
+ let resolvedBinaryPath: string | null = null
+
+ zipfile.readEntry()
+ zipfile.on('entry', async (entry) => {
+ if (/\/$/.test(entry.fileName)) {
+ zipfile.readEntry()
+ return
+ }
+
+ // Zip-slip guard: reject entries whose resolved path escapes cliDir
+ // (BROWSERSTACK_BINARY_URL lets users supply arbitrary zips).
+ const candidatePath = path.join(cliDir, entry.fileName)
+ const resolvedCandidate = path.resolve(candidatePath)
+ const resolvedDir = path.resolve(cliDir) + path.sep
+ if (!resolvedCandidate.startsWith(resolvedDir)) {
+ zipfile.close()
+ reject(new Error(`Zip-slip detected: entry "${entry.fileName}" resolves outside ${cliDir}`))
+ return
+ }
+
+ const isBinaryEntry = path.basename(entry.fileName).startsWith('binary-')
+
+ if (!isBinaryEntry) {
+ const directStream = fs.createWriteStream(candidatePath)
+ directStream.on('error', (writeErr) => {
+ zipfile.close()
+ reject(writeErr as Error)
+ })
+ const openReadStreamPromise = promisify(
+ zipfile.openReadStream,
+ ).bind(zipfile)
+ try {
+ const readStream = await openReadStreamPromise(entry)
+ readStream.on('end', function () {
+ directStream.end()
+ directStream.on('close', () => zipfile.readEntry())
+ })
+ readStream.pipe(directStream)
+ } catch (zipErr) {
+ zipfile.close()
+ reject(zipErr as Error)
+ }
+ return
+ }
+
+ // Binary entry: extract to PID-scoped temp file, chmod, atomic rename inline.
+ // Prevents ETXTBSY/EBUSY: the file being executed is never the file being written.
+ const finalPath = candidatePath
+ const tempPath = path.join(cliDir, `${entry.fileName}.tmp.${process.pid}`)
+
+ const writeStream = fs.createWriteStream(tempPath)
+
+ let writeStreamErrored = false
+ writeStream.on('error', (writeErr) => {
+ writeStreamErrored = true
+ fsp.unlink(tempPath).catch(() => {})
+ zipfile.close()
+ reject(writeErr as Error)
+ })
+
+ // 'close' fires after the fd is closed; safe for fsp.rename on Windows (where 'finish' may fire before fd release).
+ // autoClose=true also makes 'close' fire after 'error' — bail out if the error path already rejected.
+ writeStream.on('close', async () => {
+ if (writeStreamErrored) { return }
+ try {
+ await fsp.chmod(tempPath, '0755')
+ try {
+ await fsp.rename(tempPath, finalPath)
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (renameErr: any) {
+ // Narrow fallback to cross-device (EXDEV) only
+ if (renameErr.code !== 'EXDEV') {
+ throw renameErr
+ }
+ logger.warn(`Atomic rename failed (cross-device), falling back to copy: ${renameErr.message}`)
+ await fsp.copyFile(tempPath, finalPath)
+ await fsp.unlink(tempPath).catch(() => {})
+ }
+ if (!resolvedBinaryPath) {
+ resolvedBinaryPath = finalPath
+ }
+ zipfile.readEntry()
+ } catch (err) {
+ await fsp.unlink(tempPath).catch(() => {})
+ zipfile.close()
+ reject(err as Error)
+ }
+ })
+
+ const openReadStreamPromise = promisify(
+ zipfile.openReadStream,
+ ).bind(zipfile)
+ try {
+ const readStream = await openReadStreamPromise(entry)
+ readStream.on('end', function () {
+ writeStream.end()
+ })
+ readStream.pipe(writeStream)
+ } catch (zipErr) {
+ fsp.unlink(tempPath).catch(() => {})
+ zipfile.close()
+ reject(zipErr as Error)
+ }
+ })
+
+ zipfile.on('error', (zipErr) => {
+ reject(zipErr as Error)
+ })
+
+ zipfile.once('end', () => {
+ fsp.unlink(zipFilePath).catch(() => {
+ logger.warn(`Failed to delete zip file: ${zipFilePath}`)
+ })
+
+ if (!resolvedBinaryPath) {
+ zipfile.close()
+ reject(new Error('No binary-* entry found in zip; cannot complete CLI binary extraction'))
+ return
+ }
+ zipfile.close()
+ resolve(resolvedBinaryPath)
+ })
+ } catch (err) {
+ reject(err as Error)
+ }
+ })
+ }
+
+ static getTestFrameworkDetail() {
+ if (process.env.BROWSERSTACK_TEST_FRAMEWORK_DETAIL) {
+ return JSON.parse(process.env.BROWSERSTACK_TEST_FRAMEWORK_DETAIL)
+ }
+ return this.testFrameworkDetail
+ }
+
+ static getAutomationFrameworkDetail() {
+ if (process.env.BROWSERSTACK_AUTOMATION_FRAMEWORK_DETAIL) {
+ return JSON.parse(
+ process.env.BROWSERSTACK_AUTOMATION_FRAMEWORK_DETAIL,
+ )
+ }
+ return this.automationFrameworkDetail
+ }
+
+ static setFrameworkDetail(
+ testFramework: string,
+ automationFramework: string,
+ ) {
+ if (!testFramework || !automationFramework) {
+ logger.debug(
+ `Test or Automation framework not provided testFramework=${testFramework}, automationFramework=${automationFramework}`,
+ )
+ }
+
+ this.testFrameworkDetail = {
+ name: testFramework,
+ version: { [testFramework]: CLIUtils.getSdkVersion() },
+ }
+
+ this.automationFrameworkDetail = {
+ name: automationFramework,
+ version: { [automationFramework]: CLIUtils.getSdkVersion() },
+ }
+
+ process.env.BROWSERSTACK_AUTOMATION_FRAMEWORK_DETAIL = JSON.stringify(
+ this.automationFrameworkDetail,
+ )
+ process.env.BROWSERSTACK_TEST_FRAMEWORK_DETAIL = JSON.stringify(
+ this.testFrameworkDetail,
+ )
+ }
+
+ /**
+ * Get the current instance name using thread id and processId
+ * @returns {string}
+ */
+ static getCurrentInstanceName() {
+ return `${process.pid}:${threadId}`
+ }
+
+ /**
+ * Generate a unique client worker identifier combining thread ID and process ID.
+ * This identifier is used to track worker-specific events and performance metrics
+ * across distributed test execution. Format matches the Python SDK implementation
+ * for consistency across SDKs.
+ *
+ * Format: "threadId-processId"
+ *
+ * @param context - Optional execution context with threadId and processId
+ * @returns Worker ID string in format "threadId-processId"
+ * @example
+ * const workerId = CLIUtils.getClientWorkerId() // Returns "1-12345"
+ * const workerId = CLIUtils.getClientWorkerId({ threadId: 123, processId: 456 }) // Returns "123-456"
+ */
+ static getClientWorkerId(context?: { threadId?: string | number; processId?: string | number }): string {
+ const workerThreadId = context?.threadId?.toString() || threadId.toString()
+ const workerProcessId = context?.processId?.toString() || process.pid.toString()
+ return `${workerThreadId}-${workerProcessId}`
+ }
+
+ /**
+ *
+ * @param {TestFrameworkState | AutomationFrameworkState} frameworkState
+ * @param {HookState} hookState
+ * @returns {string}
+ */
+ static getHookRegistryKey(frameworkState: State, hookState: State) {
+ return `${frameworkState}:${hookState}`
+ }
+
+ static matchHookRegex(hookState: string) {
+ const pattern = new RegExp(TestFrameworkConstants.HOOK_REGEX)
+
+ return pattern.test(hookState)
+ }
+
+ static getObservabilityBuildTags(
+ observabilityOptions: TestObservabilityOptions,
+ bstackBuildTag?: string,
+ ) {
+ if (process.env.TEST_OBSERVABILITY_BUILD_TAG) {
+ return process.env.TEST_OBSERVABILITY_BUILD_TAG.split(',')
+ }
+ if (observabilityOptions.buildTag) {
+ return observabilityOptions.buildTag
+ }
+ if (bstackBuildTag) {
+ return [bstackBuildTag]
+ }
+ return []
+ }
+
+ static checkCLISupportedFrameworks(framework: string | undefined) {
+ if (framework === undefined) {
+ return false
+ }
+ return this.CLISupportedFrameworks.includes(framework)
+ }
+}
diff --git a/packages/browserstack-service/src/cli/eventDispatcher.ts b/packages/browserstack-service/src/cli/eventDispatcher.ts
new file mode 100644
index 0000000..6fb2def
--- /dev/null
+++ b/packages/browserstack-service/src/cli/eventDispatcher.ts
@@ -0,0 +1,56 @@
+/**
+ * EventDispatcher - Singleton class for event handling
+ */
+class EventDispatcher {
+
+ static #instance: EventDispatcher|null = null
+ observers: Record
+
+ constructor() {
+ this.observers = {}
+ }
+
+ /**
+ * Get the EventDispatcher singleton instance
+ * @returns {EventDispatcher} The singleton instance
+ */
+ static getInstance() {
+ if (!EventDispatcher.#instance) {
+ EventDispatcher.#instance = new EventDispatcher()
+ }
+ return EventDispatcher.#instance
+ }
+
+ /**
+ * Add event observer
+ * @param {string} event - Event name
+ * @param {Function} callback - Callback function
+ */
+ registerObserver(hookRegistryKey: string, callback: Function) {
+ if (!this.observers[hookRegistryKey]) {
+ this.observers[hookRegistryKey] = []
+ }
+
+ this.observers[hookRegistryKey].push(callback)
+ }
+
+ /**
+ * Notify registered observers on an event
+ * @param {string} event - Event name
+ * @param {*} data - Event data
+ */
+ async notifyObserver(event: string, args: unknown) {
+ if (this.observers[event]) {
+ for (const callback of this.observers[event]) {
+ await callback(args)
+ }
+ return
+ }
+ }
+}
+
+// Create the singleton instance
+export const eventDispatcher = EventDispatcher.getInstance()
+
+// Object.freeze to prevent modification of the instance
+Object.freeze(eventDispatcher)
diff --git a/packages/browserstack-service/src/cli/frameworks/automationFramework.ts b/packages/browserstack-service/src/cli/frameworks/automationFramework.ts
new file mode 100644
index 0000000..319853b
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/automationFramework.ts
@@ -0,0 +1,148 @@
+import { BStackLogger as logger } from '../cliLogger.js'
+import { eventDispatcher } from '../eventDispatcher.js'
+import { CLIUtils } from '../cliUtils.js'
+import TrackedInstance from '../instances/trackedInstance.js'
+import type AutomationFrameworkInstance from '../instances/automationFrameworkInstance.js'
+import type TrackedContext from '../instances/trackedContext.js'
+import { AutomationFrameworkConstants } from './constants/automationFrameworkConstants.js'
+
+/**
+ * AutomationFramework - Automation Framework abstract class
+ */
+export default class AutomationFramework {
+ #automationFrameworkName: string
+ #automationFrameworkVersion: string
+
+ static instances = new Map()
+ static KEY_AUTOMATION_SESSIONS = 'automation_sessions'
+ static KEY_NON_BROWSERSTACK_AUTOMATION_SESSIONS = 'non_browserstack_automation_sessions'
+
+ /**
+ * Constructor for the AutomationFramework
+ * @param {string} automationFrameworkName - Name of the automation framework
+ * @param {string} automationFrameworkVersion - Version of the automation framework
+ */
+ constructor(automationFrameworkName: string, automationFrameworkVersion: string) {
+ this.#automationFrameworkName = automationFrameworkName
+ this.#automationFrameworkVersion = automationFrameworkVersion
+ }
+
+ /**
+ * Get the automation framework name
+ * @returns {string} The name of the automation framework
+ */
+ getAutomationFrameworkName() {
+ return this.#automationFrameworkName
+ }
+
+ /**
+ * Get the automation framework version
+ * @returns {string} The version of the automation framework
+ */
+ getAutomationFrameworkVersion() {
+ return this.#automationFrameworkVersion
+ }
+
+ /**
+ * Track an event
+ * @param {Object}
+ * @param {Object}
+ * @param {Object}
+ * @returns {void}
+ */
+ async trackEvent(automationFrameworkState: State, hookState: State, args: unknown = {}) {
+ logger.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState} args=${args}`)
+ }
+
+ /**
+ *
+ * @param {*} instance
+ * @param {*} automationFrameworkState
+ * @param {*} hookState
+ * @param {*} args
+ */
+ async runHooks(instance: AutomationFrameworkInstance, automationFrameworkState: State, hookState: State, args: unknown = {}) {
+ logger.info(`runHooks: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`)
+
+ const hookRegistryKey = CLIUtils.getHookRegistryKey(automationFrameworkState, hookState)
+ await eventDispatcher.notifyObserver(hookRegistryKey, args)
+ }
+
+ /**
+ * Register an observer
+ * @returns {void}
+ */
+ static registerObserver(automationFrameworkState: State, hookState: State, callback: Function) {
+ eventDispatcher.registerObserver(CLIUtils.getHookRegistryKey(automationFrameworkState, hookState), callback)
+ }
+
+ /**
+ * Set the tracked instance
+ * @param {TrackedInstance} context - The context
+ * @param {TrackedInstance} instance - The instance
+ * @returns {void}
+ */
+ static setTrackedInstance(context: TrackedContext, instance: AutomationFrameworkInstance) {
+ logger.debug(`setTrackedInstance: ${context.getId()}`)
+ AutomationFramework.instances.set(context.getId(), instance)
+ }
+
+ /**
+ * Get the tracked instance
+ * @returns {TrackedInstance} The tracked instance
+ */
+ static getTrackedInstance() {
+ logger.debug(`getTrackedInstance: ${CLIUtils.getCurrentInstanceName()}`)
+ const context = TrackedInstance.createContext(CLIUtils.getCurrentInstanceName())
+ return AutomationFramework.instances.get(context.getId())
+ }
+
+ /**
+ * Set the state
+ * @param {TrackedInstance} instance - The instance
+ * @param {string} key - The key
+ * @param {*} value - The value
+ * @returns
+ */
+ static setState(instance: AutomationFrameworkInstance, key: string, value: unknown) {
+ instance.getAllData().set(key, value)
+ }
+
+ /**
+ * Get the state
+ * @param {TrackedInstance} instance - The instance
+ * @param {string} key - The key
+ * @returns {*} The state
+ */
+ static getState(instance: AutomationFrameworkInstance, key: string) {
+ return instance.getAllData().get(key)
+ }
+
+ static isAutomationSession(instance: AutomationFrameworkInstance): boolean {
+ return AutomationFramework.getState(instance, AutomationFrameworkConstants.KEY_IS_BROWSERSTACK_HUB)
+ }
+
+ /**
+ * Set the driver for the automation framework instance
+ * @param {AutomationFrameworkInstance} instance - The automation framework instance
+ * @param {*} driver - The driver object
+ */
+ static setDriver(instance: AutomationFrameworkInstance, driver: unknown): void {
+ if (this.isAutomationSession(instance)) {
+ AutomationFramework.setState(instance, AutomationFramework.KEY_AUTOMATION_SESSIONS, driver)
+ } else {
+ AutomationFramework.setState(instance, AutomationFramework.KEY_NON_BROWSERSTACK_AUTOMATION_SESSIONS, driver)
+ }
+ }
+
+ /**
+ * Get the driver from the automation framework instance
+ * @param {AutomationFrameworkInstance} instance - The automation framework instance
+ * @returns {*} The driver object or null
+ */
+ static getDriver(instance: AutomationFrameworkInstance): unknown {
+ let driver: unknown = null
+ driver = this.isAutomationSession(instance) ? AutomationFramework.getState(instance, AutomationFramework.KEY_AUTOMATION_SESSIONS) || null : AutomationFramework.getState(instance, AutomationFramework.KEY_NON_BROWSERSTACK_AUTOMATION_SESSIONS) || null
+ return driver
+ }
+}
diff --git a/packages/browserstack-service/src/cli/frameworks/constants/automationFrameworkConstants.ts b/packages/browserstack-service/src/cli/frameworks/constants/automationFrameworkConstants.ts
new file mode 100644
index 0000000..b0e65e0
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/constants/automationFrameworkConstants.ts
@@ -0,0 +1,17 @@
+export const AutomationFrameworkConstants = {
+ ENV_BROWSERSTACK_PLATFORM_INDEX: 'BROWSERSTACK_PLATFORM_INDEX',
+ KEY_HUB_URL: 'hub_url',
+ KEY_FRAMEWORK_SESSION_ID: 'framework_session_id',
+ KEY_INPUT_CAPABILITIES: 'input_capabilities',
+ KEY_CAPABILITIES: 'capabilities',
+ KEY_IS_BROWSERSTACK_HUB: 'is_browserstack_hub',
+ KEY_STARTED_AT: 'started_at',
+ KEY_ENDED_AT: 'ended_at',
+ KEY_PLATFORM_INDEX: 'platform_index',
+ COMMAND_NEW_SESSION: 'newsession',
+ COMMAND_GET: 'get',
+ COMMAND_SCREENSHOT: 'screenshot',
+ COMMAND_W3C_EXECUTE_SCRIPT: 'w3cexecutescript',
+ COMMAND_W3C_EXECUTE_SCRIPT_ASYNC: 'w3cexecutescriptasync',
+ COMMAND_QUIT: 'quit'
+}
diff --git a/packages/browserstack-service/src/cli/frameworks/constants/testFrameworkConstants.ts b/packages/browserstack-service/src/cli/frameworks/constants/testFrameworkConstants.ts
new file mode 100644
index 0000000..e321352
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/constants/testFrameworkConstants.ts
@@ -0,0 +1,42 @@
+export const TestFrameworkConstants = {
+ KEY_TEST_UUID: 'test_uuid',
+ KEY_TEST_ID : 'test_id',
+ KEY_TEST_NAME : 'test_name',
+ KEY_TEST_FILE_PATH : 'test_file_path',
+ KEY_TEST_TAGS : 'test_tags',
+ KEY_TEST_RESULT : 'test_result',
+ KEY_TEST_RESULT_AT : 'test_result_at',
+ KEY_TEST_STARTED_AT : 'test_started_at',
+ KEY_TEST_ENDED_AT : 'test_ended_at',
+ KEY_TEST_LOCATION : 'test_location',
+ KEY_TEST_SCOPE : 'test_scope',
+ KEY_TEST_SCOPES : 'test_scopes',
+ KEY_TEST_FRAMEWORK_NAME : 'test_framework_name',
+ KEY_TEST_FRAMEWORK_VERSION : 'test_framework_version',
+ KEY_TEST_CODE : 'test_code',
+ KEY_TEST_RERUN_NAME : 'test_rerun_name',
+ KEY_PLATFORM_INDEX : 'platform_index',
+ KEY_TEST_FAILURE : 'test_failure',
+ KEY_TEST_FAILURE_TYPE : 'test_failure_type',
+ KEY_TEST_FAILURE_REASON : 'test_failure_reason',
+ KEY_TEST_LOGS : 'test_logs',
+ KEY_TEST_META : 'test_meta',
+ KEY_TEST_DEFERRED : 'test_deferred',
+ KEY_SESSION_NAME : 'test_session_name',
+ KEY_AUTOMATE_SESSION_NAME : 'automate_session_name',
+ KEY_AUTOMATE_SESSION_STATUS: 'automate_session_status',
+ KEY_AUTOMATE_SESSION_REASON: 'automate_session_reason',
+ KEY_EVENT_STARTED_AT : 'event_started_at',
+ KEY_EVENT_ENDED_AT : 'event_ended_at',
+ KEY_HOOK_ID : 'hook_id',
+ KEY_HOOK_RESULT : 'hook_result',
+ KEY_HOOK_LOGS : 'hook_logs',
+ KEY_HOOK_NAME : 'hook_name',
+ KEY_HOOKS_STARTED: 'test_hooks_started',
+ KEY_HOOKS_FINISHED: 'test_hooks_finished',
+ DEFAULT_TEST_RESULT : 'pending',
+ DEFAULT_HOOK_RESULT : 'pending',
+ KIND_SCREENSHOT : 'TEST_SCREENSHOT',
+ KIND_LOG : 'TEST_LOG',
+ HOOK_REGEX : '^(BEFORE_|AFTER_)',
+}
diff --git a/packages/browserstack-service/src/cli/frameworks/testFramework.ts b/packages/browserstack-service/src/cli/frameworks/testFramework.ts
new file mode 100644
index 0000000..f291505
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/testFramework.ts
@@ -0,0 +1,144 @@
+import { CLIUtils } from '../cliUtils.js'
+import { eventDispatcher } from '../eventDispatcher.js'
+import { BStackLogger as logger } from '../cliLogger.js'
+import type TrackedContext from '../instances/trackedContext.js'
+import TrackedInstance from '../instances/trackedInstance.js'
+import type TestFrameworkInstance from '../instances/testFrameworkInstance.js'
+
+export default class TestFramework {
+ static instances = new Map()
+ testFrameworks: Array = []
+ testFrameworkVersions: Record = {}
+ binSessionId: string|null = null
+
+ /**
+ * Constructor for the TestFramework
+ * @param {Array} testFrameworks - List of Test frameworks
+ * @param {Map} testFrameworkVersions - Name of the Test frameworks
+ * @param {string} binSessionId - BinSessionId
+ */
+ constructor(testFrameworks: Array, testFrameworkVersions: Record, binSessionId: string) {
+ this.testFrameworks = testFrameworks
+ this.testFrameworkVersions = testFrameworkVersions
+ this.binSessionId = binSessionId
+ }
+
+ /**
+ * get all instances
+ * @return {Map} - return all instances Map
+ */
+ getInstances() {
+ return TestFramework.instances
+ }
+
+ /**
+ * set testFrameworkInstance
+ * @param {TrackedContext} context
+ * @param {TestFrameworkInstance} instance
+ */
+ setInstance(context: TrackedContext, instance: TestFrameworkInstance) {
+ TestFramework.instances.set(context.getId, instance)
+ }
+
+ /**
+ * Find instance and track any state for the test framework
+ * @returns instance
+ */
+ static getTrackedInstance() {
+ const ctx = TrackedInstance.createContext(CLIUtils.getCurrentInstanceName())
+ return TestFramework.instances.get(ctx.getId())
+ }
+
+ /**
+ * Set tracked instance
+ * @returns {string} The name of the test framework
+ */
+ static setTrackedInstance(context: TrackedContext, instance: TestFrameworkInstance) {
+ TestFramework.instances.set(context.getId(), instance)
+ }
+
+ /**
+ * get all test framework versions
+ * @returns {Map} - return all versions of framework available.
+ */
+ getTestFrameworksVersions() {
+ return this.testFrameworkVersions
+ }
+
+ /**
+ * get all test frameworks
+ * @returns {Array} - return all test frameworks
+ */
+ getTestFrameworks() {
+ return this.testFrameworks
+ }
+
+ /**
+ * Track an event
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {HookState} hookState
+ * @param {*} args
+ * @returns {void}
+ */
+ trackEvent(testFrameworkState: State, hookState: State, args: unknown = {}) {
+ logger.info(`trackEvent: testFrameworkState=${testFrameworkState}; hookState=${hookState}; args=${args}`)
+ }
+
+ /**
+ * run test hooks
+ * @param {TestFrameworkInstance} instance
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {HookState} hookState
+ * @param {*} args
+ */
+ async runHooks(instance: TestFrameworkInstance, testFrameworkState: State, hookState: State, args: unknown = {}) {
+ logger.info(`runHooks: instance=${instance} automationFrameworkState=${testFrameworkState} hookState=${hookState}`)
+
+ const hookRegistryKey = CLIUtils.getHookRegistryKey(testFrameworkState, hookState)
+ await eventDispatcher.notifyObserver(hookRegistryKey, args)
+ }
+
+ /**
+ * Register an observer
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {HookState} hookState
+ * @param {*} callback
+ * @returns {void}
+ */
+ static registerObserver(testFrameworkState: State, hookState: State, callback: Function) {
+ eventDispatcher.registerObserver(CLIUtils.getHookRegistryKey(testFrameworkState, hookState), callback)
+ }
+
+ /**
+ * Resolve instance for the test framework
+ * @param {TestFrameworkInstance} testFrameworkInstance
+ * @param {string} key
+ * @returns {TestFrameworkInstance}
+ */
+ static getState(instance: TestFrameworkInstance, key: string) {
+ return instance.getAllData().get(key)
+ }
+
+ static hasState(instance: TestFrameworkInstance, key: string) {
+ return instance.hasData(key)
+ }
+
+ /**
+ * Set the state
+ * @param {TrackedInstance} instance - The instance
+ * @param {string} key - The key
+ * @param {*} value - The value
+ * @returns
+ */
+ static setState(instance: TrackedInstance, key: string, value: unknown) {
+ instance.getAllData().set(key, value)
+ }
+
+ updateInstanceState(instance: TestFrameworkInstance, testFrameworkState: State, hookState: State) {
+ instance.setLastTestState(instance.getCurrentTestState())
+ instance.setLastHookState(instance.getCurrentHookState())
+ instance.setCurrentTestState(testFrameworkState)
+ instance.setCurrentHookState(hookState)
+ }
+
+}
diff --git a/packages/browserstack-service/src/cli/frameworks/wdioAutomationFramework.ts b/packages/browserstack-service/src/cli/frameworks/wdioAutomationFramework.ts
new file mode 100644
index 0000000..7901f5f
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/wdioAutomationFramework.ts
@@ -0,0 +1,82 @@
+import AutomationFramework from './automationFramework.js'
+import { AutomationFrameworkState } from '../states/automationFrameworkState.js'
+import { CLIUtils } from '../cliUtils.js'
+import TrackedInstance from '../instances/trackedInstance.js'
+import AutomationFrameworkInstance from '../instances/automationFrameworkInstance.js'
+import { BStackLogger as logger } from '../cliLogger.js'
+
+/**
+ * WebdriverIO Framework class
+ */
+export default class WdioAutomationFramework extends AutomationFramework {
+
+ constructor(automationFrameworkName: string, automationFrameworkVersion: string) {
+ super(automationFrameworkName, automationFrameworkVersion)
+ }
+
+ /**
+ * Find instance and track any state for the automation framework
+ * @param {*} automationFrameworkState
+ * @param {*} hookState
+ * @param {*} args
+ */
+ async trackEvent(automationFrameworkState: State, hookState: State, args: Record = {}) {
+ logger.info(`trackEvent: automationFrameworkState=${automationFrameworkState} hookState=${hookState}`)
+ await super.trackEvent(automationFrameworkState, hookState, args)
+
+ const instance = this.resolveInstance(automationFrameworkState, hookState, args)
+ if (instance === null) {
+ logger.error(`trackEvent: instance not found for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`)
+ return
+ }
+ args.instance = instance
+ await this.runHooks(instance, automationFrameworkState, hookState, args)
+ }
+
+ /**
+ * Resolve instance for the automation framework
+ * @param {*} automationFrameworkState
+ * @param {*} hookState
+ * @param {*} args
+ * @returns instance
+ */
+ resolveInstance(automationFrameworkState: State, hookState: State, args: Record = {}) {
+ let instance = null
+ logger.info(`resolveInstance: resolving instance for automationFrameworkState=${automationFrameworkState} hookState=${hookState}`)
+ if (automationFrameworkState === AutomationFrameworkState.CREATE || automationFrameworkState === AutomationFrameworkState.NONE) {
+ this.trackWebdriverIOInstance(automationFrameworkState, args)
+ }
+
+ instance = AutomationFramework.getTrackedInstance()
+ return instance
+ }
+
+ /**
+ * Create instance for WebdriverIO
+ * @returns {void}
+ */
+ trackWebdriverIOInstance(automationFrameworkState: State, args: Record = {}) {
+ if (
+ // !args.browser &&
+ AutomationFramework.getTrackedInstance()
+ ) {
+ logger.info('trackWebdriverIOInstance: instance already exists')
+ return
+ }
+
+ const target = CLIUtils.getCurrentInstanceName()
+ const trackedContext = TrackedInstance.createContext(target)
+ let instance = null
+ logger.info(`trackWebdriverIOInstance: created instance for target=${target}, state=${automationFrameworkState}, args=${args}`)
+
+ instance = new AutomationFrameworkInstance(
+ trackedContext,
+ this.getAutomationFrameworkName(),
+ this.getAutomationFrameworkVersion(),
+ automationFrameworkState
+ )
+
+ AutomationFramework.setTrackedInstance(trackedContext, instance)
+ logger.info(`trackWebdriverIOInstance: saved instance contextId=${trackedContext.getId()} target=${target}`)
+ }
+}
diff --git a/packages/browserstack-service/src/cli/frameworks/wdioMochaTestFramework.ts b/packages/browserstack-service/src/cli/frameworks/wdioMochaTestFramework.ts
new file mode 100644
index 0000000..70de2a4
--- /dev/null
+++ b/packages/browserstack-service/src/cli/frameworks/wdioMochaTestFramework.ts
@@ -0,0 +1,376 @@
+import { v4 as uuidv4 } from 'uuid'
+import path from 'node:path'
+
+import TestFramework from './testFramework.js'
+import { TestFrameworkState } from '../states/testFrameworkState.js'
+import { HookState } from '../states/hookState.js'
+import TestFrameworkInstance from '../instances/testFrameworkInstance.js'
+import { CLIUtils } from '../cliUtils.js'
+import TrackedInstance from '../instances/trackedInstance.js'
+import { TestFrameworkConstants } from './constants/testFrameworkConstants.js'
+import { BStackLogger as logger } from '../cliLogger.js'
+import type { Frameworks } from '@wdio/types'
+import { getGitMetaData, getMochaTestHierarchy, getUniqueIdentifier, isUndefined, removeAnsiColors } from '../../util.js'
+import { TEST_ANALYTICS_ID } from '../../constants.js'
+
+export default class WdioMochaTestFramework extends TestFramework {
+ static KEY_HOOK_LAST_STARTED = 'test_hook_last_started'
+ static KEY_HOOK_LAST_FINISHED = 'test_hook_last_finished'
+
+ /**
+ * Constructor for the TestFramework
+ * @param {Array} testFrameworks - List of Test frameworks
+ * @param {Map} testFrameworkVersions - Name of the Test frameworks
+ * @param {string} binSessionId - BinSessionId
+ */
+ constructor(testFrameworks: string[], testFrameworkVersions: Record, binSessionId: string) {
+ super(testFrameworks, testFrameworkVersions, binSessionId)
+ }
+
+ /**
+ * Find instance and track any state for the test framework
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {HookState} hookState
+ * @param {*} args
+ */
+ async trackEvent(testFrameworkState: State, hookState: State, args: Record = {}) {
+ logger.info(`trackEvent: testFrameworkState=${testFrameworkState} hookState=${hookState}`)
+ await super.trackEvent(testFrameworkState, hookState, args)
+
+ const instance = this.resolveInstance(testFrameworkState, hookState, args)
+ if (instance === null) {
+ logger.error(`trackEvent: instance not found for testFrameworkState=${testFrameworkState} hookState=${hookState}`)
+ return
+ }
+
+ try {
+ if (CLIUtils.matchHookRegex(testFrameworkState.toString()) && hookState === HookState.PRE) {
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_HOOK_ID]: uuidv4(),
+ })
+ }
+
+ if (!TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_ID) && hookState === HookState.PRE && testFrameworkState === TestFrameworkState.TEST) {
+ const test = args.test as Frameworks.Test
+ const testData = await this.getTestData(instance, test)
+ logger.info(`trackEvent: instanceData=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`)
+ instance.updateMultipleEntries(testData)
+ }
+
+ if (testFrameworkState === TestFrameworkState.TEST) {
+ if (hookState === HookState.PRE) {
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_TEST_STARTED_AT]: new Date().toISOString(),
+ })
+ } else if (hookState === HookState.POST) {
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_TEST_ENDED_AT]: new Date().toISOString(),
+ })
+ }
+ } else if (testFrameworkState === TestFrameworkState.LOG) {
+ const logEntry = args.logEntry as Record
+ logEntry.uuid = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID)
+ this.loadLogEntries(instance, testFrameworkState, hookState, logEntry)
+ } else if (testFrameworkState === TestFrameworkState.LOG_REPORT && hookState === HookState.POST) {
+ logger.info('trackEvent: load test results')
+ this.loadTestResult(instance, args)
+ }
+
+ await this.trackHookEvents(instance, testFrameworkState, hookState, args)
+ logger.debug(`trackEvent: tracked instance data=${JSON.stringify(Object.fromEntries(instance.getAllData()))}`)
+ } catch (error) {
+ logger.error(`trackEvent: Error in tracking events: ${error} hookState=${hookState} testFrameworkState=${testFrameworkState}`)
+ }
+ args.instance = instance
+ await this.runHooks(instance, testFrameworkState, hookState, args)
+ }
+
+ /**
+ * Resolve instance for the test framework
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {HookState} hookState
+ * @param {*} args
+ * @returns {TestFrameworkInstance}
+ */
+ resolveInstance(testFrameworkState: State, hookState: State, args: Record = {}): TestFrameworkInstance|null {
+ let instance = null
+ logger.info(`resolveInstance: resolving instance for testFrameworkState=${testFrameworkState} hookState=${hookState}`)
+ if (testFrameworkState === TestFrameworkState.INIT_TEST || testFrameworkState === TestFrameworkState.NONE) {
+ this.trackWdioMochaInstance(testFrameworkState, args)
+ }
+
+ instance = TestFramework.getTrackedInstance()
+ this.updateInstanceState(instance, testFrameworkState, hookState)
+
+ return instance
+ }
+
+ /**
+ * Track WebdriverIO instance
+ * @param {TestFrameworkState} testFrameworkState
+ * @param {*} args
+ */
+ trackWdioMochaInstance(testFrameworkState: State, args: Record) {
+ const target = CLIUtils.getCurrentInstanceName()
+ const trackedContext = TrackedInstance.createContext(target)
+ let instance = null
+ logger.info(`trackWdioMochaInstance: created instance for target=${target}, state=${testFrameworkState}, args=${args}`)
+
+ instance = new TestFrameworkInstance(
+ trackedContext,
+ this.getTestFrameworks(),
+ this.getTestFrameworksVersions(),
+ testFrameworkState,
+ HookState.NONE
+ )
+
+ const frameworkName = this.getTestFrameworks()[0]
+
+ const instanceEntries = {
+ [TestFrameworkConstants.KEY_TEST_FRAMEWORK_NAME]: frameworkName,
+ [TestFrameworkConstants.KEY_TEST_FRAMEWORK_VERSION]: this.getTestFrameworksVersions()[frameworkName],
+ [TestFrameworkConstants.KEY_TEST_LOGS]: [],
+ [TestFrameworkConstants.KEY_HOOKS_FINISHED]: new Map(),
+ [TestFrameworkConstants.KEY_HOOKS_STARTED]: new Map(),
+ [TestFrameworkConstants.KEY_TEST_UUID]: uuidv4(),
+ [TestFrameworkConstants.KEY_TEST_RESULT]: TestFrameworkConstants.DEFAULT_TEST_RESULT,
+ // TODO[CLI]: Add customRerunParam
+ // [TestFrameworkConstants.KEY_TEST_RERUN_NAME]:
+ }
+
+ // Setting test uuid in env variable for A11y and App a11y scans
+ process.env[TEST_ANALYTICS_ID] = instanceEntries[TestFrameworkConstants.KEY_TEST_UUID] as string
+
+ instance.updateMultipleEntries(instanceEntries)
+
+ TestFramework.setTrackedInstance(trackedContext, instance)
+ logger.info(`trackWdioMochaInstance: saved instance contextId=${trackedContext.getId()} target=${target}`)
+ }
+
+ async getTestData(instance: TestFrameworkInstance, test: Frameworks.Test) {
+ const framework = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_FRAMEWORK_NAME)
+ const fullTitle = getUniqueIdentifier(test, framework)
+ const gitConfig = await getGitMetaData()
+ const filename = test.file // || this._suiteFile
+
+ const testData: Record = {
+ [TestFrameworkConstants.KEY_TEST_ID]: getUniqueIdentifier(test, framework),
+ [TestFrameworkConstants.KEY_TEST_NAME]: test.title || test.description,
+ [TestFrameworkConstants.KEY_TEST_CODE]: test.body || '',
+ [TestFrameworkConstants.KEY_TEST_FILE_PATH]: (gitConfig?.root && filename) ? path.relative(gitConfig.root, filename) : undefined,
+ [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path.relative(process.cwd(), filename) : undefined,
+ [TestFrameworkConstants.KEY_TEST_SCOPE]: fullTitle,
+ [TestFrameworkConstants.KEY_TEST_SCOPES]: getMochaTestHierarchy(test),
+ }
+
+ return testData
+ }
+
+ loadTestResult(instance: TestFrameworkInstance, args: Record) {
+ const results = args.result as Frameworks.TestResult
+ const { error, passed, skipped } = results
+ let result = 'passed'
+ let failure: Array|null = null
+ let failureReason: string|null = null
+ let failureType: string|null = null
+ if (!passed) {
+ if (skipped) {
+ result = 'skipped'
+ } else {
+ result = (error && error.message && error.message.includes('sync skip; aborting execution')) ? 'ignore' : 'failed'
+ }
+ if (error && result !== 'skipped') {
+ failure = [{ backtrace: [removeAnsiColors(error.message), removeAnsiColors(error.stack || '')] }] // add all errors here
+ failureReason = removeAnsiColors(error.message)
+ failureType = isUndefined(error.message) ? null : error.message.toString().match(/AssertionError/) ? 'AssertionError' : 'UnhandledError' //verify if this is working
+ }
+ }
+
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_TEST_RESULT]: result,
+ [TestFrameworkConstants.KEY_TEST_FAILURE]: failure,
+ [TestFrameworkConstants.KEY_TEST_FAILURE_REASON]: failureReason,
+ [TestFrameworkConstants.KEY_TEST_FAILURE_TYPE]: failureType,
+ })
+ }
+
+ /**
+ * Load log entries into the test framework instance.
+ * @param instance TestFrameworkInstance
+ * @param testFrameworkState TestFrameworkState
+ * @param hookState HookState
+ * @param args Additional arguments (level, message, etc.)
+ */
+ loadLogEntries(instance: TestFrameworkInstance, testFrameworkState: State, hookState: State, logEntry: Record) {
+ const logRecord: Record = {}
+ const { level, message, timestamp } = logEntry
+
+ if (CLIUtils.matchHookRegex(instance.getCurrentTestState().toString())) {
+ logRecord[TestFrameworkConstants.KEY_HOOK_ID] = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID)
+ }
+ logRecord.kind = TestFrameworkConstants.KIND_LOG
+ logRecord.message = Buffer.from(message as string)
+ logRecord.level = level
+ logRecord.timestamp = timestamp
+
+ // Attach to the suitable hook
+ const lastActiveHook = WdioMochaTestFramework.lastActiveHook(instance, WdioMochaTestFramework.KEY_HOOK_LAST_STARTED)
+ if (lastActiveHook) {
+ const hookLogs = lastActiveHook[TestFrameworkConstants.KEY_HOOK_LOGS] as unknown[]
+ hookLogs.push(logRecord)
+ logger.debug(`hooks after update logs ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED)} ${TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED)}`)
+ return
+ }
+
+ // Attach to the test instance
+ const entries = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_LOGS) as unknown[]
+ entries.push(logRecord)
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_TEST_LOGS]: entries,
+ })
+ }
+
+ /**
+ * Get the last active hook for the given instance and hook key.
+ * @param instance TestFrameworkInstance
+ * @param lastHookKey string
+ * @returns Record | null
+ */
+ static lastActiveHook(instance: TestFrameworkInstance, lastHookKey: string): Record | null {
+ const hookStore = lastHookKey === WdioMochaTestFramework.KEY_HOOK_LAST_FINISHED
+ ? TestFrameworkConstants.KEY_HOOKS_FINISHED
+ : TestFrameworkConstants.KEY_HOOKS_STARTED
+
+ const lastActive = TestFramework.getState(instance, lastHookKey) as string | null
+ let hooksMap: Record | null = null
+
+ if (lastActive) {
+ hooksMap = TestFramework.getState(instance, hookStore) as Record | null
+ }
+
+ if (hooksMap && lastActive && hooksMap[lastActive]) {
+ const lastHooks = hooksMap[lastActive] as unknown[]
+ if (lastHooks.length > 0) {
+ return lastHooks[lastHooks.length - 1] as Record
+ }
+ }
+ return null
+ }
+
+ /**
+ * Clear logs for a specific hook.
+ * @param instance TestFrameworkInstance
+ * @param lastHookKey string
+ */
+ static clearHookLogs(instance: TestFrameworkInstance, lastHookKey: string) {
+ const hook = this.lastActiveHook(instance, lastHookKey)
+ if (hook) {
+ hook[TestFrameworkConstants.KEY_HOOK_LOGS] = []
+ }
+ }
+
+ /**
+ * Clear all logs for the given instance, test framework state, and hook state.
+ * @param instance TestFrameworkInstance
+ * @param testFrameworkState TestFrameworkState
+ * @param hookState HookState
+ */
+ static clearLogs(instance: TestFrameworkInstance, testFrameworkState: State, hookState: State) {
+ const lastHookKey = hookState === HookState.PRE
+ ? WdioMochaTestFramework.KEY_HOOK_LAST_STARTED
+ : WdioMochaTestFramework.KEY_HOOK_LAST_FINISHED
+
+ WdioMochaTestFramework.clearHookLogs(instance, lastHookKey)
+
+ instance.updateMultipleEntries({
+ [TestFrameworkConstants.KEY_TEST_LOGS]: [],
+ })
+ }
+
+ /**
+ * Get all log entries for the given instance, test framework state, and hook state.
+ * @param instance TestFrameworkInstance
+ * @param testFrameworkState TestFrameworkState
+ * @param hookState HookState
+ * @returns unknown[]
+ */
+ static getLogEntries(instance: TestFrameworkInstance, testFrameworkState: State, hookState: State): unknown[] {
+ const lastHookKey = hookState === HookState.PRE
+ ? WdioMochaTestFramework.KEY_HOOK_LAST_STARTED
+ : WdioMochaTestFramework.KEY_HOOK_LAST_FINISHED
+
+ const hook = WdioMochaTestFramework.lastActiveHook(instance, lastHookKey)
+ const entries = hook ? (hook[TestFrameworkConstants.KEY_HOOK_LOGS] as unknown[]) : []
+ const testEntries = TestFramework.getState(instance, TestFrameworkConstants.KEY_TEST_LOGS) as unknown[]
+
+ return [...entries, ...testEntries]
+ }
+
+ /**
+ * Track hook events for the test framework.
+ * @param instance TestFrameworkInstance
+ * @param testFrameworkState TestFrameworkState
+ * @param hookState HookState
+ * @param args Additional arguments (e.g., test result, test method)
+ */
+ async trackHookEvents(
+ instance: TestFrameworkInstance,
+ testFrameworkState: State,
+ hookState: State,
+ args: Record
+ ) {
+ const testResult = args.result as Frameworks.TestResult
+ const test = args.test as Frameworks.Test
+ const key = testFrameworkState.toString()
+
+ const hooksStarted = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_STARTED) as Map
+ if (!hooksStarted.has(key)) {
+ hooksStarted.set(key, [])
+ }
+
+ const hooksFinished = TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOKS_FINISHED) as Map
+ if (!hooksFinished.has(key)) {
+ hooksFinished.set(key, [])
+ }
+
+ const updates: Record = {
+ [TestFrameworkConstants.KEY_HOOKS_STARTED]: hooksStarted,
+ [TestFrameworkConstants.KEY_HOOKS_FINISHED]: hooksFinished,
+ }
+
+ if (hookState === HookState.PRE) {
+ const gitConfig = await getGitMetaData()
+ const filename = test.file
+ const hook: Record = {
+ key,
+ [TestFrameworkConstants.KEY_HOOK_ID]: TestFramework.getState(instance, TestFrameworkConstants.KEY_HOOK_ID) || '',
+ [TestFrameworkConstants.KEY_HOOK_RESULT]: TestFrameworkConstants.DEFAULT_HOOK_RESULT,
+ [TestFrameworkConstants.KEY_EVENT_STARTED_AT]: new Date().toISOString(),
+ [TestFrameworkConstants.KEY_HOOK_LOGS]: [],
+ [TestFrameworkConstants.KEY_HOOK_NAME]: test.title || test.description,
+ [TestFrameworkConstants.KEY_TEST_FILE_PATH]: (gitConfig?.root && filename) ? path.relative(gitConfig.root, filename) : undefined,
+ [TestFrameworkConstants.KEY_TEST_LOCATION]: filename ? path.relative(process.cwd(), filename) : undefined,
+ }
+ hooksStarted.get(key)?.push(hook)
+ updates[WdioMochaTestFramework.KEY_HOOK_LAST_STARTED] = key
+ logger.info(`Hook Started in PRE key = ${key} & hook = ${JSON.stringify(hook)}`)
+ } else if (hookState === HookState.POST) {
+ const hooksList = hooksStarted.get(key) || []
+ logger.info(`Hook List in Post ${JSON.stringify(hooksList)}`)
+
+ if (hooksList.length > 0) {
+ const hook = hooksList.pop() as Record
+ const result = testResult.status
+ if (result !== TestFrameworkConstants.DEFAULT_HOOK_RESULT) {
+ hook[TestFrameworkConstants.KEY_HOOK_RESULT] = result
+ }
+ hook[TestFrameworkConstants.KEY_EVENT_ENDED_AT] = new Date().toISOString()
+ hooksFinished.get(key)?.push(hook)
+ updates[WdioMochaTestFramework.KEY_HOOK_LAST_FINISHED] = key
+ }
+ }
+
+ instance.updateMultipleEntries(updates)
+ logger.info(`trackHookEvents: hook state=${key}.${hookState}, hooks started=${JSON.stringify(hooksStarted)}, hooks finished=${JSON.stringify(hooksFinished)}`)
+ }
+}
diff --git a/packages/browserstack-service/src/cli/grpcClient.ts b/packages/browserstack-service/src/cli/grpcClient.ts
new file mode 100644
index 0000000..ab3f5db
--- /dev/null
+++ b/packages/browserstack-service/src/cli/grpcClient.ts
@@ -0,0 +1,616 @@
+import path from 'node:path'
+import util, { promisify } from 'node:util'
+
+import { CLIUtils } from './cliUtils.js'
+import {
+ SDKClient,
+ grpcCredentials,
+ grpcChannel,
+ StartBinSessionRequestConstructor,
+ StopBinSessionRequestConstructor,
+ ConnectBinSessionRequestConstructor,
+ TestFrameworkEventRequestConstructor,
+ TestSessionEventRequestConstructor,
+ ExecutionContextConstructor,
+ LogCreatedEventRequestConstructor,
+ // eslint-disable-next-line camelcase
+ LogCreatedEventRequest_LogEntryConstructor,
+ AutomationSessionConstructor,
+ DriverInitRequestConstructor,
+ FetchDriverExecuteParamsEventRequestConstructor
+} from '@browserstack/wdio-browserstack-service'
+
+// Type imports
+import type {
+ StartBinSessionRequest,
+ ConnectBinSessionRequest,
+ TestFrameworkEventRequest,
+ TestSessionEventRequest,
+ LogCreatedEventRequest,
+ LogCreatedEventRequest_LogEntry as LogEntry,
+ DriverInitRequest,
+ FetchDriverExecuteParamsEventRequest,
+ ConnectBinSessionResponse,
+ StartBinSessionResponse,
+ TestFrameworkEventResponse,
+ TestSessionEventResponse,
+ LogCreatedEventResponse,
+ DriverInitResponse,
+ FetchDriverExecuteParamsEventResponse,
+ TestOrchestrationRequest,
+ TestOrchestrationResponse
+} from '@browserstack/wdio-browserstack-service'
+
+import PerformanceTester from '../instrumentation/performance/performance-tester.js'
+import * as PERFORMANCE_SDK_EVENTS from '../instrumentation/performance/constants.js'
+import { BStackLogger } from './cliLogger.js'
+
+const GRPC_MESSAGE_LIMIT = 20 * 1024 * 1024 // 20 MB in bytes
+
+/**
+ * GrpcClient - Singleton class for managing gRPC client connections
+ *
+ * This class uses the singleton pattern to ensure only one gRPC client instance exists
+ * throughout the application lifecycle.
+ */
+export class GrpcClient {
+ static #instance: GrpcClient | null = null
+
+ binSessionId: string | undefined
+ listenAddress: string | undefined
+ channel: grpcChannel | null = null
+ client: SDKClient | null = null
+ logger = BStackLogger
+
+ constructor() { }
+
+ /**
+ * Get the singleton instance of GrpcClient
+ * @returns {GrpcClient} The singleton instance
+ */
+ static getInstance() {
+ if (!GrpcClient.#instance) {
+ GrpcClient.#instance = new GrpcClient()
+ }
+ return GrpcClient.#instance
+ }
+
+ /**
+ * Helper method to get client worker ID from execution context or current context.
+ * This provides a consistent way to extract worker identification across all gRPC calls.
+ *
+ * @param executionContext - Optional execution context with threadId and processId
+ * @returns Worker ID string in format "threadId-processId"
+ */
+ private getClientWorkerIdFromContext(executionContext?: { threadId?: string; processId?: string }): string {
+ return CLIUtils.getClientWorkerId(executionContext)
+ }
+
+ /**
+ * Initialize the gRPC client connection
+ * @param {string} host The gRPC server host
+ * @param {number} port The gRPC server port
+ */
+ init(params: Record) {
+ const { id, listen } = params
+ if (!id || !listen) {
+ throw new Error(`Unable to find listen addr or bin session id binSessionId: ${id} listenAddr: ${listen}`)
+ }
+
+ this.binSessionId = id
+ this.listenAddress = listen
+ process.env.BROWSERSTACK_CLI_BIN_SESSION_ID = this.binSessionId
+ process.env.BROWSERSTACK_CLI_BIN_LISTEN_ADDR = this.listenAddress
+ this.connect()
+ this.logger.info(`Initialized gRPC client with bin session id: ${this.binSessionId} and listen address: ${this.listenAddress}`)
+ }
+
+ /**
+ * Connect to the gRPC server
+ * @returns {void}
+ */
+ connect() {
+ let listenAddress = this.listenAddress
+
+ if (!listenAddress) {
+ listenAddress = process.env.BROWSERSTACK_CLI_BIN_LISTEN_ADDR
+ }
+
+ if (!this.binSessionId) {
+ this.binSessionId = this.binSessionId || process.env.BROWSERSTACK_CLI_BIN_SESSION_ID
+ }
+
+ if (!listenAddress) {
+ throw new Error('Unable to determine gRPC server listen address')
+ }
+
+ const channelOptions = {
+ 'grpc.keepalive_time_ms': 10000,
+ 'grpc.max_send_message_length': GRPC_MESSAGE_LIMIT,
+ 'grpc.max_receive_message_length': GRPC_MESSAGE_LIMIT,
+ }
+
+ // Create a channel
+ this.channel = new grpcChannel(
+ listenAddress,
+ grpcCredentials.createInsecure(),
+ channelOptions
+ )
+
+ // Create a client using the channel
+ this.client = new SDKClient(
+ listenAddress,
+ grpcCredentials.createInsecure(),
+ channelOptions
+ )
+
+ this.logger.info(`Connected to gRPC server at ${listenAddress}`)
+ }
+
+ async startBinSession(wdioConfig: string) {
+ PerformanceTester.start(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_START_BIN_SESSION)
+ this.logger.debug('startBinSession: Calling startBinSession')
+
+ try {
+ if (!this.client) {
+ this.logger.info('No gRPC client not initialized.')
+ }
+
+ const packageVersion = CLIUtils.getSdkVersion()
+ const automationFrameworkDetail = CLIUtils.getAutomationFrameworkDetail()
+ const testFrameworkDetail = CLIUtils.getTestFrameworkDetail()
+ const frameworkVersions = {
+ ...automationFrameworkDetail.version,
+ ...testFrameworkDetail.version
+ }
+
+ // Create StartBinSessionRequest
+ const clientWorkerId = CLIUtils.getClientWorkerId()
+ const request = StartBinSessionRequestConstructor.create({
+ binSessionId: this.binSessionId,
+ sdkLanguage: CLIUtils.getSdkLanguage(),
+ sdkVersion: packageVersion,
+ pathProject: process.cwd(),
+ pathConfig: path.resolve(process.cwd(), 'browserstack.yml'),
+ cliArgs: process.argv.slice(2),
+ frameworks: [automationFrameworkDetail.name, testFrameworkDetail.name],
+ frameworkVersions,
+ language: CLIUtils.getSdkLanguage(),
+ testFramework: testFrameworkDetail.name,
+ wdioConfig: wdioConfig,
+ })
+ // Add clientWorkerId and platformIndex to request (proto fields 500 & 501)
+ ;(request as unknown as Record).clientWorkerId = clientWorkerId
+ ;(request as unknown as Record).platformIndex = '0' // Default platform index for main process
+ this.logger.debug(`StartBinSession with clientWorkerId: ${clientWorkerId}, platformIndex: 0`)
+
+ const startBinSessionPromise = promisify(this.client!.startBinSession).bind(this.client!) as (arg0: StartBinSessionRequest) => Promise
+ try {
+ const response = await startBinSessionPromise(request)
+ this.logger.info('StartBinSession successful')
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_START_BIN_SESSION)
+ return response
+ } catch (error: unknown) {
+ this.logger.error(`StartBinSession error: ${util.format(error)}`)
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_START_BIN_SESSION, false, util.format(error))
+ throw error
+ }
+ } catch (error) {
+ this.logger.error(`Error in startBinSession: ${util.format(error)}`)
+ PerformanceTester.end(PERFORMANCE_SDK_EVENTS.EVENTS.SDK_START_BIN_SESSION, false, util.format(error))
+ throw error
+ }
+ }
+
+ /**
+ * Connect to the bin session
+ * @returns {Promise