diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
new file mode 100644
index 00000000..93e03cd9
--- /dev/null
+++ b/.github/workflows/e2e.yml
@@ -0,0 +1,35 @@
+name: E2E Tests
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+
+jobs:
+ e2e:
+ runs-on: ubuntu-latest
+ defaults:
+ run:
+ working-directory: packages/oc-docs
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: npm
+
+ - run: npm ci
+ working-directory: .
+
+ - run: npx playwright install --with-deps chromium
+
+ - run: npm run test:e2e
+
+ - uses: actions/upload-artifact@v4
+ if: ${{ !cancelled() }}
+ with:
+ name: playwright-report
+ path: packages/oc-docs/playwright-report/
+ retention-days: 30
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..3a885038
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+node_modules
+dist
+.DS_Store
+dist-standalone
+test.js
+
+# Claude Code
+.claude/
+CLAUDE.md
\ No newline at end of file
diff --git a/.nvmrc b/.nvmrc
new file mode 100644
index 00000000..05f04686
--- /dev/null
+++ b/.nvmrc
@@ -0,0 +1 @@
+v22.11.0
\ No newline at end of file
diff --git a/README.md b/README.md
index c6ad2087..76ba85eb 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,25 @@
# bruno-api-docs
-Interactive API documentation + playground (@opencollection/docs).
+`@opencollection/docs` — an interactive API documentation site and request playground for the [OpenCollection](https://www.opencollection.com) format.
+
+Point it at an OpenCollection and it renders a browsable docs site: a sidebar of requests, per-request documentation (params, headers, body, auth, scripts, assertions), and a live playground that sends the request and shows the response.
+
+## Install
+
+```bash
+npm install @opencollection/docs
+```
+
+## Usage
+
+It ships three ways:
+
+- **React component** — import `OpenCollection` and pass it a collection.
+- **Standalone bundle** — a self-contained JS/CSS build (`dist-standalone/`) for dropping into any page, served from the CDN.
+- **Express / server entry** — render the docs from a Node server.
+
+See [`examples/`](./examples) for a working setup of each (`react`, `standalone-html`, `express-server`).
+
+## Development
+
+Work happens in `packages/oc-docs`. See [contributing.md](./contributing.md) for setup, dev/test/build commands, and the PR flow.
diff --git a/contributing.md b/contributing.md
new file mode 100644
index 00000000..21438eaf
--- /dev/null
+++ b/contributing.md
@@ -0,0 +1,41 @@
+# Contributing to bruno-api-docs
+
+Thanks for your interest. This repo holds `@opencollection/docs`, the interactive API documentation site and request playground for the [OpenCollection](https://www.opencollection.com) format.
+
+## Prerequisites
+
+- Node.js `v22.11.0` (see [`.nvmrc`](./.nvmrc)). With nvm: `nvm use`.
+- npm (ships with Node).
+
+## Setup
+
+```bash
+git clone https://github.com/usebruno/bruno-api-docs.git
+cd bruno-api-docs
+npm install
+```
+
+## Development
+
+Run these from `packages/oc-docs`:
+
+| Task | Command |
+|------|---------|
+| Dev server | `npm run dev` |
+| Unit tests | `npm run test:run` (watch: `npm test`) |
+| E2E tests | `npm run test:e2e` |
+| Lint | `npm run lint` |
+| Build | `npm run build` (CDN bundle: `npm run build:standalone`) |
+
+## Making changes
+
+1. Open or comment on an issue first for anything beyond a small fix.
+2. Create a branch from `main`.
+3. Make your change and add or update tests. Run `npm run lint` and `npm run test:run` before pushing; run `npm run test:e2e` when UI behavior changed.
+4. Open a pull request against `main` describing the change and linking the issue.
+
+Continuous integration runs the end-to-end tests on pull requests via GitHub Actions.
+
+## Reporting issues
+
+File issues on [GitHub](https://github.com/usebruno/bruno-api-docs/issues). For bugs, include the smallest collection that reproduces the problem and what you expected to happen.
diff --git a/examples/express-server/package-lock.json b/examples/express-server/package-lock.json
new file mode 100644
index 00000000..02c94549
--- /dev/null
+++ b/examples/express-server/package-lock.json
@@ -0,0 +1,951 @@
+{
+ "name": "opencollection-express-example",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "opencollection-express-example",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "express": "^4.18.2"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.21"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
+ "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.19.6",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
+ "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.5.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.0.tgz",
+ "integrity": "sha512-y1dMvuvJspJiPSDZUQ+WMBvF7dpnEqN4x9DDC9ie5Fs/HUZJA3wFp7EhHoVaKX/iI0cRoECV8X2jL8zi0xrHCg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.12.0"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/send": {
+ "version": "0.17.5",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
+ "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.8",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
+ "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.3",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+ "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.13.0",
+ "raw-body": "2.5.2",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+ "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/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/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/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-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.21.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+ "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.3",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.7.1",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.3.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.13.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.19.0",
+ "serve-static": "1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+ "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/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/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-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/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/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/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/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/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/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/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
+ "license": "MIT"
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+ "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.6"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+ "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "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/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/send": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+ "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/send/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/serve-static": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+ "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.19.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz",
+ "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ }
+ }
+}
diff --git a/examples/express-server/package.json b/examples/express-server/package.json
new file mode 100644
index 00000000..93077f6e
--- /dev/null
+++ b/examples/express-server/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "opencollection-express-example",
+ "version": "1.0.0",
+ "description": "Express server example using OpenCollection playground",
+ "main": "server.js",
+ "type": "module",
+ "scripts": {
+ "start": "node server.js",
+ "start:cjs": "node server-cjs.cjs",
+ "dev": "node --watch server.js",
+ "dev:cjs": "node --watch server-cjs.cjs",
+ "test": "node test.js"
+ },
+ "dependencies": {
+ "express": "^4.18.2"
+ },
+ "devDependencies": {
+ "@types/express": "^4.17.21"
+ },
+ "keywords": [
+ "opencollection",
+ "express",
+ "api-docs",
+ "playground"
+ ],
+ "author": "OpenCollection",
+ "license": "MIT"
+}
\ No newline at end of file
diff --git a/examples/express-server/server-cjs.cjs b/examples/express-server/server-cjs.cjs
new file mode 100644
index 00000000..1df77472
--- /dev/null
+++ b/examples/express-server/server-cjs.cjs
@@ -0,0 +1,117 @@
+const express = require('express');
+const { playgroundHandler, setupPlaygroundAssets } = require('../../packages/oc-playground/dist/express.cjs');
+
+const app = express();
+const PORT = process.env.PORT || 3001;
+
+setupPlaygroundAssets(app, express.static, {
+ playgroundDistPath: '../../packages/oc-playground/dist-standalone'
+});
+
+const apiCollection = {
+ name: "My Express API (CommonJS)",
+ description: "Example API documentation using OpenCollection playground with Express and CommonJS",
+ docs: "This collection demonstrates different request types, bodies, auth, variables, and assertions for an Express-based API using CommonJS imports.",
+ environments: [
+ {
+ name: "Development",
+ description: "Local development environment",
+ variables: [
+ { name: "baseUrl", value: `http://localhost:${PORT}` },
+ { name: "authToken", value: "dev-token-123" }
+ ]
+ }
+ ],
+ base: {
+ headers: [
+ { name: "Content-Type", value: "application/json" }
+ ],
+ auth: {
+ type: "bearer",
+ token: "{{authToken}}"
+ }
+ },
+ items: [
+ {
+ name: "Get Users",
+ type: "http",
+ url: "{{baseUrl}}/api/users",
+ method: "GET",
+ docs: "Retrieve a list of all users",
+ params: [
+ { name: "limit", value: "10", type: "query" }
+ ],
+ assertions: [
+ { expression: "response.status", operator: "==", value: "200" }
+ ]
+ },
+ {
+ name: "Create User",
+ type: "http",
+ url: "{{baseUrl}}/api/users",
+ method: "POST",
+ docs: "Create a new user",
+ body: {
+ type: "json",
+ data: JSON.stringify({
+ name: "Bob Wilson",
+ email: "bob@example.com"
+ }, null, 2)
+ }
+ }
+ ]
+};
+
+app.get('/api-docs', playgroundHandler({
+ collection: apiCollection,
+ theme: 'dark',
+ title: 'My Express API Documentation (CommonJS)'
+}));
+
+app.get('/simple-docs', playgroundHandler({
+ name: "Simple API (CommonJS)",
+ description: "My awesome API documentation using CommonJS",
+ items: [{
+ type: "http",
+ method: "GET",
+ url: "https://api.example.com/users",
+ docs: "Get all users"
+ }]
+}));
+
+app.get('/api/users', (req, res) => {
+ res.json({
+ users: [
+ { id: 1, name: 'Bob Wilson', email: 'bob@example.com' },
+ { id: 2, name: 'Carol Davis', email: 'carol@example.com' }
+ ]
+ });
+});
+
+app.post('/api/users', express.json(), (req, res) => {
+ const { name, email } = req.body;
+ res.status(201).json({
+ id: Date.now(),
+ name,
+ email,
+ createdAt: new Date().toISOString()
+ });
+});
+
+app.get('/', (req, res) => {
+ res.send(`
+
OpenCollection Express Example (CommonJS)
+ Visit the API documentation:
+
+ `);
+});
+
+app.listen(PORT, () => {
+ console.log(`🚀 CommonJS Server running on http://localhost:${PORT}`);
+ console.log(`📚 API docs available at:`);
+ console.log(` - http://localhost:${PORT}/api-docs`);
+ console.log(` - http://localhost:${PORT}/simple-docs`);
+});
\ No newline at end of file
diff --git a/examples/express-server/server.js b/examples/express-server/server.js
new file mode 100644
index 00000000..c421bca5
--- /dev/null
+++ b/examples/express-server/server.js
@@ -0,0 +1,247 @@
+import express from 'express';
+import { playgroundHandler, setupPlaygroundAssets } from '../../packages/oc-playground/dist/express.js';
+
+const app = express();
+const PORT = process.env.PORT || 3000;
+
+setupPlaygroundAssets(app, express.static, {
+ playgroundDistPath: '../../packages/oc-playground/dist-standalone'
+});
+
+const apiCollection = {
+ name: "My Express API",
+ description: "Example API documentation using OpenCollection playground with Express",
+ docs: "This collection demonstrates different request types, bodies, auth, variables, and assertions for an Express-based API.",
+ environments: [
+ {
+ name: "Development",
+ description: "Local development environment",
+ variables: [
+ { name: "baseUrl", value: `http://localhost:${PORT}` },
+ { name: "authToken", value: "dev-token-123" }
+ ]
+ },
+ {
+ name: "Production",
+ variables: [
+ { name: "baseUrl", value: "https://api.example.com" },
+ { name: "authToken", value: "prod-token-456" }
+ ]
+ }
+ ],
+ base: {
+ headers: [
+ { name: "Content-Type", value: "application/json" }
+ ],
+ auth: {
+ type: "bearer",
+ token: "{{authToken}}"
+ },
+ variables: [
+ { name: "globalVar", value: "global-value" }
+ ]
+ },
+ items: [
+ {
+ name: "Get Users",
+ type: "http",
+ url: "{{baseUrl}}/api/users",
+ method: "GET",
+ docs: "Retrieve a list of all users",
+ params: [
+ { name: "limit", value: "10", type: "query" },
+ { name: "offset", value: "0", type: "query" }
+ ],
+ assertions: [
+ { expression: "response.status", operator: "==", value: "200" }
+ ]
+ },
+ {
+ name: "Get User by ID",
+ type: "http",
+ url: "{{baseUrl}}/api/users/:id",
+ method: "GET",
+ docs: "Get a specific user by their ID",
+ params: [
+ { name: "id", value: "123", type: "path" }
+ ],
+ headers: [
+ { name: "X-Custom-Header", value: "CustomValue" }
+ ]
+ },
+ {
+ name: "Create User",
+ type: "http",
+ url: "{{baseUrl}}/api/users",
+ method: "POST",
+ docs: "Create a new user",
+ body: {
+ type: "json",
+ data: JSON.stringify({
+ name: "Alice Johnson",
+ email: "alice@example.com",
+ role: "user"
+ }, null, 2)
+ },
+ assertions: [
+ { expression: "response.body.name", operator: "==", value: "Alice Johnson" },
+ { expression: "response.status", operator: "==", value: "201" }
+ ]
+ },
+ {
+ name: "Update User",
+ type: "http",
+ url: "{{baseUrl}}/api/users/:id",
+ method: "PUT",
+ docs: "Update an existing user",
+ params: [
+ { name: "id", value: "123", type: "path" }
+ ],
+ body: [
+ { name: "name", value: "Alice Smith" },
+ { name: "email", value: "alice.smith@example.com" }
+ ]
+ },
+ {
+ name: "Delete User",
+ type: "http",
+ url: "{{baseUrl}}/api/users/:id",
+ method: "DELETE",
+ docs: "Delete a user by ID",
+ params: [
+ { name: "id", value: "123", type: "path" }
+ ],
+ auth: {
+ type: "apikey",
+ key: "X-API-Key",
+ value: "secret-key-999",
+ placement: "header"
+ }
+ },
+ {
+ name: "User Management",
+ type: "folder",
+ docs: "Folder containing advanced user management endpoints",
+ variables: [
+ { name: "adminUserId", value: "admin-123" }
+ ],
+ headers: [
+ { name: "X-Admin-Header", value: "AdminHeaderValue" }
+ ],
+ auth: {
+ type: "basic",
+ username: "admin",
+ password: "password"
+ }
+ },
+ {
+ name: "Get Admin Dashboard",
+ type: "http",
+ url: "{{baseUrl}}/api/admin/dashboard",
+ method: "GET",
+ docs: "Access the admin dashboard (requires admin auth)"
+ }
+ ]
+};
+
+app.get('/api-docs', playgroundHandler({
+ collection: apiCollection,
+ theme: 'light',
+ title: 'My Express API Documentation'
+}));
+
+app.get('/simple-docs', playgroundHandler({
+ name: "Simple API",
+ description: "My awesome API documentation",
+ items: [{
+ type: "http",
+ method: "GET",
+ url: "https://api.example.com/users",
+ docs: "Get all users"
+ }],
+ theme: 'dark'
+}));
+
+app.get('/api/users', (req, res) => {
+ const { limit = 10, offset = 0 } = req.query;
+ res.json({
+ users: [
+ { id: 1, name: 'John Doe', email: 'john@example.com' },
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
+ ].slice(offset, offset + parseInt(limit)),
+ total: 2,
+ limit: parseInt(limit),
+ offset: parseInt(offset)
+ });
+});
+
+app.get('/api/users/:id', (req, res) => {
+ const { id } = req.params;
+ res.json({
+ id: parseInt(id),
+ name: 'John Doe',
+ email: 'john@example.com',
+ role: 'user'
+ });
+});
+
+app.post('/api/users', express.json(), (req, res) => {
+ const { name, email, role = 'user' } = req.body;
+ res.status(201).json({
+ id: Date.now(),
+ name,
+ email,
+ role,
+ createdAt: new Date().toISOString()
+ });
+});
+
+app.put('/api/users/:id', express.json(), (req, res) => {
+ const { id } = req.params;
+ const { name, email } = req.body;
+ res.json({
+ id: parseInt(id),
+ name,
+ email,
+ updatedAt: new Date().toISOString()
+ });
+});
+
+app.delete('/api/users/:id', (req, res) => {
+ const { id } = req.params;
+ res.status(204).send();
+});
+
+app.get('/api/admin/dashboard', (req, res) => {
+ res.json({
+ stats: {
+ totalUsers: 42,
+ activeUsers: 38,
+ newUsersToday: 5
+ },
+ message: 'Admin dashboard data'
+ });
+});
+
+app.get('/', (req, res) => {
+ res.send(`
+ OpenCollection Express Example
+ Visit the API documentation:
+
+ Try the API endpoints:
+
+ `);
+});
+
+app.listen(PORT, () => {
+ console.log(`🚀 Server running on http://localhost:${PORT}`);
+ console.log(`📚 API docs available at:`);
+ console.log(` - http://localhost:${PORT}/api-docs`);
+ console.log(` - http://localhost:${PORT}/simple-docs`);
+});
\ No newline at end of file
diff --git a/examples/react/index.html b/examples/react/index.html
new file mode 100644
index 00000000..87d1bf83
--- /dev/null
+++ b/examples/react/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ OpenCollection Playground - React Example
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/react/package-lock.json b/examples/react/package-lock.json
new file mode 100644
index 00000000..591843c4
--- /dev/null
+++ b/examples/react/package-lock.json
@@ -0,0 +1,1304 @@
+{
+ "name": "opencollection-react-example",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "opencollection-react-example",
+ "version": "1.0.0",
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@vitejs/plugin-react": "^4.0.0",
+ "vite": "^4.4.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+ "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.4",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.4",
+ "@babel/types": "^7.28.4",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+ "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.3",
+ "@babel/types": "^7.28.2",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.28.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+ "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.4"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+ "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+ "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+ "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+ "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+ "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+ "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+ "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+ "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+ "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+ "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+ "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+ "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+ "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+ "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+ "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+ "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+ "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+ "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+ "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+ "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+ "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+ "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/prop-types": {
+ "version": "15.7.15",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "18.3.24",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz",
+ "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "18.3.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
+ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^18.0.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
+ "integrity": "sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.26.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+ "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.8.3",
+ "caniuse-lite": "^1.0.30001741",
+ "electron-to-chromium": "^1.5.218",
+ "node-releases": "^2.0.21",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001743",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
+ "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.218",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.218.tgz",
+ "integrity": "sha512-uwwdN0TUHs8u6iRgN8vKeWZMRll4gBkz+QMqdS7DDe49uiK68/UX92lFb61oiFPrpYZNeZIqa4bA7O6Aiasnzg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/esbuild": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.20",
+ "@esbuild/android-arm64": "0.18.20",
+ "@esbuild/android-x64": "0.18.20",
+ "@esbuild/darwin-arm64": "0.18.20",
+ "@esbuild/darwin-x64": "0.18.20",
+ "@esbuild/freebsd-arm64": "0.18.20",
+ "@esbuild/freebsd-x64": "0.18.20",
+ "@esbuild/linux-arm": "0.18.20",
+ "@esbuild/linux-arm64": "0.18.20",
+ "@esbuild/linux-ia32": "0.18.20",
+ "@esbuild/linux-loong64": "0.18.20",
+ "@esbuild/linux-mips64el": "0.18.20",
+ "@esbuild/linux-ppc64": "0.18.20",
+ "@esbuild/linux-riscv64": "0.18.20",
+ "@esbuild/linux-s390x": "0.18.20",
+ "@esbuild/linux-x64": "0.18.20",
+ "@esbuild/netbsd-x64": "0.18.20",
+ "@esbuild/openbsd-x64": "0.18.20",
+ "@esbuild/sunos-x64": "0.18.20",
+ "@esbuild/win32-arm64": "0.18.20",
+ "@esbuild/win32-ia32": "0.18.20",
+ "@esbuild/win32-x64": "0.18.20"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.21",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+ "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "3.29.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
+ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=14.18.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/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/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "4.5.14",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz",
+ "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.27",
+ "rollup": "^3.27.1"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ }
+ }
+}
diff --git a/examples/react/package.json b/examples/react/package.json
new file mode 100644
index 00000000..cce434ae
--- /dev/null
+++ b/examples/react/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "opencollection-react-example",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.0",
+ "@types/react-dom": "^18.2.0",
+ "@vitejs/plugin-react": "^4.0.0",
+ "vite": "^4.4.0"
+ }
+}
\ No newline at end of file
diff --git a/examples/react/src/App.jsx b/examples/react/src/App.jsx
new file mode 100644
index 00000000..e337e055
--- /dev/null
+++ b/examples/react/src/App.jsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import { OpenCollectionPlayground } from '../../../packages/oc-playground/dist/oc-playground.es.js';
+import '../../../packages/oc-playground/dist/playground.css';
+
+const sampleCollection = {
+ name: "Sample API Collection",
+ description: "A comprehensive OpenCollection demonstration showcasing various API endpoints and configurations",
+ items: [
+ {
+ type: "http",
+ name: "Get Users",
+ method: "GET",
+ url: "https://jsonplaceholder.typicode.com/users",
+ docs: "Retrieves a list of all users from the JSONPlaceholder API",
+ headers: [
+ {
+ name: "Accept",
+ value: "application/json"
+ }
+ ]
+ },
+ {
+ type: "http",
+ name: "Create User",
+ method: "POST",
+ url: "https://jsonplaceholder.typicode.com/users",
+ docs: "Creates a new user in the system",
+ headers: [
+ {
+ name: "Content-Type",
+ value: "application/json"
+ }
+ ],
+ body: {
+ type: "json",
+ data: JSON.stringify({
+ name: "John Doe",
+ email: "john@example.com"
+ }, null, 2)
+ }
+ },
+ {
+ type: "http",
+ name: "Get All Posts",
+ method: "GET",
+ url: "https://jsonplaceholder.typicode.com/posts",
+ docs: "Retrieves all blog posts"
+ },
+ {
+ type: "http",
+ name: "Get Post by ID",
+ method: "GET",
+ url: "https://jsonplaceholder.typicode.com/posts/1",
+ docs: "Retrieves a specific post by its ID"
+ },
+ {
+ type: "script",
+ script: "// Utility functions for API testing\nfunction generateRandomId() {\n return Math.floor(Math.random() * 1000) + 1;\n}\n\nconsole.log('Utility functions loaded');"
+ }
+ ],
+ environments: [
+ {
+ name: "Production",
+ description: "Production environment configuration",
+ variables: [
+ {
+ name: "baseUrl",
+ value: "https://api.example.com"
+ }
+ ]
+ },
+ {
+ name: "Development",
+ description: "Development environment for testing",
+ variables: [
+ {
+ name: "baseUrl",
+ value: "http://localhost:3000"
+ }
+ ]
+ }
+ ]
+};
+
+function App() {
+ return (
+
+ 🚀
+
+ }
+ />
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/examples/react/src/main.jsx b/examples/react/src/main.jsx
new file mode 100644
index 00000000..7c3fd8c2
--- /dev/null
+++ b/examples/react/src/main.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import App from './App.jsx';
+
+const container = document.getElementById('root');
+const root = createRoot(container);
+
+root.render(
+
+
+
+);
\ No newline at end of file
diff --git a/examples/react/vite.config.js b/examples/react/vite.config.js
new file mode 100644
index 00000000..4568ffba
--- /dev/null
+++ b/examples/react/vite.config.js
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+
+export default defineConfig({
+ plugins: [react()],
+ server: {
+ port: 3001
+ }
+});
\ No newline at end of file
diff --git a/examples/standalone-html/bruno.json b/examples/standalone-html/bruno.json
new file mode 100644
index 00000000..50a80eba
--- /dev/null
+++ b/examples/standalone-html/bruno.json
@@ -0,0 +1,647 @@
+{
+ "name": "E-commerce API",
+ "version": "1",
+ "items": [
+ {
+ "type": "folder",
+ "name": "Cart",
+ "filename": "Cart",
+ "seq": 4,
+ "root": {
+ "docs": "Shopping cart endpoints",
+ "meta": {
+ "name": "Cart",
+ "seq": 4
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "Add Item to Cart",
+ "filename": "Add Item to Cart.bru",
+ "seq": 2,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/cart/add/item/:itemId",
+ "method": "POST",
+ "headers": [
+ {
+ "name": "Content-Type",
+ "value": "application/json",
+ "enabled": true
+ },
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [
+ {
+ "name": "itemId",
+ "value": "cd3ad475-0784-4a0d-9fe4-a9a17e5391d9",
+ "type": "path",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "json",
+ "json": "{ \n \"quantity\": 2\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Add a product to the user's shopping cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Clear Cart",
+ "filename": "Clear Cart.bru",
+ "seq": 5,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/cart",
+ "method": "DELETE",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Remove all items from the user's cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Get User Cart",
+ "filename": "Get User Cart.bru",
+ "seq": 1,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/cart",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve the current user's shopping cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Remove Item from Cart",
+ "filename": "Remove Item from Cart.bru",
+ "seq": 4,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/cart/item/:itemId",
+ "method": "DELETE",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [
+ {
+ "name": "itemId",
+ "value": "cd3ad475-0784-4a0d-9fe4-a9a17e5391d9",
+ "type": "path",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Remove a specific item from the cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Update Cart Item",
+ "filename": "Update Cart Item.bru",
+ "seq": 3,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/cart/item/:itemId",
+ "method": "PUT",
+ "headers": [
+ {
+ "name": "Content-Type",
+ "value": "application/json",
+ "enabled": true
+ },
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [
+ {
+ "name": "itemId",
+ "value": "cd3ad475-0784-4a0d-9fe4-a9a17e5391d9",
+ "type": "path",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"quantity\": 5\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Update the quantity of an item in the cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Authentication",
+ "filename": "Authentication",
+ "seq": 2,
+ "root": {
+ "docs": "User authentication endpoints",
+ "meta": {
+ "name": "Authentication",
+ "seq": 2
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "Register User",
+ "filename": "Register User.bru",
+ "seq": 1,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/auth/register",
+ "method": "POST",
+ "headers": [
+ {
+ "name": "Content-Type",
+ "value": "application/json",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"name\": \"Anoop\",\n \"email\": \"test@example.com\",\n \"password\": \"password123\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Register a new user account",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Whoami",
+ "filename": "Whoami.bru",
+ "seq": 3,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/auth/whoami",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve authenticated user's profile information",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Login",
+ "filename": "Login.bru",
+ "seq": 2,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/auth/login",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"email\": \"test@example.com\",\n \"password\": \"password123\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setEnvVar(\"accessToken\", res.body.token)"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Authenticate a user and receive a token",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Orders",
+ "filename": "Orders",
+ "seq": 5,
+ "root": {
+ "docs": "Order management endpoints",
+ "meta": {
+ "name": "Orders",
+ "seq": 5
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "Create Order",
+ "filename": "Create Order.bru",
+ "seq": 1,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/orders",
+ "method": "POST",
+ "headers": [
+ {
+ "name": "Content-Type",
+ "value": "application/json",
+ "enabled": true
+ },
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"shippingAddress\": \"Mars\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "// Check if the request was successful\nif (res.getStatus() === 200 || res.getStatus() === 201) {\n // Parse the response body\n var jsonData = res.getBody();\n \n // Check if the order has an ID\n if (jsonData && jsonData.id) {\n // Store the order ID in the environment\n bru.setEnvVar('order_id', jsonData.id);\n console.log('Order ID saved to environment: ' + jsonData.id);\n }\n}",
+ "docs": "Create a new order using the items in the user's cart",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Get User Orders",
+ "filename": "Get User Orders.bru",
+ "seq": 2,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/orders",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve a list of all orders placed by the current user",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Get Order by ID",
+ "filename": "Get Order by ID.bru",
+ "seq": 3,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/orders/:orderId",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer {{accessToken}}",
+ "enabled": true
+ }
+ ],
+ "params": [
+ {
+ "name": "orderId",
+ "value": "9c4d1e4f-64dd-465a-b52a-5471caab828b",
+ "type": "path",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve detailed information about a specific order",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "Products",
+ "filename": "Products",
+ "seq": 3,
+ "root": {
+ "docs": "Product-related endpoints. The server automatically seeds 5 sample products on startup if no products exist.",
+ "meta": {
+ "name": "Products",
+ "seq": 3
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "Get Products by Category",
+ "filename": "Get Products by Category.bru",
+ "seq": 2,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/products?category=Electronics",
+ "method": "GET",
+ "headers": [],
+ "params": [
+ {
+ "name": "category",
+ "value": "Electronics",
+ "type": "query",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve products filtered by category. Seeded categories include: Electronics, Sports, and Home.",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Get Product by ID",
+ "filename": "Get Product by ID.bru",
+ "seq": 3,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/products/:productId",
+ "method": "GET",
+ "headers": [],
+ "params": [
+ {
+ "name": "productId",
+ "value": "cd3ad475-0784-4a0d-9fe4-a9a17e5391d9",
+ "type": "path",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve detailed information about a specific product",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Get All Products",
+ "filename": "Get All Products.bru",
+ "seq": 1,
+ "settings": {},
+ "tags": [],
+ "request": {
+ "url": "{{baseUrl}}/products",
+ "method": "GET",
+ "headers": [],
+ "params": [
+ {
+ "name": "category",
+ "value": "electronics",
+ "type": "query",
+ "enabled": false
+ }
+ ],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "Retrieve a list of all products, optionally filtered by category. Default seeded categories include: Electronics, Sports, and Home.",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "activeEnvironmentUid": "RcGeNRbYHRYrqqtGIxs7V",
+ "environments": [
+ {
+ "variables": [
+ {
+ "name": "baseUrl",
+ "value": "http://localhost:3001/api",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "userToken",
+ "value": "ZjFhZDJhMDItNmQ3Yi00OTg2LWFhZjYtODJkZGE1M2UyYTJh",
+ "secret": false,
+ "enabled": true,
+ "type": "text"
+ },
+ {
+ "name": "accessToken",
+ "value": "ZjFhZDJhMDItNmQ3Yi00OTg2LWFhZjYtODJkZGE1M2UyYTJh",
+ "secret": false,
+ "enabled": true,
+ "type": "text"
+ },
+ {
+ "name": "order_id",
+ "value": "9c4d1e4f-64dd-465a-b52a-5471caab828b",
+ "secret": false,
+ "enabled": true,
+ "type": "text"
+ }
+ ],
+ "name": "dev"
+ }
+ ],
+ "root": {
+ "request": {
+ "auth": {
+ "mode": "none"
+ }
+ },
+ "docs": "Collection for testing the E-commerce API endpoints. The server automatically seeds 5 sample products (Smartphone X, Running Shoes, Coffee Maker, Laptop Pro, Wireless Earbuds) on startup if no products exist in the database.\n\n[
](https://fetch.usebruno.com?url=git%40bitbucket.org%3Ausebruno%2Fdemo-api-collection.git \"target=_blank rel=noopener noreferrer\")",
+ "meta": {
+ "name": "E-commerce API"
+ }
+ },
+ "brunoConfig": {
+ "version": "1",
+ "name": "E-commerce API",
+ "type": "collection",
+ "ignore": [
+ "node_modules",
+ ".git"
+ ],
+ "size": 0.005391120910644531,
+ "filesCount": 23
+ }
+}
\ No newline at end of file
diff --git a/examples/standalone-html/index.html b/examples/standalone-html/index.html
new file mode 100644
index 00000000..d9563841
--- /dev/null
+++ b/examples/standalone-html/index.html
@@ -0,0 +1,206 @@
+
+
+
+
+
+ OpenCollection - Standalone HTML Example
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/standalone-html/index2.html b/examples/standalone-html/index2.html
new file mode 100644
index 00000000..8c7d36da
--- /dev/null
+++ b/examples/standalone-html/index2.html
@@ -0,0 +1,268 @@
+
+
+
+
+
+ OpenCollection - Standalone HTML Example
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main.json b/main.json
new file mode 100644
index 00000000..31efaa74
--- /dev/null
+++ b/main.json
@@ -0,0 +1,4476 @@
+{
+ "name": "bruno-testbench",
+ "version": "1",
+ "items": [
+ {
+ "type": "http",
+ "name": "ping",
+ "filename": "ping.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.runner.stopExecution();"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "folder",
+ "name": "graphql",
+ "filename": "graphql",
+ "items": [
+ {
+ "type": "graphql",
+ "name": "spacex",
+ "filename": "spacex.bru",
+ "seq": 1,
+ "request": {
+ "url": "https://spacex-production.up.railway.app/",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "graphql",
+ "graphql": {
+ "query": "{\n company {\n ceo\n }\n}\n"
+ },
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "cgAc6fGnMoVZmVUmttac9"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "echo",
+ "filename": "echo",
+ "items": [
+ {
+ "type": "http",
+ "name": "echo bom json",
+ "filename": "echo bom json.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/echo/bom-json-test",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo form-url-encoded",
+ "filename": "echo form-url-encoded.bru",
+ "seq": 9,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "formUrlEncoded",
+ "formUrlEncoded": [
+ {
+ "name": "form-data-key",
+ "value": "{{form-data-key}}",
+ "enabled": true
+ },
+ {
+ "name": "form-data-stringified-object",
+ "value": "{{form-data-stringified-object}}",
+ "enabled": true
+ }
+ ],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "let obj = JSON.stringify({foo:123});\nbru.setVar('form-data-key', 'form-data-value');\nbru.setVar('form-data-stringified-object', obj);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq form-data-key=form-data-value&form-data-stringified-object=%7B%22foo%22%3A123%7D",
+ "enabled": true,
+ "uid": "GXP3iOow05yWkFbazZh97"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo json",
+ "filename": "echo json.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [
+ {
+ "name": "foo",
+ "value": "bar",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar(\"foo\", \"foo-world-2\");"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "NtmLz1fS7Ms6eQ6ZrDRN0"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"hello\": \"bruno\"\n });\n}); ",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo multipart via scripting",
+ "filename": "echo multipart scripting.bru",
+ "seq": 10,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "multipartForm",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const FormData = require(\"form-data\");\nconst form = new FormData();\nform.append('form-data-key', 'form-data-value');\nreq.setBody(form);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "contains form-data-value",
+ "enabled": true,
+ "uid": "6jqCWTqQtH6GSgpFNU3ep"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo multipart",
+ "filename": "echo multipart.bru",
+ "seq": 8,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "multipartForm",
+ "formUrlEncoded": [],
+ "multipartForm": [
+ {
+ "type": "text",
+ "name": "foo",
+ "value": "{\"bar\":\"baz\"}",
+ "enabled": true
+ },
+ {
+ "type": "text",
+ "name": "form-data-key",
+ "value": "{{form-data-key}}",
+ "enabled": true
+ },
+ {
+ "type": "text",
+ "name": "form-data-stringified-object",
+ "value": "{{form-data-stringified-object}}",
+ "enabled": true
+ },
+ {
+ "type": "file",
+ "name": "file",
+ "value": [
+ "bruno.png"
+ ],
+ "enabled": true
+ }
+ ],
+ "file": []
+ },
+ "script": {
+ "req": "let obj = JSON.stringify({foo:123});\nbru.setVar('form-data-key', 'form-data-value');\nbru.setVar('form-data-stringified-object', obj);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "contains form-data-value",
+ "enabled": true,
+ "uid": "mvYX54Lmd3i79iB48LEyz"
+ },
+ {
+ "name": "res.body",
+ "value": "contains {\"foo\":123}",
+ "enabled": true,
+ "uid": "CAEG8PjR6KPYsIbxz1N0f"
+ },
+ {
+ "name": "res.body",
+ "value": "contains Content-Type: application/json--test",
+ "enabled": true,
+ "uid": "aZHXzHRJMkWaVqA0kFLJV"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo numbers",
+ "filename": "echo numbers.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"integer\": 123,\n \"negativeInteger\": -99,\n \"zero\": 0,\n \"float\": 2.718,\n \"negativeFloat\": -1.618,\n \"largeDouble\": 12345.678901234567,\n \"smallDouble\": 9.876e-12,\n \"booleanTrue\": true,\n \"booleanFalse\": false\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body.integer",
+ "value": "eq 123",
+ "enabled": true,
+ "uid": "ZtVS9gUgc5iSmDq0gNIaT"
+ },
+ {
+ "name": "res.body.integer",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "fqLAWWm8pqG2YacqLa58R"
+ },
+ {
+ "name": "res.body.negativeInteger",
+ "value": "eq -99",
+ "enabled": true,
+ "uid": "ULU5rgNpJBc4t1OspKAIi"
+ },
+ {
+ "name": "res.body.negativeInteger",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "gpZjNNkPr2AXn6GzkhkN8"
+ },
+ {
+ "name": "res.body.zero",
+ "value": "eq 0",
+ "enabled": true,
+ "uid": "D2pXZJB9aTOAwqwXmTVEB"
+ },
+ {
+ "name": "res.body.zero",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "TE6Q5jhRkjg0Rsp0zNLl7"
+ },
+ {
+ "name": "res.body.float",
+ "value": "eq 2.718",
+ "enabled": true,
+ "uid": "izHjCWoESD3JaoDgQBwa0"
+ },
+ {
+ "name": "res.body.float",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "MRZ9PsV8AogLzvgUolu68"
+ },
+ {
+ "name": "res.body.negativeFloat",
+ "value": "eq -1.618",
+ "enabled": true,
+ "uid": "fzzJP0kj71WFqZ0DDMeIo"
+ },
+ {
+ "name": "res.body.negativeFloat",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "cm2c5v40ilCZsraGiR564"
+ },
+ {
+ "name": "res.body.largeDouble",
+ "value": "eq 12345.678901234567",
+ "enabled": true,
+ "uid": "6gnCn1c8TSHigYy1taFhN"
+ },
+ {
+ "name": "res.body.largeDouble",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "qEHQ1qRt6HyCzMqhUrdIT"
+ },
+ {
+ "name": "res.body.smallDouble",
+ "value": "eq 9.876e-12",
+ "enabled": true,
+ "uid": "ZKrwMPCjBEGqZ4yb1KxoG"
+ },
+ {
+ "name": "res.body.smallDouble",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "xRWLvDJJZSzmpz5vubw8p"
+ },
+ {
+ "name": "res.body.booleanTrue",
+ "value": "eq true",
+ "enabled": true,
+ "uid": "FENKG4gsPZtHyYYBLNKie"
+ },
+ {
+ "name": "res.body.booleanFalse",
+ "value": "eq false",
+ "enabled": true,
+ "uid": "6SoMig8CeBBIW590VwX5K"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo plaintext",
+ "filename": "echo plaintext.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/api/echo/text",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "text",
+ "text": "hello",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "uWsY31SAmtyc2JIpTxqzO"
+ }
+ ],
+ "tests": "test(\"should return plain text\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql(\"hello\");\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo xml parsed(self closing tags)",
+ "filename": "echo xml parsed(self closing tags).bru",
+ "seq": 6,
+ "request": {
+ "url": "{{host}}/api/echo/xml-parsed",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "xml",
+ "xml": "\n bruno\n \n",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "F4K7K3z239O2WvhcYc8cu"
+ }
+ ],
+ "tests": "test(\"should return parsed xml\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"hello\": {\n \"world\": [\n \"bruno\",\n \"\"\n ]\n }\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo xml parsed",
+ "filename": "echo xml parsed.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{host}}/api/echo/xml-parsed",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "xml",
+ "xml": "\n bruno\n",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "4OxoP1d1Sn7J0Rr5A5MoR"
+ }
+ ],
+ "tests": "test(\"should return parsed xml\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"hello\": {\n \"world\": [\"bruno\"]\n }\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "echo xml raw",
+ "filename": "echo xml raw.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{host}}/api/echo/xml-raw",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "xml",
+ "xml": "bruno",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test echo any",
+ "filename": "test echo any.bru",
+ "seq": 11,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain\" },\n \"content\": \"hello\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello",
+ "enabled": true,
+ "uid": "7Plt7ZGJQhoOFXFKnTQce"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test echo-any json",
+ "filename": "test echo-any json.bru",
+ "seq": 12,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"type\": \"application/json\",\n \"contentJSON\": {\"x\": 42}\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body.x",
+ "value": "eq 42",
+ "enabled": true,
+ "uid": "wU1YDNe5ZYZLi1noaCsHK"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "folder",
+ "name": "multiline",
+ "filename": "multiline",
+ "items": [
+ {
+ "type": "http",
+ "name": "echo binary",
+ "filename": "echo binary.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "file",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": [
+ {
+ "filePath": "bruno.png",
+ "contentType": "image/png",
+ "selected": true
+ }
+ ]
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "auth",
+ "filename": "auth",
+ "items": [
+ {
+ "type": "folder",
+ "name": "inherit auth",
+ "filename": "inherit auth",
+ "items": [
+ {
+ "type": "http",
+ "name": "inherit Bearer Auth 200",
+ "filename": "inherit Bearer Auth 200.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/auth/bearer/protected",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setEnvVar(\"foo\", \"bar\");"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "200",
+ "enabled": true,
+ "uid": "60I5u9Am5kDPd7juwvKV5"
+ },
+ {
+ "name": "res.body.message",
+ "value": "Authentication successful",
+ "enabled": true,
+ "uid": "fkQViSlIxJJ0RyhCN5tp3"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "inherit"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "basic",
+ "filename": "basic",
+ "items": [
+ {
+ "type": "folder",
+ "name": "via auth",
+ "filename": "via auth",
+ "items": [
+ {
+ "type": "http",
+ "name": "Basic Auth 200",
+ "filename": "Basic Auth 200.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/auth/basic/protected",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "200",
+ "enabled": true,
+ "uid": "d5CVuD1HpRVtyUWziE6Y7"
+ },
+ {
+ "name": "res.body.message",
+ "value": "Authentication successful",
+ "enabled": true,
+ "uid": "kSZPZekosG0Uci7SE8Hju"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "basic",
+ "basic": {
+ "username": "bruno",
+ "password": "{{basic_auth_password}}"
+ }
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Basic Auth 400",
+ "filename": "Basic Auth 401.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/auth/basic/protected",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "401",
+ "enabled": true,
+ "uid": "xnlyXClGdlx7gGLwzaniZ"
+ },
+ {
+ "name": "res.body",
+ "value": "Unauthorized",
+ "enabled": true,
+ "uid": "20H5jGbawcioeVKPLMsHn"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "via script",
+ "filename": "via script",
+ "items": [
+ {
+ "type": "http",
+ "name": "Basic Auth 401",
+ "filename": "Basic Auth 401.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/auth/basic/protected",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const username = \"bruno\";\nconst password = \"invalid\";\n\nconst authString = `${username}:${password}`;\nconst encodedAuthString = require('btoa')(authString);\n\nreq.setHeader(\"Authorization\", `Basic ${encodedAuthString}`);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "401",
+ "enabled": true,
+ "uid": "96LEDffmtAmfKTsfemJaB"
+ },
+ {
+ "name": "res.body",
+ "value": "Unauthorized",
+ "enabled": true,
+ "uid": "7B66oHgquEiW39PCRcf5A"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Basic Auth 200",
+ "filename": "Basic Auth 200.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/auth/basic/protected",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const username = \"bruno\";\nconst password = \"della\";\n\nconst authString = `${username}:${password}`;\nconst encodedAuthString = require('btoa')(authString);\n\nreq.setHeader(\"Authorization\", `Basic ${encodedAuthString}`);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "C7EXFxZSx9MTjrPvbZK9h"
+ },
+ {
+ "name": "res.body.message",
+ "value": "Authentication successful",
+ "enabled": true,
+ "uid": "zXFBjrNaXojNhRdJVJ86w"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "cookie",
+ "filename": "cookie",
+ "items": [
+ {
+ "type": "http",
+ "name": "Check",
+ "filename": "Check.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/auth/cookie/protected",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Login",
+ "filename": "Login.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/auth/cookie/login",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "bearer",
+ "filename": "bearer",
+ "items": [
+ {
+ "type": "folder",
+ "name": "via headers",
+ "filename": "via headers",
+ "items": [
+ {
+ "type": "http",
+ "name": "Bearer Auth 200",
+ "filename": "Bearer Auth 200.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/auth/bearer/protected",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "Authorization",
+ "value": "Bearer your_secret_token",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setEnvVar(\"foo\", \"bar\");"
+ },
+ "vars": {
+ "req": [
+ {
+ "name": "a-c",
+ "value": "foo",
+ "enabled": true,
+ "local": false
+ }
+ ]
+ },
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "200",
+ "enabled": true,
+ "uid": "uV4xNx780Qk3ff8zj0xVX"
+ },
+ {
+ "name": "res.body.message",
+ "value": "Authentication successful",
+ "enabled": true,
+ "uid": "0t9sjKI6l5tFRfLYcFLXv"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "via auth",
+ "filename": "via auth",
+ "items": [
+ {
+ "type": "http",
+ "name": "Bearer Auth 200",
+ "filename": "Bearer Auth 200.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/auth/bearer/protected",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setEnvVar(\"foo\", \"bar\");"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "200",
+ "enabled": true,
+ "uid": "nD6fKpZaZcqky2EMS3hhQ"
+ },
+ {
+ "name": "res.body.message",
+ "value": "Authentication successful",
+ "enabled": true,
+ "uid": "HRp5kskhIHPPXXDesRKj0"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "bearer",
+ "bearer": {
+ "token": "{{bearer_auth_token}}"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "multipart",
+ "filename": "multipart"
+ },
+ {
+ "type": "folder",
+ "name": "lib",
+ "filename": "lib",
+ "items": [
+ {
+ "type": "js",
+ "name": "constants",
+ "filename": "constants.js",
+ "seq": 1,
+ "fileContent": "const PI = 3.14;\n\nmodule.exports = {\n PI\n};"
+ },
+ {
+ "type": "js",
+ "name": "math",
+ "filename": "math.js",
+ "seq": 1,
+ "fileContent": "const { PI } = require('./constants');\n\nconst sum = (a, b) => a + b;\nconst areaOfCircle = (radius) => PI * radius * radius;\n\nmodule.exports = {\n sum,\n areaOfCircle\n};\n"
+ },
+ {
+ "type": "js",
+ "name": "notes",
+ "filename": "notes.js",
+ "seq": 1,
+ "fileContent": "const visualizeNotes = (res) => {\n let response = res.body;\n\n let notes = response?.notes || {};\n let responseRuntime = notes.runtime_sec || 0;\n\n notes.runtime = new Date(responseRuntime * 1000).toISOString().substr(11, 8);\n\n if (typeof response?.data === 'undefined' && typeof response?.rows === 'object') {\n response.data = response?.rows?.map(function (data) {\n return data?.values;\n });\n }\n\n const templateScript = `\n \n `;\n\n const mainScript = `\n \n `;\n\n const style = `\n \n `;\n\n const htmlString = `\n \n \n ${style}\n \n \n \n ${templateScript}\n ${mainScript}\n \n \n `;\n\n return htmlString;\n};\n\nmodule.exports = visualizeNotes;\n"
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "string interpolation",
+ "filename": "string interpolation",
+ "root": {
+ "request": {
+ "vars": {
+ "req": [
+ {
+ "name": "folder_pre_var",
+ "value": "folder_pre_var_value",
+ "enabled": true,
+ "local": false,
+ "uid": "V3bTRQFGwkKI4UoahPd2V"
+ },
+ {
+ "name": "folder_pre_var_2",
+ "value": "{{env.var1}}",
+ "enabled": true,
+ "local": false,
+ "uid": "av2XViQpOS4JZDWur8dK2"
+ }
+ ]
+ }
+ },
+ "meta": {
+ "name": "string interpolation"
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "env vars",
+ "filename": "env vars.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"envVar1\": \"{{env.var1}}\",\n \"envVar2\": \"{{env-var2}}\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "u2yA2zeeglSqFZxTDHEiZ"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n expect(res.getBody()).to.eql({\n \"envVar1\": \"envVar1\",\n \"envVar2\": \"envVar2\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "missing values",
+ "filename": "missing values.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/echo/json?foo={{undefinedVar}}",
+ "method": "POST",
+ "headers": [],
+ "params": [
+ {
+ "name": "foo",
+ "value": "{{undefinedVar}}",
+ "type": "query",
+ "enabled": true
+ }
+ ],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"{{undefinedVar2}}\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "BwlJRndmkVnlQgCdpdNoE"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const url = req.getUrl();\n const query = url.split(\"?\")[1];\n expect(query).to.equal(\"foo={{undefinedVar}}\");\n\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"hello\": \"{{undefinedVar2}}\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "process env vars",
+ "filename": "process env vars.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"bark\": \"{{bark}}\",\n \"bark2\": \"{{process.env.PROC_ENV_VAR}}\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "VDoqOFucl5B4UdBGqGCAl"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n expect(res.getBody()).to.eql({\n \"bark\": \"woof\",\n \"bark2\": \"woof\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "runtime vars",
+ "filename": "runtime vars.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/api/echo/text",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "text",
+ "json": "{\n \"envVar1\": \"{{env.var1}}\",\n \"envVar2\": \"{{env-var2}}\"\n}",
+ "text": "Hi, I am {{rUser.full_name}},\nI am {{rUser.age}} years old.\nMy favorite food is {{rUser.fav-food[0]}} and {{rUser.fav-food[1]}}.\nI like attention: {{rUser.want.attention}}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar(\"rUser\", {\n full_name: 'Bruno',\n age: 5,\n 'fav-food': ['egg', 'meat'],\n 'want.attention': true\n});"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "EodEloyMBhRCH8mPoLR8E"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const expectedResponse = `Hi, I am Bruno,\nI am 5 years old.\nMy favorite food is egg and meat.\nI like attention: true`;\n expect(res.getBody()).to.equal(expectedResponse);\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "redirects",
+ "filename": "redirects",
+ "items": [
+ {
+ "type": "http",
+ "name": "Disable Redirect",
+ "filename": "Disable Redirect.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/redirect-to-ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setMaxRedirects(0);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "302",
+ "enabled": true,
+ "uid": "Kqu9TpenOeiPke7gM6e2W"
+ }
+ ],
+ "tests": "test(\"should disable redirect to ping\", function() {\n const data = res.getBody();\n expect(data).to.equal('Found. Redirecting to /ping');\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "Test Redirect",
+ "filename": "Test Redirect.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/redirect-to-ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "200",
+ "enabled": true,
+ "uid": "IDIABjMsPFmyysPy3DDLG"
+ },
+ {
+ "name": "res.body",
+ "value": "pong",
+ "enabled": true,
+ "uid": "d74g0aRt3Mlk1yaTa2BD1"
+ }
+ ],
+ "tests": "test(\"should redirect to ping\", function() {\n const data = res.getBody();\n expect(data).to.equal('pong');\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "asserts",
+ "filename": "asserts",
+ "items": [
+ {
+ "type": "http",
+ "name": "test-assert-combinations",
+ "filename": "test-assert-combinations.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"type\": \"application/json\",\n \"contentJSON\": {\n \"string\": \"foo\",\n \"stringWithSQuotes\": \"'foo'\",\n \"stringWithDQuotes\": \"\\\"foo\\\"\",\n \"number\": 123,\n \"numberAsString\": \"123\",\n \"numberAsStringWithSQuotes\": \"'123'\",\n \"numberAsStringWithDQuotes\": \"\\\"123\\\"\",\n \"numberAsStringWithLeadingZero\": \"0123\",\n \"numberBig\": 9007199254740992000,\n \"numberBigAsString\": \"9007199254740991999\",\n \"null\": null,\n \"nullAsString\": \"null\",\n \"nullAsStringWithSQuotes\": \"'null'\",\n \"nullAsStringWithDQuotes\": \"\\\"null\\\"\",\n \"true\": true,\n \"trueAsString\": \"true\",\n \"trueAsStringWithSQuotes\": \"'true'\",\n \"trueAsStringWithDQuotes\": \"\\\"true\\\"\",\n \"false\": false,\n \"falseAsString\": \"false\",\n \"falseAsStringWithSQuotes\": \"'false'\",\n \"falseAsStringWithDQuotes\": \"\\\"false\\\"\",\n \"stringWithCurlyBraces\": \"{foo}\",\n \"stringWithDoubleCurlyBraces\": \"{{foobar}}\"\n }\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body.string",
+ "value": "eq foo",
+ "enabled": true,
+ "uid": "BIAZhDa8r5jiaeUMC9oJx"
+ },
+ {
+ "name": "res.body.string",
+ "value": "eq 'foo'",
+ "enabled": true,
+ "uid": "MmDv72YGFukil4LAZ6H1f"
+ },
+ {
+ "name": "res.body.string",
+ "value": "eq \"foo\"",
+ "enabled": true,
+ "uid": "p0YuYI8JJhOLnQmb1OJyO"
+ },
+ {
+ "name": "res.body.stringWithSQuotes",
+ "value": "eq \"'foo'\"",
+ "enabled": true,
+ "uid": "6vBjUYmjT6w680kXw5GN8"
+ },
+ {
+ "name": "res.body.stringWithDQuotes",
+ "value": "eq '\"foo\"'",
+ "enabled": true,
+ "uid": "6SlJJOabN6dqU6zzBGJ5V"
+ },
+ {
+ "name": "res.body.number",
+ "value": "eq 123",
+ "enabled": true,
+ "uid": "qsTsccOFzdaTad54qLRPD"
+ },
+ {
+ "name": "res.body.numberAsString",
+ "value": "eq '123'",
+ "enabled": true,
+ "uid": "acr4c0DbVSMHybtmPfpAK"
+ },
+ {
+ "name": "res.body.numberAsString",
+ "value": "eq \"123\"",
+ "enabled": true,
+ "uid": "j2UBEitg7trKqERvHFonB"
+ },
+ {
+ "name": "res.body.numberAsStringWithSQuotes",
+ "value": "eq \"'123'\"",
+ "enabled": true,
+ "uid": "HkhFuTMDlPTtjdRH1JtDq"
+ },
+ {
+ "name": "res.body.numberAsStringWithDQuotes",
+ "value": "eq '\"123\"'",
+ "enabled": true,
+ "uid": "FOJ9Il1Mw26AVh3mtfH2A"
+ },
+ {
+ "name": "res.body.numberAsStringWithLeadingZero",
+ "value": "eq \"0123\"",
+ "enabled": true,
+ "uid": "PYqZgMwa8utODeQu6jGZ8"
+ },
+ {
+ "name": "res.body.numberBig.toString()",
+ "value": "eq '9007199254740992000'",
+ "enabled": true,
+ "uid": "ceH22BYjeONOfjQzCQuQ5"
+ },
+ {
+ "name": "res.body.numberBigAsString",
+ "value": "eq \"9007199254740991999\"",
+ "enabled": true,
+ "uid": "ISsGCwNYz2gO1OiwCrSzj"
+ },
+ {
+ "name": "res.body.null",
+ "value": "eq null",
+ "enabled": true,
+ "uid": "ymthap5UgbSWYrA2KrhSf"
+ },
+ {
+ "name": "res.body.nullAsString",
+ "value": "eq \"null\"",
+ "enabled": true,
+ "uid": "70dQ4jmZ3NObBuSgNms4U"
+ },
+ {
+ "name": "res.body.nullAsStringWithSQuotes",
+ "value": "eq \"'null'\"",
+ "enabled": true,
+ "uid": "8sHCgezylhO5WobuMF6x5"
+ },
+ {
+ "name": "res.body.nullAsStringWithDQuotes",
+ "value": "eq '\"null\"'",
+ "enabled": true,
+ "uid": "Beo0GPeJjGChOUW3ULJFq"
+ },
+ {
+ "name": "res.body.true",
+ "value": "eq true",
+ "enabled": true,
+ "uid": "xyKYxUigaRbnsM3NUCGqo"
+ },
+ {
+ "name": "res.body.trueAsString",
+ "value": "eq \"true\"",
+ "enabled": true,
+ "uid": "TpEuGS0KamPW2P5WlNKIz"
+ },
+ {
+ "name": "res.body.trueAsStringWithSQuotes",
+ "value": "eq \"'true'\"",
+ "enabled": true,
+ "uid": "NGOStfvaFasU1BnDQBeNw"
+ },
+ {
+ "name": "res.body.trueAsStringWithDQuotes",
+ "value": "eq '\"true\"'",
+ "enabled": true,
+ "uid": "1aQu1geER6NzyRyvn6YKL"
+ },
+ {
+ "name": "res.body.false",
+ "value": "eq false",
+ "enabled": true,
+ "uid": "5hYV1aZexcmTnvWVGukhR"
+ },
+ {
+ "name": "res.body.falseAsString",
+ "value": "eq \"false\"",
+ "enabled": true,
+ "uid": "0nlBWyhHLkqwJnnQvntpH"
+ },
+ {
+ "name": "res.body.falseAsStringWithSQuotes",
+ "value": "eq \"'false'\"",
+ "enabled": true,
+ "uid": "6SyZkAdoR7nymmSuxEAVm"
+ },
+ {
+ "name": "res.body.falseAsStringWithDQuotes",
+ "value": "eq '\"false\"'",
+ "enabled": true,
+ "uid": "ikW1dRvg543wlg4OBVOj4"
+ },
+ {
+ "name": "res.body.nonexistent",
+ "value": "eq undefined",
+ "enabled": true,
+ "uid": "18cmPWFrjuhO9w3r37QbC"
+ },
+ {
+ "name": "res.body.stringWithCurlyBraces",
+ "value": "eq \"{foo}\"",
+ "enabled": true,
+ "uid": "MG7kIGiDRpVMWFsUNJwwL"
+ },
+ {
+ "name": "res.body.stringWithDoubleCurlyBraces",
+ "value": "eq \"{{foobar}}\"",
+ "enabled": true,
+ "uid": "lc8H3nkOK6oH9EU8pfGAB"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "response-parsing",
+ "filename": "response-parsing",
+ "items": [
+ {
+ "type": "http",
+ "name": "test JSON false response",
+ "filename": "test JSON false response.bru",
+ "seq": 11,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"false\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq false",
+ "enabled": true,
+ "uid": "44ByglOpNCcWR39kkFqUB"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON null response",
+ "filename": "test JSON null response.bru",
+ "seq": 6,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"null\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq null",
+ "enabled": true,
+ "uid": "SoMSHwOxrNF0mO7vjtMIq"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON number response",
+ "filename": "test JSON number response.bru",
+ "seq": 12,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"3.1\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq 3.1",
+ "enabled": true,
+ "uid": "PXORG50VO2DQhpxTe4Z9b"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON response",
+ "filename": "test JSON response.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"contentJSON\": { \"message\": \"hello\" }\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body.message",
+ "value": "eq hello",
+ "enabled": true,
+ "uid": "ghYaoqOIqNkzYySyevIbS"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON string response",
+ "filename": "test JSON string response.bru",
+ "seq": 7,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"\\\"ok\\\"\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq ok",
+ "enabled": true,
+ "uid": "lrb7s0Cy5fSBmpsnQS2hC"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON string with quotes response",
+ "filename": "test JSON string with quotes response.bru",
+ "seq": 8,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"contentJSON\": \"\\\"ok\\\"\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq '\"ok\"'",
+ "enabled": true,
+ "uid": "0vtvad5pJzWJ82EkoP1tL"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON true response",
+ "filename": "test JSON true response.bru",
+ "seq": 10,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"true\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq true",
+ "enabled": true,
+ "uid": "gWf2HHCyZEfJDjF9epFgh"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test JSON unsafe-int response",
+ "filename": "test JSON unsafe-int response.bru",
+ "seq": 13,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"90071992547409919876\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body.toString()",
+ "value": "eq 90071992547409920000",
+ "enabled": true,
+ "uid": "VPxENgWx5laoc8a8AbPSt"
+ }
+ ],
+ "tests": "",
+ "docs": "Note: This test is not perfect, we should match the unparsed raw-response with the expected string version of the unsafe-integer",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test binary response",
+ "filename": "test binary response.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"type\": \"application/octet-stream\",\n \"contentBase64\": \"+Z1P82iH1wmbILfvnhvjQVbVAktP4TzltpxYD74zNyA=\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"response matches the expectation after utf-8 decoding(needs improvement)\", function () {\n expect(res.getStatus()).to.equal(200);\n const dataBinary = Buffer.from(\"+Z1P82iH1wmbILfvnhvjQVbVAktP4TzltpxYD74zNyA=\", \"base64\"); \n expect(res.body).to.equal(dataBinary.toString(\"utf-8\"));\n});",
+ "docs": "Note:\n\nThis test is not perfect and needs to be improved by direclty matching expected binary data with raw-response.\n\nCurrently res.body is decoded with `utf-8` by default and looses data in the process. We need some property in `res` which gives access to raw-data/Buffer.",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test html response",
+ "filename": "test html response.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/html\" },\n \"content\": \"hello
\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello
",
+ "enabled": true,
+ "uid": "2ljMHST9vdVDcGsDYeea5"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test image response",
+ "filename": "test image response.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"type\": \"image/png\",\n \"contentBase64\": \"iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAQMAAABKLAcXAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAGUExURQCqAP///59OGOoAAAABYktHRAH/Ai3eAAAAB3RJTUUH6QMHCwUNKHvFmgAAABRJREFUOMtjYBgFo2AUjIJRQE8AAAV4AAEpcbn8AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDI1LTAzLTA3VDExOjA1OjEzKzAwOjAwQkgGWgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyNS0wMy0wN1QxMTowNToxMyswMDowMDMVvuYAAAAodEVYdGRhdGU6dGltZXN0YW1wADIwMjUtMDMtMDdUMTE6MDU6MTMrMDA6MDBkAJ85AAAAAElFTkSuQmCC\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text response with formatting",
+ "filename": "test plain text response with formatting.bru",
+ "seq": 18,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain\" },\n \"content\": \"hello\\n\\tworld\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello\\n\\tworld",
+ "enabled": true,
+ "uid": "krtHsmpnhOUT4SP575BjE"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text response",
+ "filename": "test plain text response.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain\" },\n \"content\": \"hello\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello",
+ "enabled": true,
+ "uid": "iiduau7JWqfG721cU41GX"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test invalid JSON response with formatting",
+ "filename": "test invalid JSON response with formatting.bru",
+ "seq": 19,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/json\" },\n \"content\": \"hello\\n\\tworld\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello\\n\\tworld",
+ "enabled": true,
+ "uid": "2Lgh5484D4lpF5w2d0y4M"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text utf16 response",
+ "filename": "test plain text utf16 response.bru",
+ "seq": 14,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain; charset=utf-16\" },\n \"contentBase64\": \"dABoAGkAcwAgAGkAcwAgAGUAbgBjAG8AZABlAGQAIAB3AGkAdABoACAAdQB0AGYAMQA2AA==\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq \"this is encoded with utf16\"",
+ "enabled": true,
+ "uid": "bTudYyt3VYDJBGUQMaBrn"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text utf16-be with BOM response",
+ "filename": "test plain text utf16-be with BOM response.bru",
+ "seq": 15,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain; charset=utf-16\" },\n \"contentBase64\": \"/v8AdABoAGkAcwAgAGkAcwAgAGUAbgBjAG8AZABlAGQAIAB3AGkAdABoACAAdQB0AGYAMQA2AC0AYgBlACAAdwBpAHQAaAAgAEIATwBN\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq \"this is encoded with utf16-be with BOM\"",
+ "enabled": true,
+ "uid": "2y4vvfKmEIiPbazx9WcI7"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text utf16-le with BOM response",
+ "filename": "test plain text utf16-le with BOM response.bru",
+ "seq": 16,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain; charset=utf-16\" },\n \"contentBase64\": \"//50AGgAaQBzACAAaQBzACAAZQBuAGMAbwBkAGUAZAAgAHcAaQB0AGgAIAB1AHQAZgAxADYALQBsAGUAIAB3AGkAdABoACAAQgBPAE0A\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq \"this is encoded with utf16-le with BOM\"",
+ "enabled": true,
+ "uid": "DoCOfg20CxCaNv59xBeMK"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test plain text utf8 with BOM response",
+ "filename": "test plain text utf8 with BOM response.bru",
+ "seq": 17,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"text/plain; charset=utf8\" },\n \"contentBase64\": \"77u/dGhpcyBpcyB1dGY4IGVuY29kZWQgd2l0aCBCT00sIHdoeSBub3Q/\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq \"this is utf8 encoded with BOM, why not?\"",
+ "enabled": true,
+ "uid": "W2wEieY0CyJnZPTS7QFdi"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "test xml response",
+ "filename": "test xml response.bru",
+ "seq": 9,
+ "request": {
+ "url": "{{httpfaker}}/api/echo/custom",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"headers\": { \"content-type\": \"application/xml\" },\n \"content\": \"hello\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.body",
+ "value": "eq hello",
+ "enabled": true,
+ "uid": "LpkeJWArhseIjWVvrRSsY"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "preview",
+ "filename": "preview",
+ "items": [
+ {
+ "type": "folder",
+ "name": "html",
+ "filename": "html",
+ "items": [
+ {
+ "type": "http",
+ "name": "bruno",
+ "filename": "bruno.bru",
+ "seq": 1,
+ "request": {
+ "url": "https://www.usebruno.com",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "Lq3jQdo5w6Sj5DmK7RR4e"
+ }
+ ],
+ "tests": "test(\"should return parsed xml\", function() {\n const headers = res.getHeaders();\n expect(headers['content-type']).to.eql(\"text/html; charset=utf-8\");\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "image",
+ "filename": "image",
+ "items": [
+ {
+ "type": "http",
+ "name": "bruno",
+ "filename": "bruno.bru",
+ "seq": 1,
+ "request": {
+ "url": "https://www.usebruno.com/favicon.ico",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should return parsed xml\", function() {\n const headers = res.getHeaders();\n expect(headers['content-type']).to.eql(\"image/x-icon\");\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "scripting",
+ "filename": "scripting",
+ "items": [
+ {
+ "type": "folder",
+ "name": "js",
+ "filename": "js",
+ "root": {
+ "request": {
+ "headers": [
+ {
+ "name": "folder-header",
+ "value": "folder-header-value",
+ "enabled": true,
+ "uid": "IbjpKtt6OSIEfbEpq63i5"
+ }
+ ],
+ "script": {
+ "req": "// used by `scripting/js/folder-collection script-tests`\nconst shouldTestFolderScripts = bru.getVar('should-test-folder-scripts');\nif(shouldTestFolderScripts) {\n bru.setVar('folder-var-set-by-folder-script', 'folder-var-value-set-by-folder-script');\n}"
+ },
+ "tests": "// used by `scripting/js/folder-collection script-tests`\nconst shouldTestFolderScripts = bru.getVar('should-test-folder-scripts');\nconst folderVar = bru.getVar(\"folder-var-set-by-folder-script\");\nif (shouldTestFolderScripts && folderVar) {\n test(\"folder level test - should get the var that was set by the folder script\", function() {\n expect(folderVar).to.equal(\"folder-var-value-set-by-folder-script\");\n }); \n bru.setVar('folder-var-set-by-folder-script', null); \n bru.setVar('should-test-folder-scripts', null);\n}"
+ },
+ "meta": {
+ "name": "js"
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "data types - request vars",
+ "filename": "data types - request vars.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"boolean\": false,\n \"number_1\": 1,\n \"number_2\": 0,\n \"number_3\": -1,\n \"string\": \"bruno\",\n \"array\": [1, 2, 3, 4, 5],\n \"object\": {\n \"hello\": \"bruno\"\n },\n \"null\": null\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "req.body.boolean",
+ "value": "isBoolean false",
+ "enabled": true,
+ "uid": "zEDwisxV9J5rpkVFsogOa"
+ },
+ {
+ "name": "req.body.number_1",
+ "value": "isNumber 1",
+ "enabled": true,
+ "uid": "dl2kC9vNfZZstXR4T7m82"
+ },
+ {
+ "name": "req.body.undefined",
+ "value": "isUndefined undefined",
+ "enabled": true,
+ "uid": "IgJsHATg2BunQdduIPWj7"
+ },
+ {
+ "name": "req.body.string",
+ "value": "isString bruno",
+ "enabled": true,
+ "uid": "ZkjsCtU9U3CXoUXQR22wr"
+ },
+ {
+ "name": "req.body.null",
+ "value": "isNull null",
+ "enabled": true,
+ "uid": "QK3P1uBuD9DwmMgQfeEIU"
+ },
+ {
+ "name": "req.body.array",
+ "value": "isArray",
+ "enabled": true,
+ "uid": "SS4pel9Lxy2zXJplAwdGl"
+ },
+ {
+ "name": "req.body.boolean",
+ "value": "eq false",
+ "enabled": true,
+ "uid": "bgDu625CBaYhGfZdDUPW0"
+ },
+ {
+ "name": "req.body.number_1",
+ "value": "eq 1",
+ "enabled": true,
+ "uid": "H0iOZFFLufmyelF7JT66C"
+ },
+ {
+ "name": "req.body.undefined",
+ "value": "eq undefined",
+ "enabled": true,
+ "uid": "NH5NrTa3rDBUovinP39vc"
+ },
+ {
+ "name": "req.body.string",
+ "value": "eq bruno",
+ "enabled": true,
+ "uid": "BWf3Y60ywGiLMP3BdtjF8"
+ },
+ {
+ "name": "req.body.null",
+ "value": "eq null",
+ "enabled": true,
+ "uid": "mz2qdTyufiVSGmDAsdDJD"
+ },
+ {
+ "name": "req.body.number_2",
+ "value": "eq 0",
+ "enabled": true,
+ "uid": "Fj8Je4fBjHQaBn9MlcyRY"
+ },
+ {
+ "name": "req.body.number_3",
+ "value": "eq -1",
+ "enabled": true,
+ "uid": "8nH1gowUVSlPE5B7zXjIu"
+ },
+ {
+ "name": "req.body.number_2",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "bZXbYyYOrxtfq3rcK4T0R"
+ },
+ {
+ "name": "req.body.number_3",
+ "value": "isNumber",
+ "enabled": true,
+ "uid": "WUpdAAGdYgyumiueofKzX"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "data types",
+ "filename": "data types.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"boolean\": false,\n \"number\": 1,\n \"string\": \"bruno\",\n \"array\": [1, 2, 3, 4, 5],\n \"object\": {\n \"hello\": \"bruno\"\n },\n \"null\": null\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const reqBody = req.getBody();\n\nbru.setVar(\"dataTypeVarTest\", {\n ...reqBody,\n \"undefined\": undefined\n});"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"data types check via bru var\", function() {\n let v = bru.getVar(\"dataTypeVarTest\");\n v = {\n ...v,\n \"undefined\": undefined\n };\n expect(v).to.eql({\n \"boolean\": false,\n \"number\": 1,\n \"string\": \"bruno\",\n \"array\": [1, 2, 3, 4, 5],\n \"object\": {\n \"hello\": \"bruno\"\n },\n \"null\": null,\n \"undefined\": undefined\n })\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "folder-collection script-tests pre",
+ "filename": "folder-collection script-tests pre.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar('should-test-collection-scripts', true);\nbru.setVar('should-test-folder-scripts', true);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "folder-collection script-tests",
+ "filename": "folder-collection script-tests.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "// do not delete - the collection/folder scripts/tests run during this request execution"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "const collectionHeader = req.getHeader(\"collection-header\");\nconst folderHeader = req.getHeader(\"folder-header\");\n\ntest(\"should get the header value set at collection level\", function() {\n expect(collectionHeader).to.equal(\"collection-header-value\");\n});\n\ntest(\"should get the header value set at folder level\", function() {\n expect(folderHeader).to.equal(\"folder-header-value\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setTimeout",
+ "filename": "setTimeout.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar(\"test-js-set-timeout\", \"\");\nawait new Promise((resolve, reject) => {\n setTimeout(() => {\n bru.setVar(\"test-js-set-timeout\", \"bruno\");\n resolve();\n }, 1000);\n});\n\nconst v = bru.getVar(\"test-js-set-timeout\");\nbru.setVar(\"test-js-set-timeout\", v + \"-is-awesome\");\n"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"setTimeout()\", function() {\n const v = bru.getVar(\"test-js-set-timeout\")\n expect(v).to.eql(\"bruno-is-awesome\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "npm modules",
+ "filename": "npm modules",
+ "items": [
+ {
+ "type": "http",
+ "name": "fakerjs",
+ "filename": "fakerjs.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const { faker } = require('@faker-js/faker');\nconst uuid = faker.string.uuid();\n\nconst data = req.getBody();\ndata.uuid = uuid;\n\nreq.setBody(data);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "lD0O3YJPd70wfjyybkyd5"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const data = res.getBody();\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n const isUUID = (inputString) => {\n return uuidRegex.test(inputString);\n };\n \n expect(data.hello).to.equal(\"bruno\");\n expect(isUUID(data.uuid)).to.be.true;\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "local modules",
+ "filename": "local modules",
+ "items": [
+ {
+ "type": "http",
+ "name": "invalid and valid module imports",
+ "filename": "invalid and valid module imports.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "try {\n bru.setVar('invalid_module_error_thrown', false);\n // should throw an error\n const invalid = require(\"./lib/invalid\");\n}\ncatch(error) {\n bru.setVar('invalid_module_error_thrown', true);\n}\n\n\ntry {\n bru.setVar('valid_module_no_error', true);\n // should not throw an error\n const math = require(\"./lib/math\");\n}\ncatch(error) {\n bru.setVar('valid_module_no_error', false);\n}"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "invalid_module_error_thrown",
+ "value": "eq true",
+ "enabled": true,
+ "uid": "3imk4DIFjOQdXZL7RKBN0"
+ },
+ {
+ "name": "valid_module_no_error",
+ "value": "eq true",
+ "enabled": true,
+ "uid": "bGJX4qgETYERw2hvg1i3U"
+ }
+ ],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "sum (without js extn)",
+ "filename": "sum (without js extn).bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"a\": 1,\n \"b\": 2\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const math = require(\"./lib/math\");\nconsole.log(math, 'math');\n\nconst body = req.getBody();\nbody.sum = math.sum(body.a, body.b);\nbody.areaOfCircle = math.areaOfCircle(2);\n\nreq.setBody(body);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "ckHfAfPNwcmxcCRBrj9sN"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"a\": 1,\n \"b\": 2,\n \"sum\": 3,\n \"areaOfCircle\": 12.56\n });\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "sum",
+ "filename": "sum.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"a\": 1,\n \"b\": 2\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const math = require(\"./lib/math.js\"); \nconst body = req.getBody();\nbody.sum = math.sum(body.a, body.b);\n\nreq.setBody(body);"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "51KAG1UxDubFYXJrXSLCR"
+ }
+ ],
+ "tests": "test(\"should return json\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"a\": 1,\n \"b\": 2,\n \"sum\": 3\n });\n});\n\ntest(\"should return json\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"a\": 1,\n \"b\": 2,\n \"sum\": 3\n });\n});\n\ntest(\"should return json\", function() {\n const data = res.getBody();\n expect(res.getBody()).to.eql({\n \"a\": 1,\n \"b\": 2,\n \"sum\": 3\n });\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "inbuilt modules",
+ "filename": "inbuilt modules",
+ "items": [
+ {
+ "type": "folder",
+ "name": "axios",
+ "filename": "axios",
+ "items": [
+ {
+ "type": "http",
+ "name": "axios-pre-req-script",
+ "filename": "axios-pre-req-script.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const axios = require(\"axios\");\n\nconst url = \"https://testbench-sanity.usebruno.com/api/echo/json\";\nconst response = await axios.post(url, {\n \"hello\": \"bruno\"\n});\n\nreq.setBody(response.data);\nreq.setMethod(\"POST\");\nreq.setUrl(url);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"req.getBody()\", function() {\n const data = res.getBody();\n expect(data).to.eql({\n \"hello\": \"bruno\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "cheerio",
+ "filename": "cheerio",
+ "items": [
+ {
+ "type": "http",
+ "name": "cheerio",
+ "filename": "cheerio.bru",
+ "seq": 1,
+ "request": {
+ "url": "https://echo.usebruno.com",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "text",
+ "text": "Hello Bruno!
",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const cheerio = require('cheerio');\n\nconst $ = cheerio.load('Hello world
');\n\n$('h2.title').text('Hello there!');\n$('h2').addClass('welcome');\n\nbru.setVar(\"cheerio-test-html\", $.html());"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "const cheerio = require('cheerio');\n\ntest(\"cheerio html - from scripts\", function() {\n const expected = 'Hello there!
';\n const html = bru.getVar('cheerio-test-html');\n expect(html).to.eql(expected);\n});\n\ntest(\"cheerio html - from tests\", function() {\n const expected = 'Hello Bruno!
';\n const $ = cheerio.load(res.body);\n expect($.html()).to.eql(expected);\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "crypto-js",
+ "filename": "crypto-js",
+ "items": [
+ {
+ "type": "http",
+ "name": "crypto-js-pre-request-script",
+ "filename": "crypto-js-pre-request-script.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "var CryptoJS = require(\"crypto-js\");\n\n// Encrypt\nvar ciphertext = CryptoJS.AES.encrypt('my message', 'secret key 123').toString();\n\n// Decrypt\nvar bytes = CryptoJS.AES.decrypt(ciphertext, 'secret key 123');\nvar originalText = bytes.toString(CryptoJS.enc.Utf8);\n\nbru.setVar('crypto-test-message', originalText);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"crypto message\", function() {\n const data = bru.getVar('crypto-test-message');\n bru.setVar('crypto-test-message', null);\n expect(data).to.eql('my message');\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "nanoid",
+ "filename": "nanoid",
+ "items": [
+ {
+ "type": "http",
+ "name": "nanoid",
+ "filename": "nanoid.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const { nanoid } = require(\"nanoid\");\n \nbru.setVar(\"nanoid-test-id\", nanoid());"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"nanoid var\", function() {\n const id = bru.getVar('nanoid-test-id');\n let isValidNanoid = /^[a-zA-Z0-9_-]{21}$/.test(id)\n bru.setVar('nanoid-test-id', null);\n expect(isValidNanoid).to.eql(true);\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "xml2js",
+ "filename": "xml2js",
+ "items": [
+ {
+ "type": "http",
+ "name": "xml2js",
+ "filename": "xml2js.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "var parseString = require('xml2js').parseString;\nvar xml = \"Hello xml2js!\"\nparseString(xml, function (err, result) {\n bru.setVar(\"xml2js-test-result\", result); \n});"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "var parseString = require('xml2js').parseString;\n\ntest(\"xml2js parseString in scripts\", function() {\n const expected = {\n root: 'Hello xml2js!'\n };\n const result = bru.getVar('xml2js-test-result');\n expect(result).to.eql(expected);\n});\n\ntest(\"xml2js parseString in tests\", async function() {\n var xml = \"Hello inside test!\"\n const expected = {\n root: 'Hello inside test!'\n };\n parseString(xml, function (err, result) {\n expect(result).to.eql(expected);\n });\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "uuid",
+ "filename": "uuid",
+ "items": [
+ {
+ "type": "http",
+ "name": "uuid",
+ "filename": "uuid.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const { v4 } = require(\"uuid\");\n \nbru.setVar(\"uuid-test-id\", v4());"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"uuid var\", function() {\n const id = bru.getVar('uuid-test-id');\n let isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id);\n bru.setVar('uuid-test-id', null);\n expect(isValidUuid).to.eql(true);\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "api",
+ "filename": "api",
+ "items": [
+ {
+ "type": "folder",
+ "name": "bru",
+ "filename": "bru",
+ "root": {
+ "request": {
+ "vars": {
+ "req": [
+ {
+ "name": "folder-var",
+ "value": "folder-var-value",
+ "enabled": true,
+ "local": false,
+ "uid": "AqPWEUdm2LylmjMIt3lkw"
+ }
+ ]
+ }
+ },
+ "meta": {
+ "name": "bru"
+ }
+ },
+ "items": [
+ {
+ "type": "http",
+ "name": "getCollectionVar",
+ "filename": "getCollectionVar.bru",
+ "seq": 9,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get collection var in scripts\", function() {\n const testVar = bru.getCollectionVar(\"collection-var\");\n expect(testVar).to.equal(\"collection-var-value\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getEnvName",
+ "filename": "getEnvName.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "const envName = bru.getEnvName();\nbru.setVar(\"testEnvName\", envName);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get env name in scripts\", function() {\n const testEnvName = bru.getVar(\"testEnvName\");\n expect(testEnvName).to.equal(\"Prod\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getEnvVar",
+ "filename": "getEnvVar.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get env var in scripts\", function() {\n const host = bru.getEnvVar(\"host\")\n expect(host).to.equal(\"https://testbench-sanity.usebruno.com\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getFolderVar",
+ "filename": "getFolderVar.bru",
+ "seq": 8,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get folder var in scripts\", function() {\n const testVar = bru.getFolderVar(\"folder-var\");\n expect(testVar).to.equal(\"folder-var-value\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getProcessEnv",
+ "filename": "getProcessEnv.bru",
+ "seq": 6,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"bru.getProcessEnv()\", function() {\n const v = bru.getProcessEnv(\"PROC_ENV_VAR\");\n expect(v).to.equal(\"woof\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getRequestVar",
+ "filename": "getRequestVar.bru",
+ "seq": 7,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {
+ "req": [
+ {
+ "name": "request-var",
+ "value": "request-var-value",
+ "enabled": true,
+ "local": false
+ }
+ ]
+ },
+ "assertions": [],
+ "tests": "test(\"should get request var in scripts\", function() {\n const testVar = bru.getRequestVar(\"request-var\");\n expect(testVar).to.equal(\"request-var-value\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getVar",
+ "filename": "getVar.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get var in scripts\", function() {\n const testSetVar = bru.getVar(\"testSetVar\");\n expect(testSetVar).to.equal(\"bruno-test-87267\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "runRequest-1",
+ "filename": "runRequest-1.bru",
+ "seq": 10,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "text",
+ "text": "bruno",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "// reset values\nbru.setVar('run-request-runtime-var', null);\nbru.setEnvVar('run-request-env-var', null);\nbru.setGlobalEnvVar('run-request-global-env-var', null);\n\n// the above vars will be set in the below request\nconst resp = await bru.runRequest('scripting/api/bru/runRequest-2');\n\nbru.setVar('run-request-resp', {\n data: resp?.data,\n statusText: resp?.statusText,\n status: resp?.status\n});"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get runtime var set in runRequest-2\", function() {\n const val = bru.getVar(\"run-request-runtime-var\");\n expect(val).to.equal(\"run-request-runtime-var-value\");\n});\n\ntest(\"should get env var set in runRequest-2\", function() {\n const val = bru.getEnvVar(\"run-request-env-var\");\n expect(val).to.equal(\"run-request-env-var-value\");\n});\n\ntest(\"should get global env var set in runRequest-2\", function() {\n const val = bru.getGlobalEnvVar(\"run-request-global-env-var\");\n const executionMode = req.getExecutionMode();\n if (executionMode == 'runner') {\n expect(val).to.equal(\"run-request-global-env-var-value\");\n }\n});\n\ntest(\"should get response of runRequest-2\", function() {\n const val = bru.getVar('run-request-resp');\n expect(JSON.stringify(val)).to.equal(JSON.stringify({\n \"data\": \"bruno\",\n \"statusText\": \"OK\",\n \"status\": 200\n }));\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "runRequest-2",
+ "filename": "runRequest-2.bru",
+ "seq": 11,
+ "request": {
+ "url": "{{echo-host}}",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "text",
+ "text": "bruno",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar('run-request-runtime-var', 'run-request-runtime-var-value');\nbru.setEnvVar('run-request-env-var', 'run-request-env-var-value');\nbru.setGlobalEnvVar('run-request-global-env-var', 'run-request-global-env-var-value');"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "runRequest",
+ "filename": "runRequest.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [
+ {
+ "name": "foo",
+ "value": "bar",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar(\"runRequest-ping-res-1\", null);\nbru.setVar(\"runRequest-ping-res-2\", null);\nbru.setVar(\"runRequest-ping-res-3\", null);\n\nlet pingRes = await bru.runRequest('ping');\nbru.setVar('runRequest-ping-res-1', {\n data: pingRes?.data,\n statusText: pingRes?.statusText,\n status: pingRes?.status\n});",
+ "res": "let pingRes = await bru.runRequest('ping');\nbru.setVar('runRequest-ping-res-2', {\n data: pingRes?.data,\n statusText: pingRes?.statusText,\n status: pingRes?.status\n});"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "XiYVLMGIQARuIZRmXYS65"
+ }
+ ],
+ "tests": "const pingRes = await bru.runRequest('ping');\nbru.setVar('runRequest-ping-res-3', {\n data: pingRes?.data,\n statusText: pingRes?.statusText,\n status: pingRes?.status\n});\n\ntest(\"should run request and return valid response in pre-request script\", function() {\n const expectedPingRes = {\n data: \"pong\",\n statusText: \"OK\",\n status: 200\n };\n const pingRes = bru.getVar('runRequest-ping-res-1');\n expect(pingRes).to.eql(expectedPingRes);\n});\n\ntest(\"should run request and return valid response in post-response script\", function() {\n const expectedPingRes = {\n data: \"pong\",\n statusText: \"OK\",\n status: 200\n };\n const pingRes = bru.getVar('runRequest-ping-res-2');\n expect(pingRes).to.eql(expectedPingRes);\n});\n\ntest(\"should run request and return valid response in tests script\", function() {\n const expectedPingRes = {\n data: \"pong\",\n statusText: \"OK\",\n status: 200\n };\n const pingRes = bru.getVar('runRequest-ping-res-3');\n expect(pingRes).to.eql(expectedPingRes);\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setEnvVar",
+ "filename": "setEnvVar.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setEnvVar(\"testSetEnvVar\", \"bruno-29653\")"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should set env var in scripts\", function() {\n const testSetEnvVar = bru.getEnvVar(\"testSetEnvVar\")\n expect(testSetEnvVar).to.equal(\"bruno-29653\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setVar",
+ "filename": "setVar.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "res": "bru.setVar(\"testSetVar\", \"bruno-test-87267\")"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "test(\"should get var in scripts\", function() {\n const testSetVar = bru.getVar(\"testSetVar\");\n expect(testSetVar).to.equal(\"bruno-test-87267\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "folder",
+ "name": "runner",
+ "filename": "runner",
+ "items": [
+ {
+ "type": "http",
+ "name": "1",
+ "filename": "1.bru",
+ "seq": 1,
+ "request": {
+ "url": "https://echo.usebruno.com",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.setVar('bru-runner-req', 1);",
+ "res": "bru.setVar('bru.runner.skipRequest', true);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "2",
+ "filename": "2.bru",
+ "seq": 2,
+ "request": {
+ "url": "https://echo.usebruno.com",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "bru.runner.skipRequest();",
+ "res": "bru.setVar('bru.runner.skipRequest', false);"
+ },
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "3",
+ "filename": "3.bru",
+ "seq": 3,
+ "request": {
+ "url": "https://echo.usebruno.com",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [],
+ "tests": "",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "req",
+ "filename": "req",
+ "items": [
+ {
+ "type": "http",
+ "name": "getBody",
+ "filename": "getBody.bru",
+ "seq": 9,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "YACUsQsYlX6yvIkkHfGeM"
+ }
+ ],
+ "tests": "test(\"req.getBody()\", function() {\n const data = res.getBody();\n expect(data).to.eql({\n \"hello\": \"bruno\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getHeader",
+ "filename": "getHeader.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "bruno",
+ "value": "is-awesome",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "1fFLd8VtOZKujvtAkGUZj"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "QD11VDqnqq5jTcL88Y3D1"
+ }
+ ],
+ "tests": "test(\"req.getHeader(name)\", function() {\n const h = req.getHeader('bruno');\n expect(h).to.equal(\"is-awesome\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getHeaders",
+ "filename": "getHeaders.bru",
+ "seq": 7,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "bruno",
+ "value": "is-awesome",
+ "enabled": true
+ },
+ {
+ "name": "della",
+ "value": "is-beautiful",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "04R4EJbusCqY89KXTKajO"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "CKd1EZjgvkeFB6a25BpDc"
+ }
+ ],
+ "tests": "test(\"req.getHeaders()\", function() {\n const h = req.getHeaders();\n expect(h.bruno).to.equal(\"is-awesome\");\n expect(h.della).to.equal(\"is-beautiful\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getMethod",
+ "filename": "getMethod.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "5ItoSs1VqOfB0sll7wqpN"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "JdEtqrNa8XTVM8bwHYNLq"
+ }
+ ],
+ "tests": "test(\"req.getMethod()()\", function() {\n const method = req.getMethod();\n expect(method).to.equal(\"GET\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getUrl",
+ "filename": "getUrl.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "OkR2RNGAnwkPvXPex4huK"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "T7L4EFpqrauldg2JOGshM"
+ }
+ ],
+ "tests": "test(\"req.getUrl()\", function() {\n const url = req.getUrl();\n expect(url).to.equal(\"https://testbench-sanity.usebruno.com/ping\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setBody",
+ "filename": "setBody.bru",
+ "seq": 10,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setBody({\n \"bruno\": \"is awesome\"\n});"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "1tuWeypKcGgbuLEXYF54S"
+ }
+ ],
+ "tests": "test(\"req.setBody()\", function() {\n const data = res.getBody();\n expect(data).to.eql({\n \"bruno\": \"is awesome\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setHeader",
+ "filename": "setHeader.bru",
+ "seq": 6,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "bruno",
+ "value": "is-awesome",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setHeader('bruno', 'is-the-future');"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "jLHIdvmg0VXn4PLW5Ch3j"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "PLKiqwDU1HsEkwchjyNky"
+ }
+ ],
+ "tests": "test(\"req.setHeader(name)\", function() {\n const h = req.getHeader('bruno');\n expect(h).to.equal(\"is-the-future\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setHeaders",
+ "filename": "setHeaders.bru",
+ "seq": 8,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [
+ {
+ "name": "bruno",
+ "value": "is-awesome",
+ "enabled": true
+ },
+ {
+ "name": "della",
+ "value": "is-beautiful",
+ "enabled": true
+ }
+ ],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setHeaders({\n \"content-type\": \"application/text\",\n \"transaction-id\": \"foobar\"\n});"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "cFZM1lk0lnaR845ZQscl9"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "Gt07qor0o6lnGiMGvtPF3"
+ }
+ ],
+ "tests": "test(\"req.setHeaders()\", function() {\n const h = req.getHeaders();\n expect(h['content-type']).to.equal(\"application/text\");\n expect(h['transaction-id']).to.equal(\"foobar\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setMethod",
+ "filename": "setMethod.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setMethod(\"GET\");"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "cJZfmbnZVfdaenvhz4wfq"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "wHTmbMRx9ZYWSZ8QivM8h"
+ }
+ ],
+ "tests": "test(\"req.setMethod()()\", function() {\n const method = req.getMethod();\n expect(method).to.equal(\"GET\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "setUrl",
+ "filename": "setUrl.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/ping/invalid",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {
+ "req": "req.setUrl(\"https://testbench-sanity.usebruno.com/ping\");"
+ },
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "rVolqUH1aCO0NurDPCA0T"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "5ynLdeD42v7nQlvI8ORXZ"
+ }
+ ],
+ "tests": "test(\"req.setUrl()\", function() {\n const url = req.getUrl();\n expect(url).to.equal(\"https://testbench-sanity.usebruno.com/ping\");\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "type": "folder",
+ "name": "res",
+ "filename": "res",
+ "items": [
+ {
+ "type": "http",
+ "name": "getBody",
+ "filename": "getBody.bru",
+ "seq": 4,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "QAa35PSfpwk267ompkUyX"
+ }
+ ],
+ "tests": "test(\"res.getBody()\", function() {\n const data = res.getBody();\n expect(data).to.eql({\n \"hello\": \"bruno\"\n });\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getHeader",
+ "filename": "getHeader.bru",
+ "seq": 2,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "QfXtdGakjK897gTqaU4PE"
+ }
+ ],
+ "tests": "test(\"res.getHeader(name)\", function() {\n const server = res.getHeader('x-powered-by');\n expect(server).to.eql('Express');\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getHeaders",
+ "filename": "getHeaders.bru",
+ "seq": 3,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "WCmqMcNZlAoJdZ9g2KLVe"
+ }
+ ],
+ "tests": "test(\"res.getHeaders(name)\", function() {\n const h = res.getHeaders();\n expect(h['x-powered-by']).to.eql('Express');\n expect(h['content-length']).to.eql('17');\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getResponseTime",
+ "filename": "getResponseTime.bru",
+ "seq": 5,
+ "request": {
+ "url": "{{host}}/api/echo/json",
+ "method": "POST",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "json",
+ "json": "{\n \"hello\": \"bruno\"\n}",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "DpDzW3VB5cIFdxtvxe6Og"
+ }
+ ],
+ "tests": "test(\"res.getResponseTime()\", function() {\n const responseTime = res.getResponseTime();\n expect(typeof responseTime).to.eql(\"number\");\n expect(responseTime > 0).to.be.true;\n});\n",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getStatus",
+ "filename": "getStatus.bru",
+ "seq": 1,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.status",
+ "value": "eq 200",
+ "enabled": true,
+ "uid": "9lIBr7KIWkUTYANiSBNAW"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "TnsOCt0EUxB7meZTOkEdb"
+ }
+ ],
+ "tests": "test(\"res.getStatus()\", function() {\n const status = res.getStatus()\n expect(status).to.equal(200);\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ },
+ {
+ "type": "http",
+ "name": "getStatusText",
+ "filename": "getStatusText.bru",
+ "seq": 6,
+ "request": {
+ "url": "{{host}}/ping",
+ "method": "GET",
+ "headers": [],
+ "params": [],
+ "body": {
+ "mode": "none",
+ "formUrlEncoded": [],
+ "multipartForm": [],
+ "file": []
+ },
+ "script": {},
+ "vars": {},
+ "assertions": [
+ {
+ "name": "res.statusText",
+ "value": "eq OK",
+ "enabled": true,
+ "uid": "bhhg2wMYFSh060HKl8Vgq"
+ },
+ {
+ "name": "res.body",
+ "value": "eq pong",
+ "enabled": true,
+ "uid": "DTYW4zxmKrtsbPxqn8U5E"
+ }
+ ],
+ "tests": "test(\"res.getStatusText()\", function() {\n const statusText = res.getStatusText()\n expect(statusText).to.equal('OK');\n});",
+ "docs": "",
+ "auth": {
+ "mode": "none"
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "activeEnvironmentUid": "epJ1gynipcQgb5uJLBHZr",
+ "environments": [
+ {
+ "variables": [
+ {
+ "name": "host",
+ "value": "http://localhost:8080",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "httpfaker",
+ "value": "https://www.httpfaker.org",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "bearer_auth_token",
+ "value": "your_secret_token",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "basic_auth_password",
+ "value": "della",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "env.var1",
+ "value": "envVar1",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "env-var2",
+ "value": "envVar2",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "bark",
+ "value": "{{process.env.PROC_ENV_VAR}}",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "foo",
+ "value": "bar",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "testSetEnvVar",
+ "value": "bruno-29653",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "echo-host",
+ "value": "https://echo.usebruno.com",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "client_id",
+ "value": "client_id_1",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "client_secret",
+ "value": "client_secret_1",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "auth_url",
+ "value": "http://localhost:8080/api/auth/oauth2/authorization_code/authorize",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "callback_url",
+ "value": "http://localhost:8080/api/auth/oauth2/authorization_code/callback",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "access_token_url",
+ "value": "http://localhost:8080/api/auth/oauth2/authorization_code/token",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "passwordCredentials_username",
+ "value": "foo",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "passwordCredentials_password",
+ "value": "bar",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "github_authorize_url",
+ "value": "https://github.com/login/oauth/authorize",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "github_access_token_url",
+ "value": "https://github.com/login/oauth/access_token",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "google_auth_url",
+ "value": "https://accounts.google.com/o/oauth2/auth",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "google_access_token_url",
+ "value": "https://accounts.google.com/o/oauth2/token",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "google_scope",
+ "value": "https://www.googleapis.com/auth/userinfo.email",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "github_client_secret",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "github_client_id",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "google_client_id",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "google_client_secret",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "github_authorization_code",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "passwordCredentials_access_token",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "client_credentials_access_token",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "authorization_code_access_token",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ },
+ {
+ "name": "github_access_token",
+ "value": "",
+ "enabled": true,
+ "secret": true,
+ "type": "text"
+ }
+ ],
+ "name": "Local"
+ },
+ {
+ "variables": [
+ {
+ "name": "host",
+ "value": "https://testbench-sanity.usebruno.com",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "httpfaker",
+ "value": "https://www.httpfaker.org",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "bearer_auth_token",
+ "value": "your_secret_token",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "basic_auth_password",
+ "value": "della",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "env.var1",
+ "value": "envVar1",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "env-var2",
+ "value": "envVar2",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "bark",
+ "value": "{{process.env.PROC_ENV_VAR}}",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "foo",
+ "value": "bar",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "testSetEnvVar",
+ "value": "bruno-29653",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ },
+ {
+ "name": "echo-host",
+ "value": "https://echo.usebruno.com",
+ "enabled": true,
+ "secret": false,
+ "type": "text"
+ }
+ ],
+ "name": "Prod"
+ }
+ ],
+ "root": {
+ "request": {
+ "auth": {
+ "mode": "bearer",
+ "bearer": {
+ "token": "{{bearer_auth_token}}"
+ }
+ },
+ "headers": [
+ {
+ "name": "check",
+ "value": "again",
+ "enabled": true,
+ "uid": "x5ic2SWqv4uOlkzzUaK6u"
+ },
+ {
+ "name": "token",
+ "value": "{{collection_pre_var_token}}",
+ "enabled": true,
+ "uid": "MdFY4Vekah6cfuxuClOCu"
+ },
+ {
+ "name": "collection-header",
+ "value": "collection-header-value",
+ "enabled": true,
+ "uid": "wCrMSPJUrX9QljaY6kadq"
+ }
+ ],
+ "script": {
+ "req": "// used by `scripting/js/folder-collection script-tests`\nconst shouldTestCollectionScripts = bru.getVar('should-test-collection-scripts');\nif(shouldTestCollectionScripts) {\n bru.setVar('collection-var-set-by-collection-script', 'collection-var-value-set-by-collection-script');\n}"
+ },
+ "vars": {
+ "req": [
+ {
+ "name": "collection_pre_var",
+ "value": "collection_pre_var_value",
+ "enabled": true,
+ "local": false,
+ "uid": "6K19B5ZyhSBTB1ilbx2Sx"
+ },
+ {
+ "name": "collection_pre_var_token",
+ "value": "{{request_pre_var_token}}",
+ "enabled": true,
+ "local": false,
+ "uid": "zdoL9ayNeJnNY7ot6RHDj"
+ },
+ {
+ "name": "collection-var",
+ "value": "collection-var-value",
+ "enabled": true,
+ "local": false,
+ "uid": "6tgTaZw6HTazsyAMWrVfL"
+ }
+ ]
+ },
+ "tests": "// used by `scripting/js/folder-collection script-tests`\nconst shouldTestCollectionScripts = bru.getVar('should-test-collection-scripts');\nconst collectionVar = bru.getVar(\"collection-var-set-by-collection-script\");\nif (shouldTestCollectionScripts && collectionVar) {\n test(\"collection level test - should get the var that was set by the collection script\", function() {\n expect(collectionVar).to.equal(\"collection-var-value-set-by-collection-script\");\n }); \n bru.setVar('collection-var-set-by-collection-script', null); \n bru.setVar('should-test-collection-scripts', null);\n}"
+ },
+ "docs": "# bruno-testbench 🐶\n\nThis is a test collection that I am using to test various functionalities around bruno"
+ },
+ "brunoConfig": {
+ "version": "1",
+ "name": "bruno-testbench",
+ "type": "collection",
+ "proxy": {
+ "enabled": false,
+ "protocol": "http",
+ "hostname": "{{proxyHostname}}",
+ "port": 4000,
+ "auth": {
+ "enabled": false,
+ "username": "anoop"
+ },
+ "bypassProxy": ""
+ },
+ "scripts": {
+ "moduleWhitelist": [
+ "crypto",
+ "buffer",
+ "form-data"
+ ],
+ "filesystemAccess": {
+ "allow": true
+ }
+ },
+ "clientCertificates": {
+ "enabled": true,
+ "certs": []
+ },
+ "presets": {
+ "requestType": "http",
+ "requestUrl": "http://localhost:6000"
+ },
+ "ignore": [
+ "node_modules",
+ ".git"
+ ],
+ "size": 0.046390533447265625,
+ "filesCount": 104
+ }
+ }
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..306175a7
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,9693 @@
+{
+ "name": "opencollection",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "opencollection",
+ "workspaces": [
+ "packages/oc-docs"
+ ]
+ },
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "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",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
+ "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+ "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.7"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+ "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+ "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
+ "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@codemirror/autocomplete": {
+ "version": "6.20.3",
+ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz",
+ "integrity": "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.17.0",
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/commands": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.4.tgz",
+ "integrity": "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.7.0",
+ "@codemirror/view": "^6.27.0",
+ "@lezer/common": "^1.1.0"
+ }
+ },
+ "node_modules/@codemirror/language": {
+ "version": "6.12.4",
+ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.4.tgz",
+ "integrity": "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.23.0",
+ "@lezer/common": "^1.5.0",
+ "@lezer/highlight": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "style-mod": "^4.0.0"
+ }
+ },
+ "node_modules/@codemirror/lint": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.7.tgz",
+ "integrity": "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.42.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/search": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.1.tgz",
+ "integrity": "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.37.0",
+ "crelt": "^1.0.5"
+ }
+ },
+ "node_modules/@codemirror/state": {
+ "version": "6.7.1",
+ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.7.1.tgz",
+ "integrity": "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@marijn/find-cluster-break": "^1.0.0"
+ }
+ },
+ "node_modules/@codemirror/view": {
+ "version": "6.43.6",
+ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.6.tgz",
+ "integrity": "sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/state": "^6.7.0",
+ "crelt": "^1.0.6",
+ "style-mod": "^4.1.0",
+ "w3c-keyname": "^2.2.4"
+ }
+ },
+ "node_modules/@emotion/babel-plugin": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
+ "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.16.7",
+ "@babel/runtime": "^7.18.3",
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/serialize": "^1.3.3",
+ "babel-plugin-macros": "^3.1.0",
+ "convert-source-map": "^1.5.0",
+ "escape-string-regexp": "^4.0.0",
+ "find-root": "^1.1.0",
+ "source-map": "^0.5.7",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/cache": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz",
+ "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "stylis": "4.2.0"
+ }
+ },
+ "node_modules/@emotion/css": {
+ "version": "11.13.5",
+ "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz",
+ "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/cache": "^11.13.5",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/sheet": "^1.4.0",
+ "@emotion/utils": "^1.4.2"
+ }
+ },
+ "node_modules/@emotion/hash": {
+ "version": "0.9.2",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz",
+ "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz",
+ "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/memoize": "^0.9.0"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz",
+ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/react": {
+ "version": "11.14.0",
+ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
+ "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/cache": "^11.14.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2",
+ "@emotion/weak-memoize": "^0.4.0",
+ "hoist-non-react-statics": "^3.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/serialize": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
+ "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@emotion/memoize": "^0.9.0",
+ "@emotion/unitless": "^0.10.0",
+ "@emotion/utils": "^1.4.2",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/@emotion/sheet": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz",
+ "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/styled": {
+ "version": "11.14.1",
+ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
+ "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.3",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@emotion/is-prop-valid": "^1.3.0",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
+ "@emotion/utils": "^1.4.2"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.0.0-rc.0",
+ "react": ">=16.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@emotion/unitless": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz",
+ "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
+ "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@emotion/utils": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz",
+ "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==",
+ "license": "MIT"
+ },
+ "node_modules/@emotion/weak-memoize": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz",
+ "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
+ "license": "MIT"
+ },
+ "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"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
+ "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.7",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.5"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
+ "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
+ "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz",
+ "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.14.0",
+ "debug": "^4.3.2",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.3.0",
+ "minimatch": "^3.1.5",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@eslint/js": {
+ "version": "9.39.5",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz",
+ "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
+ "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
+ "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^0.17.0",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@faker-js/faker": {
+ "version": "9.9.0",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.9.0.tgz",
+ "integrity": "sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fakerjs"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=9.0.0"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@jitl/quickjs-ffi-types": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@jitl/quickjs-ffi-types/-/quickjs-ffi-types-0.31.0.tgz",
+ "integrity": "sha512-1yrgvXlmXH2oNj3eFTrkwacGJbmM0crwipA3ohCrjv52gBeDaD7PsTvFYinlAnqU8iPME3LGP437yk05a2oejw==",
+ "license": "MIT"
+ },
+ "node_modules/@jitl/quickjs-wasmfile-debug-asyncify": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-asyncify/-/quickjs-wasmfile-debug-asyncify-0.31.0.tgz",
+ "integrity": "sha512-YkdzQdr1uaftFhgEnTRjTTZHk2SFZdpWO7XhOmRVbi6CEVsH9g5oNF8Ta1q3OuSJHRwwT8YsuR1YzEiEIJEk6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-ffi-types": "0.31.0"
+ }
+ },
+ "node_modules/@jitl/quickjs-wasmfile-debug-sync": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-debug-sync/-/quickjs-wasmfile-debug-sync-0.31.0.tgz",
+ "integrity": "sha512-8XvloaaWBONqcHXYs5tWOjdhQVxzULilIfB2hvZfS6S+fI4m2+lFiwQy7xeP8ExHmiZ7D8gZGChNkdLgjGfknw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-ffi-types": "0.31.0"
+ }
+ },
+ "node_modules/@jitl/quickjs-wasmfile-release-asyncify": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-asyncify/-/quickjs-wasmfile-release-asyncify-0.31.0.tgz",
+ "integrity": "sha512-uz0BbQYTxNsFkvkurd7vk2dOg57ElTBLCuvNtRl4rgrtbC++NIndD5qv2+AXb6yXDD3Uy1O2PCwmoaH0eXgEOg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-ffi-types": "0.31.0"
+ }
+ },
+ "node_modules/@jitl/quickjs-wasmfile-release-sync": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/@jitl/quickjs-wasmfile-release-sync/-/quickjs-wasmfile-release-sync-0.31.0.tgz",
+ "integrity": "sha512-hYduecOByj9AsAfsJhZh5nA6exokmuFC8cls39+lYmTCGY51bgjJJJwReEu7Ff7vBWaQCL6TeDdVlnp2WYz0jw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-ffi-types": "0.31.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@lezer/common": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.2.tgz",
+ "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==",
+ "license": "MIT"
+ },
+ "node_modules/@lezer/highlight": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
+ "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.3.0"
+ }
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.4.10",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.10.tgz",
+ "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@marijn/find-cluster-break": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.3.tgz",
+ "integrity": "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==",
+ "license": "MIT"
+ },
+ "node_modules/@mintlify/httpsnippet": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@mintlify/httpsnippet/-/httpsnippet-1.0.11.tgz",
+ "integrity": "sha512-Hlp9STlZn+Y3uXAWW9RqsJL63vmt7EEW9A6X4siW1AEHMHDCIse75Adcwf26IJvzWTWrXjwjYDBVL8teOO1UuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "qs": "6.14.2",
+ "stringify-object": "3.3.0",
+ "type-fest": "5.2.0"
+ }
+ },
+ "node_modules/@monaco-editor/loader": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.7.0.tgz",
+ "integrity": "sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==",
+ "license": "MIT",
+ "dependencies": {
+ "state-local": "^1.0.6"
+ }
+ },
+ "node_modules/@monaco-editor/react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.7.0.tgz",
+ "integrity": "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@monaco-editor/loader": "^1.5.0"
+ },
+ "peerDependencies": {
+ "monaco-editor": ">= 0.25.0 < 1",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@opencollection/docs": {
+ "resolved": "packages/oc-docs",
+ "link": true
+ },
+ "node_modules/@opencollection/types": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.11.0.tgz",
+ "integrity": "sha512-6Ehji+5P9DaPYtJusbzZMbNOsYOPb1qwV7Y6ZYhPF+oWQkwPPEIgzKBU8qZbtxaHXuISgrItr6AoBRFWcyPMbw==",
+ "license": "MIT"
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.1.tgz",
+ "integrity": "sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright": "1.61.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
+ "node_modules/@prantlf/jsonlint": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/@prantlf/jsonlint/-/jsonlint-16.1.0.tgz",
+ "integrity": "sha512-in5eDSz+Y4Se2avdlXU0CENjUHaw10+ChJYt5fNUgdrg08ywAC4vFXDdlZbPzQU+brzbrOZesTgpAtSROoXdBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "8.17.1",
+ "ajv-draft-04": "1.0.0",
+ "ajv-formats": "^3.0.1",
+ "ajv-formats-draft2019": "^1.6.1",
+ "ajv-keywords": "^5.1.0",
+ "cosmiconfig": "9.0.0",
+ "diff": "8.0.2",
+ "fast-glob": "3.3.3",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "jsonlint": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=16.9"
+ }
+ },
+ "node_modules/@prantlf/jsonlint/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz",
+ "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^11.0.0",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.27",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz",
+ "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz",
+ "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz",
+ "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz",
+ "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz",
+ "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz",
+ "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz",
+ "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz",
+ "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz",
+ "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz",
+ "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz",
+ "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz",
+ "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz",
+ "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz",
+ "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz",
+ "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz",
+ "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz",
+ "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz",
+ "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz",
+ "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz",
+ "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz",
+ "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz",
+ "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz",
+ "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz",
+ "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz",
+ "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
+ "node_modules/@tabler/icons": {
+ "version": "1.119.0",
+ "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-1.119.0.tgz",
+ "integrity": "sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/codecalm"
+ },
+ "peerDependencies": {
+ "react": "^16.x || 17.x || 18.x",
+ "react-dom": "^16.x || 17.x || 18.x"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
+ "jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz",
+ "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "postcss": "^8.5.16",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/typography": {
+ "version": "0.5.20",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.20.tgz",
+ "integrity": "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "6.0.10"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || >=4.0.0 || insiders"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
+ "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "tailwindcss": "4.3.3"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
+ }
+ },
+ "node_modules/@tippyjs/react": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
+ "integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==",
+ "license": "MIT",
+ "dependencies": {
+ "tippy.js": "^6.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.2"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.13",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
+ "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*"
+ }
+ },
+ "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==",
+ "license": "MIT"
+ },
+ "node_modules/@types/estree-jsx": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz",
+ "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.25",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz",
+ "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "^1"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.19.9",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.9.tgz",
+ "integrity": "sha512-QP2ESEe/ImWY0HDwNAnK9PvEffUyhLTnWkk7KXzHfyeWAnlrDe1fN77bXl6ia8KT3wPlmA7t9/VPRpnf4Ex9sg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/hast": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz",
+ "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/js-yaml": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
+ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/linkify-it": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
+ "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
+ "license": "MIT"
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.17.24",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz",
+ "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/lodash-es": {
+ "version": "4.17.12",
+ "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
+ "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/lodash": "*"
+ }
+ },
+ "node_modules/@types/markdown-it": {
+ "version": "14.1.2",
+ "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
+ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/linkify-it": "^5",
+ "@types/mdurl": "^2"
+ }
+ },
+ "node_modules/@types/mdast": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
+ "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "*"
+ }
+ },
+ "node_modules/@types/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/ms": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "26.1.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz",
+ "integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~8.3.0"
+ }
+ },
+ "node_modules/@types/parse-json": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/prismjs": {
+ "version": "1.26.6",
+ "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz",
+ "integrity": "sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/qs": {
+ "version": "6.15.1",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz",
+ "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.17",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
+ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.3",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
+ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
+ "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "<1"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/send": {
+ "version": "0.17.6",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
+ "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
+ "integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/unist": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
+ "license": "MIT"
+ },
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz",
+ "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.65.0",
+ "@typescript-eslint/type-utils": "8.65.0",
+ "@typescript-eslint/utils": "8.65.0",
+ "@typescript-eslint/visitor-keys": "8.65.0",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.65.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
+ "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz",
+ "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.65.0",
+ "@typescript-eslint/types": "8.65.0",
+ "@typescript-eslint/typescript-estree": "8.65.0",
+ "@typescript-eslint/visitor-keys": "8.65.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz",
+ "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.65.0",
+ "@typescript-eslint/types": "^8.65.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz",
+ "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.65.0",
+ "@typescript-eslint/visitor-keys": "8.65.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz",
+ "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz",
+ "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.65.0",
+ "@typescript-eslint/typescript-estree": "8.65.0",
+ "@typescript-eslint/utils": "8.65.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz",
+ "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz",
+ "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.65.0",
+ "@typescript-eslint/tsconfig-utils": "8.65.0",
+ "@typescript-eslint/types": "8.65.0",
+ "@typescript-eslint/visitor-keys": "8.65.0",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
+ "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz",
+ "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.65.0",
+ "@typescript-eslint/types": "8.65.0",
+ "@typescript-eslint/typescript-estree": "8.65.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz",
+ "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.65.0",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz",
+ "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==",
+ "license": "ISC"
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+ "@rolldown/pluginutils": "1.0.0-beta.27",
+ "@types/babel__core": "^7.20.5",
+ "react-refresh": "^0.17.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "peerDependencies": {
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ }
+ },
+ "node_modules/@vitest/expect": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz",
+ "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.1.9",
+ "@vitest/utils": "2.1.9",
+ "chai": "^5.1.2",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/runner": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz",
+ "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "2.1.9",
+ "pathe": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/snapshot": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz",
+ "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "magic-string": "^0.30.12",
+ "pathe": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz",
+ "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^3.0.2"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@vitest/utils": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz",
+ "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "loupe": "^3.1.2",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.17.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
+ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
+ "devOptional": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-draft-04": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz",
+ "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^8.5.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
+ "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats-draft2019": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats-draft2019/-/ajv-formats-draft2019-1.6.1.tgz",
+ "integrity": "sha512-JQPvavpkWDvIsBp2Z33UkYCtXCSpW4HD3tAZ+oL4iEFOk9obQZffx0yANwECt6vzr6ET+7HN5czRyqXbnq/u0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.1.1",
+ "schemes": "^1.4.0",
+ "smtp-address-parser": "^1.0.3",
+ "uri-js": "^4.4.1"
+ },
+ "peerDependencies": {
+ "ajv": "*"
+ }
+ },
+ "node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "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/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?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==",
+ "license": "Python-2.0"
+ },
+ "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/autoprefixer": {
+ "version": "10.5.4",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz",
+ "integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.28.6",
+ "caniuse-lite": "^1.0.30001806",
+ "fraction.js": "^5.3.4",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/babel-plugin-macros": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
+ "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "cosmiconfig": "^7.0.0",
+ "resolve": "^1.19.0"
+ },
+ "engines": {
+ "node": ">=10",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/babel-plugin-macros/node_modules/cosmiconfig": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+ "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-json": "^4.0.0",
+ "import-fresh": "^3.2.1",
+ "parse-json": "^5.0.0",
+ "path-type": "^4.0.0",
+ "yaml": "^1.10.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/bail": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/baseline-browser-mapping": {
+ "version": "2.10.44",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.44.tgz",
+ "integrity": "sha512-T3ghW+sl/ZJ8w1v/yQx3qvJ9040DWoLBz8JT/CILbAKcFyG9b2MRe75v6W5uXjv6uH1lumK2Kv46y2zSkcej0Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.16",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
+ "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.6",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.6.tgz",
+ "integrity": "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.10.42",
+ "caniuse-lite": "^1.0.30001803",
+ "electron-to-chromium": "^1.5.389",
+ "node-releases": "^2.0.51",
+ "update-browserslist-db": "^1.2.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "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/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001806",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
+ "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/ccount": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/character-entities": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
+ "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-html4": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
+ "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-entities-legacy": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
+ "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/character-reference-invalid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
+ "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/cli": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+ "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==",
+ "license": "MIT",
+ "dependencies": {
+ "exit": "0.1.2",
+ "glob": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=0.2.5"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/codemirror": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
+ "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
+ "license": "MIT",
+ "dependencies": {
+ "@codemirror/autocomplete": "^6.0.0",
+ "@codemirror/commands": "^6.0.0",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/lint": "^6.0.0",
+ "@codemirror/search": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.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==",
+ "dev": true,
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/comma-separated-tokens": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
+ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
+ "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"
+ },
+ "node_modules/concurrently": {
+ "version": "9.2.4",
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.4.tgz",
+ "integrity": "sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "4.1.2",
+ "rxjs": "7.8.2",
+ "shell-quote": "1.9.0",
+ "supports-color": "8.1.1",
+ "tree-kill": "1.2.2",
+ "yargs": "17.7.2"
+ },
+ "bin": {
+ "conc": "dist/bin/concurrently.js",
+ "concurrently": "dist/bin/concurrently.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
+ }
+ },
+ "node_modules/console-browserify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+ "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==",
+ "dependencies": {
+ "date-now": "^0.1.4"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
+ "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "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/cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/crelt": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.7.tgz",
+ "integrity": "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==",
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/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==",
+ "dev": true,
+ "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-select/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==",
+ "dev": true,
+ "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/css-select/node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/css-select/node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/css-select/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==",
+ "dev": true,
+ "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/css-select/node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+ "license": "MIT"
+ },
+ "node_modules/date-now": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+ "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw=="
+ },
+ "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/decode-named-character-reference": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
+ "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/devlop": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
+ "license": "MIT",
+ "dependencies": {
+ "dequal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/diff": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
+ "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/discontinuous-range": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
+ "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==",
+ "license": "MIT"
+ },
+ "node_modules/dom-serializer": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+ "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "entities": "^2.0.0"
+ }
+ },
+ "node_modules/dom-serializer/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/dom-serializer/node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+ "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==",
+ "dependencies": {
+ "domelementtype": "1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==",
+ "dependencies": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "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/electron-to-chromium": {
+ "version": "1.5.394",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.394.tgz",
+ "integrity": "sha512-Wmt2Gm0o8JWBuGgmc4XZ0u9s1RaCRqhxP47phplmfg04+qypTUurpeJGP45A7Fhv7jdrrVH44PLlR9qXo37cVQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.24.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz",
+ "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+ "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==",
+ "license": "BSD-like"
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "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",
+ "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/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "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/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "9.39.5",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz",
+ "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.1",
+ "@eslint/config-array": "^0.21.2",
+ "@eslint/config-helpers": "^0.4.2",
+ "@eslint/core": "^0.17.0",
+ "@eslint/eslintrc": "^3.3.6",
+ "@eslint/js": "9.39.5",
+ "@eslint/plugin-kit": "^0.4.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^8.4.0",
+ "eslint-visitor-keys": "^4.2.1",
+ "espree": "^10.4.0",
+ "esquery": "^1.5.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz",
+ "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.4.26",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.26.tgz",
+ "integrity": "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "eslint": ">=8.40"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/eslint/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/espree": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.2.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-util-is-identifier-name": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
+ "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/expect-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+ "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "license": "MIT"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
+ "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
+ "license": "MIT"
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fraction.js": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
+ "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fuse.js": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.5.0.tgz",
+ "integrity": "sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/krisk"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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-own-enumerable-property-symbols": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+ "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
+ "license": "ISC"
+ },
+ "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/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/globals": {
+ "version": "15.15.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
+ "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "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/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-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/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/hast-util-to-jsx-runtime": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
+ "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/unist": "^3.0.0",
+ "comma-separated-tokens": "^2.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "hast-util-whitespace": "^3.0.0",
+ "mdast-util-mdx-expression": "^2.0.0",
+ "mdast-util-mdx-jsx": "^3.0.0",
+ "mdast-util-mdxjs-esm": "^2.0.0",
+ "property-information": "^7.0.0",
+ "space-separated-tokens": "^2.0.0",
+ "style-to-js": "^1.0.0",
+ "unist-util-position": "^5.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hast-util-whitespace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/html-url-attributes": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
+ "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+ "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "1",
+ "domhandler": "2.3",
+ "domutils": "1.5",
+ "entities": "1.0",
+ "readable-stream": "1.1"
+ }
+ },
+ "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/immer": {
+ "version": "11.1.15",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.15.tgz",
+ "integrity": "sha512-VrNANlmnWQnh5COXIIOQXM9oOJw7naGKlBT74ZOOR6lpVXc3gFEu9FJLDFcpCJ2j+NWr8TIwtWD//T6ZX6TKiQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/inline-style-parser": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
+ "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==",
+ "license": "MIT"
+ },
+ "node_modules/is-alphabetical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
+ "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-alphanumerical": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
+ "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
+ "license": "MIT",
+ "dependencies": {
+ "is-alphabetical": "^2.0.0",
+ "is-decimal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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"
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.2",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
+ "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-decimal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
+ "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-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==",
+ "dev": true,
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-hexadecimal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
+ "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
+ "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.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-regexp": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+ "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/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": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz",
+ "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==",
+ "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/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jshint": {
+ "version": "2.13.6",
+ "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.6.tgz",
+ "integrity": "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cli": "~1.0.0",
+ "console-browserify": "1.1.x",
+ "exit": "0.1.x",
+ "htmlparser2": "3.8.x",
+ "lodash": "~4.17.21",
+ "minimatch": "~3.0.2",
+ "strip-json-comments": "1.0.x"
+ },
+ "bin": {
+ "jshint": "bin/jshint"
+ }
+ },
+ "node_modules/jshint/node_modules/minimatch": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
+ "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/jshint/node_modules/strip-json-comments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+ "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==",
+ "license": "MIT",
+ "bin": {
+ "strip-json-comments": "cli.js"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
+ },
+ "node_modules/linkify-it": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz",
+ "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^2.0.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash-es": {
+ "version": "4.17.23",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz",
+ "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/longest-streak": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
+ "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "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": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "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/markdown-it": {
+ "version": "14.3.0",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz",
+ "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/markdown-it"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "^4.5.0",
+ "linkify-it": "^5.0.2",
+ "mdurl": "^2.0.0",
+ "punycode.js": "^2.3.1",
+ "uc.micro": "^2.1.0"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.mjs"
+ }
+ },
+ "node_modules/markdown-it/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/markdown-table": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz",
+ "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/mdast-util-find-and-replace": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz",
+ "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "escape-string-regexp": "^5.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mdast-util-from-markdown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
+ "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark": "^4.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unist-util-stringify-position": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz",
+ "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-gfm-autolink-literal": "^2.0.0",
+ "mdast-util-gfm-footnote": "^2.0.0",
+ "mdast-util-gfm-strikethrough": "^2.0.0",
+ "mdast-util-gfm-table": "^2.0.0",
+ "mdast-util-gfm-task-list-item": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-autolink-literal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz",
+ "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-find-and-replace": "^3.0.0",
+ "micromark-util-character": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-strikethrough": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz",
+ "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz",
+ "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "markdown-table": "^3.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-gfm-task-list-item": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz",
+ "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-mdx-expression": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
+ "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-mdx-jsx": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz",
+ "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "ccount": "^2.0.0",
+ "devlop": "^1.1.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "parse-entities": "^4.0.0",
+ "stringify-entities": "^4.0.0",
+ "unist-util-stringify-position": "^4.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-mdxjs-esm": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
+ "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-phrasing": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
+ "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "unist-util-is": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-hast": {
+ "version": "13.2.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
+ "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "@ungap/structured-clone": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "trim-lines": "^3.0.0",
+ "unist-util-position": "^5.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-markdown": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
+ "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "@types/unist": "^3.0.0",
+ "longest-streak": "^3.0.0",
+ "mdast-util-phrasing": "^4.0.0",
+ "mdast-util-to-string": "^4.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-decode-string": "^2.0.0",
+ "unist-util-visit": "^5.0.0",
+ "zwitch": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdast-util-to-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
+ "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/mdurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+ "license": "MIT"
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromark": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
+ "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@types/debug": "^4.0.0",
+ "debug": "^4.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-core-commonmark": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
+ "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "devlop": "^1.0.0",
+ "micromark-factory-destination": "^2.0.0",
+ "micromark-factory-label": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-factory-title": "^2.0.0",
+ "micromark-factory-whitespace": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-html-tag-name": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-subtokenize": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-extension-gfm": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz",
+ "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-extension-gfm-autolink-literal": "^2.0.0",
+ "micromark-extension-gfm-footnote": "^2.0.0",
+ "micromark-extension-gfm-strikethrough": "^2.0.0",
+ "micromark-extension-gfm-table": "^2.0.0",
+ "micromark-extension-gfm-tagfilter": "^2.0.0",
+ "micromark-extension-gfm-task-list-item": "^2.0.0",
+ "micromark-util-combine-extensions": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-autolink-literal": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz",
+ "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-footnote": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz",
+ "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-core-commonmark": "^2.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-normalize-identifier": "^2.0.0",
+ "micromark-util-sanitize-uri": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-strikethrough": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz",
+ "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-classify-character": "^2.0.0",
+ "micromark-util-resolve-all": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-table": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz",
+ "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-tagfilter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz",
+ "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==",
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-extension-gfm-task-list-item": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz",
+ "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==",
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/micromark-factory-destination": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
+ "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-label": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
+ "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-space": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
+ "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-title": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
+ "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-factory-whitespace": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
+ "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-factory-space": "^2.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-character": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-chunked": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
+ "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-classify-character": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
+ "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-combine-extensions": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
+ "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-numeric-character-reference": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
+ "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-decode-string": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
+ "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decode-named-character-reference": "^1.0.0",
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-encode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-html-tag-name": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
+ "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-normalize-identifier": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
+ "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-resolve-all": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
+ "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-sanitize-uri": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "micromark-util-character": "^2.0.0",
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-subtokenize": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
+ "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "devlop": "^1.0.0",
+ "micromark-util-chunked": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0",
+ "micromark-util-types": "^2.0.0"
+ }
+ },
+ "node_modules/micromark-util-symbol": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
+ "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromark-util-types": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
+ "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/unifiedjs"
+ },
+ {
+ "type": "OpenCollective",
+ "url": "https://opencollective.com/unified"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
+ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/monaco-editor": {
+ "version": "0.53.0",
+ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.53.0.tgz",
+ "integrity": "sha512-0WNThgC6CMWNXXBxTbaYYcunj08iB5rnx4/G56UOPeL9UVIUGGHA1GR0EWIh9Ebabj7NpCRawQ5b0hfN1jQmYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/trusted-types": "^1.0.6"
+ }
+ },
+ "node_modules/moo": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz",
+ "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
+ "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
+ "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/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nearley": {
+ "version": "2.20.1",
+ "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz",
+ "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^2.19.0",
+ "moo": "^0.5.0",
+ "railroad-diagrams": "^1.0.0",
+ "randexp": "0.4.6"
+ },
+ "bin": {
+ "nearley-railroad": "bin/nearley-railroad.js",
+ "nearley-test": "bin/nearley-test.js",
+ "nearley-unparse": "bin/nearley-unparse.js",
+ "nearleyc": "bin/nearleyc.js"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://nearley.js.org/#give-to-nearley"
+ }
+ },
+ "node_modules/node-html-parser": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-8.0.4.tgz",
+ "integrity": "sha512-w2YxujN/TqrSIWGVNW/fVgKKfAyQeHMXCvnKZI0owLnfP0tfjdLecUoy9zhOMZGoEFk6eP5qSDyvUarjPl3bwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "css-select": "^5.1.0",
+ "entities": "^8.0.0"
+ }
+ },
+ "node_modules/node-html-parser/node_modules/entities": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz",
+ "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.51",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz",
+ "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "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==",
+ "dev": true,
+ "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==",
+ "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/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/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==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-entities": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
+ "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^2.0.0",
+ "character-entities-legacy": "^3.0.0",
+ "character-reference-invalid": "^2.0.0",
+ "decode-named-character-reference": "^1.0.0",
+ "is-alphanumerical": "^2.0.0",
+ "is-decimal": "^2.0.0",
+ "is-hexadecimal": "^2.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/parse-entities/node_modules/@types/unist": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
+ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
+ "license": "MIT"
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "license": "MIT"
+ },
+ "node_modules/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==",
+ "dev": true,
+ "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-scurry/node_modules/lru-cache": {
+ "version": "11.5.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
+ "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "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/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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.1.tgz",
+ "integrity": "sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.61.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.61.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.1.tgz",
+ "integrity": "sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.21",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.21.tgz",
+ "integrity": "sha512-v4sDNP3fdNiWMfabO7OwOQdOX8TiQSztKyT1Wj0w+j7LDallJThJRBBBmzVGyYj0crMh7jlV4zepPkiNu9UwDQ==",
+ "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.16",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.0.10",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
+ "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prismjs": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
+ "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/property-information": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz",
+ "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/punycode.js": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+ "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz",
+ "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/quickjs-emscripten": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/quickjs-emscripten/-/quickjs-emscripten-0.31.0.tgz",
+ "integrity": "sha512-K7Yt78aRPLjPcqv3fIuLW1jW3pvwO21B9pmFOolsjM/57ZhdVXBr51GqJpalgBlkPu9foAvhEAuuQPnvIGvLvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-wasmfile-debug-asyncify": "0.31.0",
+ "@jitl/quickjs-wasmfile-debug-sync": "0.31.0",
+ "@jitl/quickjs-wasmfile-release-asyncify": "0.31.0",
+ "@jitl/quickjs-wasmfile-release-sync": "0.31.0",
+ "quickjs-emscripten-core": "0.31.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/quickjs-emscripten-core": {
+ "version": "0.31.0",
+ "resolved": "https://registry.npmjs.org/quickjs-emscripten-core/-/quickjs-emscripten-core-0.31.0.tgz",
+ "integrity": "sha512-oQz8p0SiKDBc1TC7ZBK2fr0GoSHZKA0jZIeXxsnCyCs4y32FStzCW4d1h6E1sE0uHDMbGITbk2zhNaytaoJwXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jitl/quickjs-ffi-types": "0.31.0"
+ }
+ },
+ "node_modules/railroad-diagrams": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
+ "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==",
+ "license": "CC0-1.0"
+ },
+ "node_modules/randexp": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
+ "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "discontinuous-range": "1.0.0",
+ "ret": "~0.1.10"
+ },
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/react": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.2"
+ },
+ "peerDependencies": {
+ "react": "^18.3.1"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
+ "node_modules/react-markdown": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
+ "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "devlop": "^1.0.0",
+ "hast-util-to-jsx-runtime": "^2.0.0",
+ "html-url-attributes": "^3.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-rehype": "^11.0.0",
+ "unified": "^11.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18",
+ "react": ">=18"
+ }
+ },
+ "node_modules/react-redux": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz",
+ "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-refresh": {
+ "version": "0.17.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-router": {
+ "version": "7.18.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.1.tgz",
+ "integrity": "sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==",
+ "license": "MIT",
+ "dependencies": {
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.18.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.1.tgz",
+ "integrity": "sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.18.1"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
+ "node_modules/remark-gfm": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+ "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-gfm": "^3.0.0",
+ "micromark-extension-gfm": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-stringify": "^11.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-parse": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
+ "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-from-markdown": "^2.0.0",
+ "micromark-util-types": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-rehype": {
+ "version": "11.1.2",
+ "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
+ "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hast": "^3.0.0",
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-hast": "^13.0.0",
+ "unified": "^11.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/remark-stringify": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
+ "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mdast": "^4.0.0",
+ "mdast-util-to-markdown": "^2.0.0",
+ "unified": "^11.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/reselect": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz",
+ "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==",
+ "license": "MIT"
+ },
+ "node_modules/resolve": {
+ "version": "1.22.12",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
+ "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "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/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
+ "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "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/rimraf/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.62.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz",
+ "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==",
+ "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.2",
+ "@rollup/rollup-android-arm64": "4.62.2",
+ "@rollup/rollup-darwin-arm64": "4.62.2",
+ "@rollup/rollup-darwin-x64": "4.62.2",
+ "@rollup/rollup-freebsd-arm64": "4.62.2",
+ "@rollup/rollup-freebsd-x64": "4.62.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.62.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.62.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.62.2",
+ "@rollup/rollup-linux-arm64-musl": "4.62.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.62.2",
+ "@rollup/rollup-linux-loong64-musl": "4.62.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.62.2",
+ "@rollup/rollup-linux-ppc64-musl": "4.62.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.62.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.62.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.62.2",
+ "@rollup/rollup-linux-x64-gnu": "4.62.2",
+ "@rollup/rollup-linux-x64-musl": "4.62.2",
+ "@rollup/rollup-openbsd-x64": "4.62.2",
+ "@rollup/rollup-openharmony-arm64": "4.62.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.62.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.62.2",
+ "@rollup/rollup-win32-x64-gnu": "4.62.2",
+ "@rollup/rollup-win32-x64-msvc": "4.62.2",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.23.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "node_modules/schemes": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/schemes/-/schemes-1.4.0.tgz",
+ "integrity": "sha512-ImFy9FbCsQlVgnE3TCWmLPCFnVzx0lHL/l+umHplDqAKd0dzFpnS6lFZIpagBlYhKwzVmlV36ec0Y1XTu8JBAQ==",
+ "license": "MIT",
+ "dependencies": {
+ "extend": "^3.0.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
+ "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
+ "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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz",
+ "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
+ "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4",
+ "side-channel-list": "^1.0.1",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/siginfo": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+ "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/smtp-address-parser": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.1.0.tgz",
+ "integrity": "sha512-Gz11jbNU0plrReU9Sj7fmshSBxxJ9ShdD2q4ktHIHo/rpTH6lFyQoYHYKINPJtPe8aHFnsbtW46Ls0tCCBsIZg==",
+ "license": "MIT",
+ "dependencies": {
+ "nearley": "^2.20.1"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/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==",
+ "devOptional": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/space-separated-tokens": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
+ "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "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/state-local": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/state-local/-/state-local-1.0.7.tgz",
+ "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==",
+ "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/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
+ "license": "MIT"
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "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/stringify-entities": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
+ "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
+ "license": "MIT",
+ "dependencies": {
+ "character-entities-html4": "^2.0.0",
+ "character-entities-legacy": "^3.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/stringify-object": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+ "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "get-own-enumerable-property-symbols": "^3.0.0",
+ "is-obj": "^1.0.1",
+ "is-regexp": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/style-mod": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
+ "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
+ "license": "MIT"
+ },
+ "node_modules/style-to-js": {
+ "version": "1.1.21",
+ "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz",
+ "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "style-to-object": "1.0.14"
+ }
+ },
+ "node_modules/style-to-object": {
+ "version": "1.0.14",
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz",
+ "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==",
+ "license": "MIT",
+ "dependencies": {
+ "inline-style-parser": "0.2.7"
+ }
+ },
+ "node_modules/stylis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
+ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
+ "license": "MIT"
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/tagged-tag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
+ "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.49.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz",
+ "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==",
+ "devOptional": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "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": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tippy.js": {
+ "version": "6.3.7",
+ "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
+ "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@popperjs/core": "^2.9.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/trim-lines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
+ "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/trough": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
+ "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "devOptional": true,
+ "license": "0BSD"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.2.0.tgz",
+ "integrity": "sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA==",
+ "license": "(MIT OR CC0-1.0)",
+ "dependencies": {
+ "tagged-tag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
+ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.65.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.65.0.tgz",
+ "integrity": "sha512-/ggrHAwyjENDusvyxbuqxAC2dTnZg/Z8F+fgQtYIz+L6n/9HfSlEZcFGV/NsMNa6CkGk0xUjUAFwC0vHOflvIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.65.0",
+ "@typescript-eslint/parser": "8.65.0",
+ "@typescript-eslint/typescript-estree": "8.65.0",
+ "@typescript-eslint/utils": "8.65.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+ "license": "MIT"
+ },
+ "node_modules/undici-types": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
+ "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/unified": {
+ "version": "11.0.5",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
+ "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "bail": "^2.0.0",
+ "devlop": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-plain-obj": "^4.0.0",
+ "trough": "^2.0.0",
+ "vfile": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-is": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
+ "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-position": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
+ "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-stringify-position": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
+ "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz",
+ "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0",
+ "unist-util-visit-parents": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/unist-util-visit-parents": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz",
+ "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-is": "^6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vfile": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
+ "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "vfile-message": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vfile-message": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/unist": "^3.0.0",
+ "unist-util-stringify-position": "^4.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
+ "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
+ "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": "2.1.9",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz",
+ "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.3.7",
+ "es-module-lexer": "^1.5.4",
+ "pathe": "^1.1.2",
+ "vite": "^5.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite-node/node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/vite-node/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/vite-node/node_modules/vite": {
+ "version": "5.4.21",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.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",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/vite/node_modules/picomatch": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/vitest": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz",
+ "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "2.1.9",
+ "@vitest/mocker": "2.1.9",
+ "@vitest/pretty-format": "^2.1.9",
+ "@vitest/runner": "2.1.9",
+ "@vitest/snapshot": "2.1.9",
+ "@vitest/spy": "2.1.9",
+ "@vitest/utils": "2.1.9",
+ "chai": "^5.1.2",
+ "debug": "^4.3.7",
+ "expect-type": "^1.1.0",
+ "magic-string": "^0.30.12",
+ "pathe": "^1.1.2",
+ "std-env": "^3.8.0",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^0.3.1",
+ "tinypool": "^1.0.1",
+ "tinyrainbow": "^1.2.0",
+ "vite": "^5.0.0",
+ "vite-node": "2.1.9",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "@vitest/browser": "2.1.9",
+ "@vitest/ui": "2.1.9",
+ "happy-dom": "*",
+ "jsdom": "*"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/aix-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/android-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/android-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/android-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/darwin-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-arm": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-loong64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-s390x": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/linux-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/sunos-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/win32-arm64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/win32-ia32": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@esbuild/win32-x64": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vitest/node_modules/@vitest/mocker": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz",
+ "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.1.9",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.12"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitest/node_modules/esbuild": {
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
+ }
+ },
+ "node_modules/vitest/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/vitest/node_modules/vite": {
+ "version": "5.4.21",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || >=20.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",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/w3c-keyname": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
+ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+ "license": "MIT"
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/why-is-node-running": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+ "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "siginfo": "^2.0.0",
+ "stackback": "0.0.2"
+ },
+ "bin": {
+ "why-is-node-running": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/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==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
+ "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zwitch": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
+ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "packages/oc-docs": {
+ "name": "@opencollection/docs",
+ "version": "0.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "@emotion/css": "^11.13.5",
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@faker-js/faker": "^9.7.0",
+ "@mintlify/httpsnippet": "^1.0.10",
+ "@monaco-editor/react": "^4.7.0",
+ "@opencollection/types": "0.11.0",
+ "@prantlf/jsonlint": "^16.0.0",
+ "@reduxjs/toolkit": "^2.10.1",
+ "@tabler/icons": "^1.46.0",
+ "@tailwindcss/vite": "^4.0.9",
+ "@tippyjs/react": "^4.2.6",
+ "@types/js-yaml": "^4.0.9",
+ "@types/markdown-it": "^14.1.2",
+ "@types/prismjs": "^1.26.5",
+ "ajv": "^8.12.0",
+ "codemirror": "^6.0.2",
+ "fuse.js": "^7.5.0",
+ "js-yaml": "^4.1.0",
+ "jshint": "^2.13.6",
+ "markdown-it": "^14.1.0",
+ "monaco-editor": "^0.53.0",
+ "nanoid": "~3.3.11",
+ "prismjs": "^1.29.0",
+ "quickjs-emscripten": "~0.31.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-markdown": "^10.0.0",
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.3.0",
+ "remark-gfm": "^4.0.1",
+ "strip-json-comments": "^3.1.1"
+ },
+ "devDependencies": {
+ "@emotion/babel-plugin": "~11.13.5",
+ "@eslint/js": "^9.21.0",
+ "@playwright/test": "^1.52.0",
+ "@tailwindcss/postcss": "^4.1.13",
+ "@tailwindcss/typography": "^0.5.10",
+ "@types/express": "^4.17.21",
+ "@types/lodash-es": "~4.17.12",
+ "@types/prismjs": "^1.26.3",
+ "@types/react": "^19.0.10",
+ "@types/react-dom": "^19.0.4",
+ "@types/uuid": "^10.0.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "autoprefixer": "^10.4.20",
+ "chai": "~5.3.3",
+ "concurrently": "^9.1.2",
+ "eslint": "^9.21.0",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "eslint-plugin-react-refresh": "^0.4.19",
+ "globals": "^15.15.0",
+ "lodash-es": "~4.17.21",
+ "node-html-parser": "^8.0.4",
+ "postcss": "^8.5.3",
+ "rimraf": "^6.0.1",
+ "rollup": "^4.50.2",
+ "tailwindcss": "^4.0.9",
+ "terser": "^5.44.0",
+ "typescript": "~5.7.2",
+ "typescript-eslint": "^8.24.1",
+ "vite": "^6.2.0",
+ "vitest": "^2.1.8"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..bcd52578
--- /dev/null
+++ b/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "opencollection",
+ "private": true,
+ "workspaces": [
+ "packages/oc-docs"
+ ],
+ "homepage": "https://www.opencollection.com"
+}
diff --git a/packages/oc-docs/.gitignore b/packages/oc-docs/.gitignore
new file mode 100644
index 00000000..66582f2c
--- /dev/null
+++ b/packages/oc-docs/.gitignore
@@ -0,0 +1,5 @@
+src/scripting/sandbox/quickjs/bundled-libraries.iife.js
+
+# Playwright
+playwright-report/
+test-results/
\ No newline at end of file
diff --git a/packages/oc-docs/e2e/README.md b/packages/oc-docs/e2e/README.md
new file mode 100644
index 00000000..24990aff
--- /dev/null
+++ b/packages/oc-docs/e2e/README.md
@@ -0,0 +1,143 @@
+# End-to-end tests
+
+Playwright tests for the docs app. They open the app in a real browser and check that
+what a person sees on the page is correct.
+
+Two rules shape every test here:
+
+1. **Tests read like documentation.** The title says, in plain English, what the page
+ does; the body confirms it.
+2. **Elements are located by `data-testid`.** The app sets a stable test id on each
+ meaningful element (via the components' `testId` props); tests target those, never
+ styling classes. Rendered-Markdown internals — which have no test id — are matched
+ by role/tag within their test-id'd container.
+
+## What's tested
+
+| Area | Spec |
+|------|------|
+| Collection Overview — version/name, stat counts, environments, configuration | `tests/overview/overview.spec.ts` |
+| Overview documentation — rendered Markdown | `tests/overview/overview-documentation.spec.ts` |
+| Request page — details (breadcrumb, title, method/URL, description, params, auth, code snippet) | `tests/request/request-details.spec.ts` |
+| Request page — Examples | `tests/request/request-examples.spec.ts` |
+| Request page — Execution Context (scripts, variables, asserts, tests) | `tests/request/request-execution-context.spec.ts` |
+| Script page — title, breadcrumb, source code | `tests/script/script.spec.ts` |
+| Light/dark theme switch | `tests/theming/theme-toggle.spec.ts` |
+
+## Running the tests
+
+```sh
+npm run test:e2e # run headless
+npm run test:e2e:ui # run in Playwright's interactive UI
+```
+
+Playwright starts the dev server for you (see `webServer` in `playwright.config.ts`).
+
+## Folder layout
+
+```
+e2e/
+├── tests/ # the tests, grouped by feature
+│ ├── overview/ # Collection Overview page
+│ │ ├── overview.spec.ts
+│ │ └── overview-documentation.spec.ts
+│ ├── request/ # Request page
+│ │ ├── request-details.spec.ts
+│ │ ├── request-examples.spec.ts
+│ │ └── request-execution-context.spec.ts
+│ ├── script/ # Script page
+│ │ └── script.spec.ts
+│ └── theming/ # light/dark theme switch
+│ └── theme-toggle.spec.ts
+├── pages/ # one "page object" per screen
+│ ├── base.page.ts # shared navigation (goto, reload)
+│ ├── overview.page.ts # OverviewPage — composes its overview/ sections
+│ ├── request.page.ts # RequestPage — composes its request/ sections
+│ └── script.page.ts # ScriptPage — breadcrumb, title, source code
+├── components/ # reusable pieces
+│ ├── base.component.ts # shared base — every component has a `root`
+│ ├── markdown.component.ts # any block of rendered Markdown
+│ ├── secret-value.component.ts # a masked value with a reveal toggle
+│ ├── theme-toggle.component.ts # the light/dark switch
+│ ├── sidebar.component.ts # the navigation tree (open a request/script)
+│ ├── breadcrumb.component.ts # the "folder › folder › page" trail
+│ ├── overview/ # sections specific to the Overview page
+│ │ ├── header-section.component.ts
+│ │ ├── stats-section.component.ts
+│ │ ├── environments-section.component.ts
+│ │ └── configuration-section.component.ts
+│ ├── request/ # sections specific to the Request page
+│ │ ├── url-bar.component.ts
+│ │ ├── code-snippet.component.ts
+│ │ ├── examples.component.ts
+│ │ └── execution-context.component.ts
+│ └── script/ # sections specific to the Script page
+│ └── script-content.component.ts
+├── playwright/ # the test harness
+│ ├── pages.fixture.ts # defines the fixtures
+│ └── index.ts # merges them; the single import for specs
+├── config/app.config.ts # base URL + how to start the app
+└── tsconfig.json # TypeScript settings for this folder
+```
+
+The Request and Script pages have no URL of their own, so their page objects reach
+them by navigating the **sidebar** — `requestPage.open(['billing', 'customers', 'Get
+All Customers'])` clicks down the folder trail and waits for the page to render. The
+reusable `sidebar` and `breadcrumb` components are shared by both pages.
+
+## The three building blocks
+
+**Page objects** (`pages/`) describe a whole screen. They own navigation (`goto`) and
+compose the components a test cares about — the `OverviewPage`, for instance, wires up
+the header, stats, environments and configuration sections.
+
+**Components** (`components/`) are the reusable building blocks. Common controls used
+across pages — the Markdown renderer, the theme switch — live at the top level; point
+one at the element it lives in (its `root`) and it works anywhere that UI appears.
+**Sections that belong to a single page live in a subfolder named after it** — the
+Overview's header, stats, environments and configuration sections are in
+`components/overview/`. (Its documentation section is just the common `MarkdownComponent`
+scoped to the `overview-markdown-documentation` container.)
+
+**Fixtures** (`playwright/`) hand a test ready-made page objects and common components:
+
+```ts
+test('…', async ({ overviewPage, themeToggle }) => { … });
+```
+
+`pages.fixture.ts` defines them; `index.ts` combines them with Playwright's `mergeTests`
+and is the single place specs import from. To add a page, drop a new `*.fixture.ts` in
+this folder and merge it in `index.ts`.
+
+## Writing a test
+
+Import `test` and `expect` from the `playwright` folder, then pull the page objects and
+components you need off the test callback — no `new`, no setup boilerplate:
+
+```ts
+import { test, expect } from '../../playwright';
+
+test.describe('Collection Overview', () => {
+ test.beforeEach(async ({ overviewPage }) => {
+ await overviewPage.goto();
+ });
+
+ test('shows the collection name in the header', async ({ overviewPage }) => {
+ await expect(overviewPage.header.collectionName).toHaveText('Bruno Testbench');
+ });
+});
+```
+
+Keep the `expect`s in the test. Page objects and sections only expose elements and
+actions — the test decides what to check.
+
+## Imports
+
+Every import is a relative path — there are no path aliases. Specs import from the
+`playwright` barrel; everything else points straight at the file it needs:
+
+```ts
+import { test, expect } from '../../playwright'; // test → harness
+import { OverviewPage } from '../pages/overview.page'; // harness → page
+import { MarkdownComponent } from '../components/markdown.component'; // page → component
+```
diff --git a/packages/oc-docs/e2e/components/base.component.ts b/packages/oc-docs/e2e/components/base.component.ts
new file mode 100644
index 00000000..ccc51a55
--- /dev/null
+++ b/packages/oc-docs/e2e/components/base.component.ts
@@ -0,0 +1,9 @@
+import type { Page, Locator } from '@playwright/test';
+
+export abstract class BaseComponent {
+ readonly root: Locator;
+
+ constructor(protected readonly page: Page, root?: Locator) {
+ this.root = root ?? page.locator(':root');
+ }
+}
diff --git a/packages/oc-docs/e2e/components/breadcrumb.component.ts b/packages/oc-docs/e2e/components/breadcrumb.component.ts
new file mode 100644
index 00000000..8eaa348a
--- /dev/null
+++ b/packages/oc-docs/e2e/components/breadcrumb.component.ts
@@ -0,0 +1,18 @@
+import type { Locator, Page } from '@playwright/test';
+import { BaseComponent } from './base.component';
+
+export class BreadcrumbComponent extends BaseComponent {
+ readonly current: Locator;
+ readonly segments: Locator;
+
+ constructor(page: Page, testId: string) {
+ super(page, page.getByTestId(testId));
+
+ this.current = page.getByTestId(`${testId}-current`);
+ this.segments = page.getByTestId(`${testId}-segment`);
+ }
+
+ segment(name: string): Locator {
+ return this.segments.filter({ hasText: name });
+ }
+}
diff --git a/packages/oc-docs/e2e/components/code-editor/code-editor.component.ts b/packages/oc-docs/e2e/components/code-editor/code-editor.component.ts
new file mode 100644
index 00000000..f2bb3c53
--- /dev/null
+++ b/packages/oc-docs/e2e/components/code-editor/code-editor.component.ts
@@ -0,0 +1,27 @@
+import type { Locator, Page } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+/**
+ * A Monaco-backed code editor (see `src/ui/CodeEditor`). Only the container carries a test id;
+ * Monaco renders its own DOM, so the editor surface, the text region we click to focus, and the
+ * (portaled) autocomplete popup are matched by Monaco's stable class names and kept out of specs.
+ */
+export class CodeEditorComponent extends BaseComponent {
+ readonly copyButton: Locator;
+ readonly suggestions: Locator;
+ private readonly surface: Locator;
+ private readonly lines: Locator;
+
+ constructor(page: Page, testId: string) {
+ super(page, page.getByTestId(testId));
+ this.copyButton = this.root.getByTestId(`${testId}-copy`);
+ this.surface = this.root.locator('.monaco-editor');
+ this.lines = this.root.locator('.view-lines');
+ this.suggestions = page.locator('.suggest-widget.visible');
+ }
+
+ async focus(): Promise {
+ await this.surface.waitFor({ state: 'visible', timeout: 20000 });
+ await this.lines.click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/collection-settings/collection-settings.component.ts b/packages/oc-docs/e2e/components/collection-settings/collection-settings.component.ts
new file mode 100644
index 00000000..43a5a969
--- /dev/null
+++ b/packages/oc-docs/e2e/components/collection-settings/collection-settings.component.ts
@@ -0,0 +1,42 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class CollectionSettingsComponent extends BaseComponent {
+ readonly view = this.page.getByTestId('playground-view');
+ readonly collectionNode = this.page.getByTestId('sidebar-collection-root');
+ readonly overviewMarkdown = this.view.getByTestId('overview-markdown-documentation');
+ readonly overviewEmpty = this.view.getByTestId('overview-empty');
+ readonly bulkEditToggle = this.view.getByTestId('bulk-edit-toggle');
+ readonly varsTable = this.view.getByTestId('variables-pre-request');
+ readonly authMode = this.view.getByTestId('auth-mode-select');
+
+ tab(id: string): Locator {
+ return this.view.getByTestId(`collection-settings-tabs-tab-${id}`);
+ }
+
+ scriptTab(id: string): Locator {
+ return this.view.getByTestId(`scripts-tabs-tab-${id}`);
+ }
+
+ authField(name: string): Locator {
+ return this.view.getByTestId(`auth-${name}`);
+ }
+
+ /** An option inside the (opened) auth-mode dropdown. */
+ authModeOption(value: string): Locator {
+ return this.page.getByTestId(`auth-mode-select-${value}`);
+ }
+
+ async open(): Promise {
+ await this.collectionNode.click();
+ }
+
+ async openTab(id: string): Promise {
+ await this.tab(id).click();
+ }
+
+ async selectAuthMode(value: string): Promise {
+ await this.authMode.click();
+ await this.page.getByTestId(`auth-mode-select-${value}`).click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/environments/env-editor.component.ts b/packages/oc-docs/e2e/components/environments/env-editor.component.ts
new file mode 100644
index 00000000..fedb0222
--- /dev/null
+++ b/packages/oc-docs/e2e/components/environments/env-editor.component.ts
@@ -0,0 +1,7 @@
+import { BaseComponent } from '../base.component';
+
+export class EnvEditorComponent extends BaseComponent {
+ readonly cards = this.page.getByTestId('env-var-cards');
+ readonly nameInputs = this.cards.getByPlaceholder('Name');
+ readonly valueInputs = this.cards.getByPlaceholder('Value');
+}
diff --git a/packages/oc-docs/e2e/components/environments/environment-table.component.ts b/packages/oc-docs/e2e/components/environments/environment-table.component.ts
new file mode 100644
index 00000000..feb51503
--- /dev/null
+++ b/packages/oc-docs/e2e/components/environments/environment-table.component.ts
@@ -0,0 +1,43 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class EnvironmentTableComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('environment-table');
+ readonly variableRows = this.page.getByTestId('environment-variable-row');
+ readonly secretVariableRows = this.page.getByTestId('environment-secret-variable-row');
+ readonly externalSecretRows = this.page.getByTestId('environment-external-secret-row');
+ readonly variableDescriptions = this.page.getByTestId('environment-variable-row-description');
+ readonly secretVariableDescriptions = this.page.getByTestId('environment-secret-variable-row-description');
+
+ columnHeader(key: string): Locator {
+ return this.root.getByTestId(`table-header-${key}`);
+ }
+
+ variableRow(name: string): Locator {
+ return this.variableRows.filter({ hasText: name });
+ }
+
+ secretVariableRow(name: string): Locator {
+ return this.secretVariableRows.filter({ hasText: name });
+ }
+
+ externalSecretRow(name: string): Locator {
+ return this.externalSecretRows.filter({ hasText: name });
+ }
+
+ valueOf(name: string): Locator {
+ return this.variableRow(name).getByTestId('table-cell-value');
+ }
+
+ dataTypeOf(name: string): Locator {
+ return this.variableRow(name).getByTestId('table-cell-type');
+ }
+
+ secretValueOf(name: string): Locator {
+ return this.secretVariableRow(name).getByTestId('table-cell-value');
+ }
+
+ secretRevealToggleOf(name: string): Locator {
+ return this.secretValueOf(name).getByTestId('environment-secret-value-toggle');
+ }
+}
diff --git a/packages/oc-docs/e2e/components/folder/folder-configuration.component.ts b/packages/oc-docs/e2e/components/folder/folder-configuration.component.ts
new file mode 100644
index 00000000..ed8c0199
--- /dev/null
+++ b/packages/oc-docs/e2e/components/folder/folder-configuration.component.ts
@@ -0,0 +1,10 @@
+import { BaseComponent } from '../base.component';
+
+export class FolderConfigurationComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('folder-config');
+ readonly headers = this.page.getByTestId('folder-config-headers');
+ readonly auth = this.page.getByTestId('folder-config-auth');
+ readonly script = this.page.getByTestId('folder-config-script');
+ readonly vars = this.page.getByTestId('folder-config-vars');
+ readonly tests = this.page.getByTestId('folder-config-tests');
+}
diff --git a/packages/oc-docs/e2e/components/key-value-table/key-value-table.component.ts b/packages/oc-docs/e2e/components/key-value-table/key-value-table.component.ts
new file mode 100644
index 00000000..41b671db
--- /dev/null
+++ b/packages/oc-docs/e2e/components/key-value-table/key-value-table.component.ts
@@ -0,0 +1,22 @@
+import type { Locator, Page } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+/** A KeyValueTable instance (headers, params, variables …). Pass the table's testId to target a specific one. */
+export class KeyValueTableComponent extends BaseComponent {
+ readonly container: Locator;
+ readonly table: Locator;
+ readonly nameInputs: Locator;
+ readonly valueInputs: Locator;
+ readonly cellErrors: Locator;
+ readonly autocomplete: Locator;
+
+ constructor(page: Page, testId = 'key-value-table') {
+ super(page, page.getByTestId(testId));
+ this.container = page.getByTestId(`${testId}-container`);
+ this.table = page.getByTestId(`${testId}-table`);
+ this.nameInputs = page.getByTestId(`${testId}-name-input`);
+ this.valueInputs = page.getByTestId(`${testId}-value-input`);
+ this.cellErrors = page.getByTestId(`${testId}-error`);
+ this.autocomplete = page.getByTestId('variable-autocomplete');
+ }
+}
diff --git a/packages/oc-docs/e2e/components/layout/env-switcher.component.ts b/packages/oc-docs/e2e/components/layout/env-switcher.component.ts
new file mode 100644
index 00000000..355d160e
--- /dev/null
+++ b/packages/oc-docs/e2e/components/layout/env-switcher.component.ts
@@ -0,0 +1,49 @@
+import type { Page, Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+/**
+ * The environment controls in the page header: the show-variables toggle and
+ * the environment switcher. Both are sibling controls in the header's env slot,
+ * so the toggle is found page-wide by its test id and the trigger is scoped to
+ * the switcher root. The menu renders through MenuDropdown (Tippy), portaled to
+ * so it escapes the topbar stacking context and clears the playground
+ * docks, so its menu and options are located page-wide. Parts are found by test
+ * id, never by class.
+ */
+export class EnvSwitcherComponent extends BaseComponent {
+ readonly showVarsToggle = this.page.getByTestId('show-vars-toggle');
+ readonly trigger: Locator;
+ readonly menu: Locator;
+ readonly emptyOption: Locator;
+
+ constructor(
+ page: Page,
+ private readonly base = 'env-switcher'
+ ) {
+ super(page, page.getByTestId(`${base}-root`));
+ this.trigger = this.root.getByTestId(base);
+ this.menu = this.page.getByTestId(`${base}-dropdown`);
+ this.emptyOption = this.option('no-environments');
+ }
+
+ option(name: string): Locator {
+ return this.menu.getByTestId(`${this.base}-${name.toLowerCase()}`);
+ }
+
+ async open(): Promise {
+ await this.trigger.click();
+ }
+
+ async selectEnvironment(name: string): Promise {
+ await this.open();
+ await this.option(name).click();
+ }
+
+ async toggle(): Promise {
+ await this.showVarsToggle.click();
+ }
+
+ async pressKey(key: string): Promise {
+ await this.page.keyboard.press(key);
+ }
+}
diff --git a/packages/oc-docs/e2e/components/layout/page-header.component.ts b/packages/oc-docs/e2e/components/layout/page-header.component.ts
new file mode 100644
index 00000000..971d3905
--- /dev/null
+++ b/packages/oc-docs/e2e/components/layout/page-header.component.ts
@@ -0,0 +1,30 @@
+import type { Page } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+/**
+ * The page header (sticky top navigation bar). A layout component — present on
+ * every screen — so tests get it handed over directly (`pageHeader.brandName`),
+ * the same way the sidebar is.
+ *
+ * Scoped to the `topbar` test id. Exposes the header's own shipped chrome:
+ * brand cluster, the Open-in-Bruno CTA, and the menu (hamburger) trigger.
+ * Parts are found by test id or accessible name, never by class.
+ */
+export class PageHeaderComponent extends BaseComponent {
+ constructor(page: Page) {
+ super(page, page.getByTestId('topbar'));
+ }
+
+ // Brand cluster
+ readonly brand = this.root.getByTestId('brand');
+ readonly brandName = this.root.getByTestId('brand-name');
+ readonly brandVersion = this.root.getByTestId('brand-version');
+ readonly brandInitials = this.root.getByTestId('brand-initials');
+
+ // Open-in-Bruno CTA
+ readonly openInBruno = this.root.getByTestId('open-in-bruno');
+
+ // Sidebar (hamburger) trigger — shown below desktop. The header only renders
+ // the button; the drawer it opens lives elsewhere.
+ readonly menuButton = this.root.getByTestId('topbar-menu');
+}
diff --git a/packages/oc-docs/e2e/components/layout/theme-toggle.component.ts b/packages/oc-docs/e2e/components/layout/theme-toggle.component.ts
new file mode 100644
index 00000000..dd9d1922
--- /dev/null
+++ b/packages/oc-docs/e2e/components/layout/theme-toggle.component.ts
@@ -0,0 +1,9 @@
+import { BaseComponent } from '../base.component';
+
+export class ThemeToggleComponent extends BaseComponent {
+ readonly button = this.page.getByTestId('theme-toggle');
+
+ async toggle(): Promise {
+ await this.button.click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/markdown.component.ts b/packages/oc-docs/e2e/components/markdown.component.ts
new file mode 100644
index 00000000..3b67e80a
--- /dev/null
+++ b/packages/oc-docs/e2e/components/markdown.component.ts
@@ -0,0 +1,49 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from './base.component';
+
+/**
+ * A block of rendered Markdown — headings, paragraphs, lists, tables, code and
+ * quotes.
+ */
+export class MarkdownComponent extends BaseComponent {
+ heading(text: string): Locator {
+ return this.root.getByRole('heading', { name: text });
+ }
+
+ paragraph(text: string): Locator {
+ return this.root.getByRole('paragraph').filter({ hasText: text });
+ }
+
+ /** An item in a numbered (ordered) list. */
+ numberedItem(text: string): Locator {
+ return this.root.locator('ol > li', { hasText: text });
+ }
+
+ /** An item in a bulleted (unordered) list. */
+ bulletedItem(text: string): Locator {
+ return this.root.locator('ul > li', { hasText: text });
+ }
+
+ /** Bold (`**…**`) text. */
+ boldText(text: string): Locator {
+ return this.root.locator('strong', { hasText: text });
+ }
+
+ /** Inline or fenced code. */
+ code(text: string): Locator {
+ return this.root.locator('code', { hasText: text });
+ }
+
+ table(): Locator {
+ return this.root.getByRole('table');
+ }
+
+ columnHeader(text: string): Locator {
+ return this.table().getByRole('columnheader', { name: text });
+ }
+
+ /** A table cell, matched exactly. */
+ cell(text: string): Locator {
+ return this.table().getByRole('cell', { name: text, exact: true });
+ }
+}
diff --git a/packages/oc-docs/e2e/components/overview/collection-configuration.component.ts b/packages/oc-docs/e2e/components/overview/collection-configuration.component.ts
new file mode 100644
index 00000000..c560fe48
--- /dev/null
+++ b/packages/oc-docs/e2e/components/overview/collection-configuration.component.ts
@@ -0,0 +1,28 @@
+import type { Locator } from "@playwright/test";
+import { BaseComponent } from "../base.component";
+import { SecretValueComponent } from "../secret-value.component";
+
+export class ConfigurationSection extends BaseComponent {
+ readonly root = this.page.getByTestId("collection-config");
+
+ readonly copyButton = this.root.getByTestId("collection-config-tests-copy");
+
+ readonly secret = new SecretValueComponent(
+ this.page,
+ "collection-config-auth-secret",
+ );
+
+ readonly disabledRows = this.root
+ .getByTestId("property-value-line")
+ .filter({ has: this.page.getByTestId("disabled-badge") });
+
+ subHeading(name: string): Locator {
+ return this.root
+ .getByTestId("collection-config-subheading")
+ .filter({ hasText: name });
+ }
+
+ async copyToClipboard(): Promise {
+ await this.copyButton.click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/overview/collection-stats.component.ts b/packages/oc-docs/e2e/components/overview/collection-stats.component.ts
new file mode 100644
index 00000000..ba202bcf
--- /dev/null
+++ b/packages/oc-docs/e2e/components/overview/collection-stats.component.ts
@@ -0,0 +1,15 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class StatsSection extends BaseComponent {
+
+ readonly cards = this.page.getByTestId('collection-stats-stat');
+
+ card(label: string): Locator {
+ return this.cards.filter({ hasText: label });
+ }
+
+ valueFor(label: string): Locator {
+ return this.card(label).getByTestId('collection-stats-stat-value');
+ }
+}
diff --git a/packages/oc-docs/e2e/components/overview/environments.component.ts b/packages/oc-docs/e2e/components/overview/environments.component.ts
new file mode 100644
index 00000000..3b01f5bb
--- /dev/null
+++ b/packages/oc-docs/e2e/components/overview/environments.component.ts
@@ -0,0 +1,15 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class EnvironmentsSection extends BaseComponent {
+
+ readonly items = this.page.getByTestId('overview-environment-item');
+
+ item(name: string): Locator {
+ return this.items.filter({ has: this.page.getByText(name, { exact: true }) });
+ }
+
+ variableCount(name: string): Locator {
+ return this.item(name).getByTestId('overview-environment-item-variable-count');
+ }
+}
diff --git a/packages/oc-docs/e2e/components/overview/header.component.ts b/packages/oc-docs/e2e/components/overview/header.component.ts
new file mode 100644
index 00000000..114259e9
--- /dev/null
+++ b/packages/oc-docs/e2e/components/overview/header.component.ts
@@ -0,0 +1,6 @@
+import { BaseComponent } from '../base.component';
+
+export class HeaderSection extends BaseComponent {
+ readonly collectionVersion = this.page.getByTestId('overview-collection-version');
+ readonly collectionName = this.page.getByTestId('overview-collection-name');
+}
diff --git a/packages/oc-docs/e2e/components/playground.component.ts b/packages/oc-docs/e2e/components/playground.component.ts
new file mode 100644
index 00000000..ea549374
--- /dev/null
+++ b/packages/oc-docs/e2e/components/playground.component.ts
@@ -0,0 +1,124 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from './base.component';
+import { KeyValueTableComponent } from './key-value-table/key-value-table.component';
+import { CodeEditorComponent } from './code-editor/code-editor.component';
+import type { DockMode } from '../../src/utils/playgroundDock';
+
+export class PlaygroundComponent extends BaseComponent {
+ readonly keyValueTable = new KeyValueTableComponent(this.page);
+ readonly preRequestScriptEditor = new CodeEditorComponent(this.page, 'scripts-editor-pre-request');
+ readonly postResponseScriptEditor = new CodeEditorComponent(this.page, 'scripts-editor-post-response');
+
+ readonly header = this.page.getByTestId('playground-header');
+ readonly switcher = this.page.getByTestId('playground-dock-switcher');
+ readonly content = this.page.getByTestId('playground-content');
+ readonly runner = this.page.getByTestId('playground-runner');
+ readonly loadError = this.page.getByTestId('playground-load-error');
+ readonly sidebarPanel = this.page.getByTestId('playground-sidebar-panel');
+ readonly sidebarBackdrop = this.page.getByTestId('playground-sidebar-backdrop');
+ readonly collectionNode = this.page.getByTestId('sidebar-collection-root');
+ readonly collectionCollapseToggle = this.collectionNode.getByRole('button', {
+ name: /Collapse collection|Expand collection/,
+ });
+ readonly collectionRootLink = this.collectionNode.getByRole('button', {
+ name: /Bruno Testbench|Collection/,
+ });
+ readonly envSwitcher = this.page.getByTestId('playground-env-switcher');
+ readonly gear = this.page.getByTestId('playground-env-settings');
+ readonly view = this.page.getByTestId('playground-view');
+ readonly sidebarToggle = this.page.getByTestId('playground-sidebar-toggle');
+ readonly treeItems = this.page.getByTestId('playground-sidebar-panel').getByTestId('sidebar-item');
+ readonly closeButton = this.page.getByTestId('playground-close');
+ readonly collapseButton = this.page.getByTestId('playground-collapse');
+ readonly inlinePanel = this.page.getByTestId('playground-dock-inline-panel');
+ readonly bottomPanel = this.page.getByTestId('playground-dock-bottom-panel');
+ readonly modalPanel = this.page.getByTestId('playground-dock-modal-panel');
+ readonly mobilePanel = this.page.getByTestId('playground-dock-mobile-panel');
+ readonly unsupported = this.view.getByTestId('unsupported-request');
+ readonly unsupportedTitle = this.view.getByTestId('unsupported-request-title');
+ readonly unsupportedMessage = this.view.getByTestId('unsupported-request-empty');
+ readonly unsupportedIcon = this.view.getByTestId('file-not-found-icon');
+ readonly exampleView = this.page.getByTestId('example-view');
+ readonly exampleViewRequest = this.page.getByTestId('example-view-request');
+ readonly exampleViewResponse = this.page.getByTestId('example-view-response');
+
+ readonly exampleViewControls = this.exampleView.locator('input, textarea');
+
+ exampleToggle(requestName: string): Locator {
+ return this.treeItems.filter({ hasText: requestName }).getByTestId('sidebar-example-toggle');
+ }
+
+ exampleRow(exampleName: string): Locator {
+ return this.sidebarPanel.getByTestId('sidebar-example').filter({ hasText: exampleName });
+ }
+
+ async open(dock: DockMode = 'bottom'): Promise {
+ await this.page.goto(`/#/?pg=1&dock=${dock}`);
+ }
+
+ sidebarItem(name: string): Locator {
+ return this.treeItems.filter({ hasText: name }).first();
+ }
+
+ async openSidebarItem(name: string): Promise {
+ await this.sidebarItem(name).click();
+ }
+
+ scriptTab(id: string): Locator {
+ return this.page.getByTestId(`scripts-tabs-tab-${id}`);
+ }
+
+ async selectScriptTab(id: string): Promise {
+ await this.scriptTab(id).click();
+ }
+
+ async openTreeItem(names: string[]): Promise {
+ for (const name of names) {
+ await this.treeItems.filter({ hasText: name }).first().click();
+ }
+ }
+
+ dockButton(mode: DockMode): Locator {
+ return this.page.getByTestId(`playground-dock-${mode}`);
+ }
+
+ panel(mode: DockMode): Locator {
+ return this.page.getByTestId(`playground-dock-${mode}-panel`);
+ }
+
+ async open(mode: DockMode): Promise {
+ await this.page.goto(`/#/?pg=1&dock=${mode}`);
+ await this.runner.waitFor({ state: 'visible' });
+ }
+
+ async openRequest(name: string): Promise {
+ await this.treeItems.filter({ hasText: name }).first().click();
+ }
+
+ async openEnvironments(): Promise {
+ if (!(await this.gear.isVisible())) {
+ await this.sidebarToggle.click();
+ }
+ await this.gear.click();
+ }
+
+ async selectDock(mode: DockMode): Promise {
+ await this.dockButton(mode).click();
+ }
+
+ tab(id: string): Locator {
+ return this.page.getByTestId(`tabs-tab-${id}`);
+ }
+
+ async selectTab(id: string): Promise {
+ await this.tab(id).click();
+ }
+
+ async close(): Promise {
+ await this.closeButton.click();
+ }
+
+ async toggleCollapse(): Promise {
+ await this.collapseButton.click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/playground/request-body.component.ts b/packages/oc-docs/e2e/components/playground/request-body.component.ts
new file mode 100644
index 00000000..eb56b718
--- /dev/null
+++ b/packages/oc-docs/e2e/components/playground/request-body.component.ts
@@ -0,0 +1,15 @@
+import { BaseComponent } from '../base.component';
+
+// The Body tab inside the playground request pane: the body-type dropdown and
+// the editor region each type renders. Open the tab via playground.selectTab('body').
+export class RequestBodyComponent extends BaseComponent {
+ readonly typeSelect = this.page.getByTestId('body-type-select');
+ readonly empty = this.page.getByTestId('body-empty');
+ readonly multipart = this.page.getByTestId('body-multipart');
+ readonly file = this.page.getByTestId('body-file');
+
+ async selectType(value: string): Promise {
+ await this.typeSelect.click();
+ await this.page.getByTestId(`body-type-select-${value}`).click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/request/code-snippet.component.ts b/packages/oc-docs/e2e/components/request/code-snippet.component.ts
new file mode 100644
index 00000000..317d37dc
--- /dev/null
+++ b/packages/oc-docs/e2e/components/request/code-snippet.component.ts
@@ -0,0 +1,46 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class CodeSnippetComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('request-code-snippet');
+
+ readonly code = this.root.getByTestId('code-snippet-code');
+
+ readonly copyButton = this.root.getByTestId('code-snippet-code-copy');
+
+ readonly expandButton = this.root.getByTestId('code-snippet-expand');
+
+ readonly modal = this.page.getByTestId('code-snippet-modal');
+
+ readonly modalCode = this.modal.getByTestId('code-snippet-code');
+
+ variableToken(name: string): Locator {
+ return this.code.getByTestId(`variable-token-${name}`).first();
+ }
+
+ modalVariableToken(name: string): Locator {
+ return this.modalCode.getByTestId(`variable-token-${name}`).first();
+ }
+
+ languageTab(language: string): Locator {
+ return this.root.getByTestId(`code-snippet-tab-${language}`);
+ }
+
+ modalLanguageTab(language: string): Locator {
+ return this.modal.getByTestId(`code-snippet-tab-${language}`);
+ }
+
+ async selectLanguage(language: string): Promise {
+ await this.languageTab(language).click();
+ }
+
+ /** Open the enlarged code-snippet view via the expand control. */
+ async openExpandedView(): Promise {
+ await this.expandButton.click();
+ await this.modal.waitFor({ state: 'visible' });
+ }
+
+ async selectModalLanguage(language: string): Promise {
+ await this.modalLanguageTab(language).click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/request/examples.component.ts b/packages/oc-docs/e2e/components/request/examples.component.ts
new file mode 100644
index 00000000..c4b81ab6
--- /dev/null
+++ b/packages/oc-docs/e2e/components/request/examples.component.ts
@@ -0,0 +1,43 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class ExamplesComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('request-examples');
+
+ readonly items = this.root.getByTestId('example-card');
+
+ // The card the sidebar navigated to (data-active set by ExampleCard).
+ readonly activeCard = this.root.locator('[data-testid="example-card"][data-active="true"]');
+
+ example(name: string): Locator {
+ return this.items.filter({ hasText: name });
+ }
+
+ statusCode(name: string): Locator {
+ return this.example(name).getByTestId('example-status');
+ }
+
+ requestBody(name: string): Locator {
+ return this.example(name).getByTestId('example-request-pane-body');
+ }
+
+ responseBody(name: string): Locator {
+ return this.example(name).getByTestId('example-response-pane-body');
+ }
+
+ async open(name: string): Promise {
+ await this.example(name).getByTestId('example-toggle').click();
+ }
+
+ async try(name: string): Promise {
+ await this.example(name).getByTestId('example-try').click();
+ }
+
+ async selectRequestTab(name: string, tab: string): Promise {
+ await this.example(name).getByTestId(`example-request-pane-tab-${tab}`).click();
+ }
+
+ async selectResponseTab(name: string, tab: string): Promise {
+ await this.example(name).getByTestId(`example-response-pane-tab-${tab}`).click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/request/execution-context.component.ts b/packages/oc-docs/e2e/components/request/execution-context.component.ts
new file mode 100644
index 00000000..45142c57
--- /dev/null
+++ b/packages/oc-docs/e2e/components/request/execution-context.component.ts
@@ -0,0 +1,44 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export type ExecutionContextTab = 'variables' | 'scripts' | 'asserts' | 'tests';
+
+export class ExecutionContextComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('execution-context');
+
+ readonly executionFlow = this.root.getByTestId('execution-context-flow');
+ readonly viewCompleteCodeButton = this.root.getByTestId('execution-context-view-complete-code');
+
+ readonly variablesPanel = this.root.getByTestId('execution-context-variables');
+ readonly scriptsPanel = this.root.getByTestId('execution-context-scripts');
+ readonly assertsPanel = this.root.getByTestId('execution-context-asserts');
+ readonly testsPanel = this.root.getByTestId('execution-context-tests');
+
+ tab(name: ExecutionContextTab): Locator {
+ return this.root.getByTestId(`execution-context-tabs-tab-${name}`);
+ }
+
+ async openTab(name: ExecutionContextTab): Promise {
+ await this.tab(name).click();
+ }
+
+ scriptStep(label: string): Locator {
+ return this.scriptsPanel.getByText(label);
+ }
+
+ scriptSource(name: string): Locator {
+ return this.scriptsPanel.locator('button.script-step-source').filter({ hasText: name });
+ }
+
+ variable(name: string): Locator {
+ return this.variablesPanel.getByText(name, { exact: true });
+ }
+
+ assertion(text: string): Locator {
+ return this.assertsPanel.getByText(text);
+ }
+
+ testCase(name: string): Locator {
+ return this.testsPanel.getByText(name);
+ }
+}
diff --git a/packages/oc-docs/e2e/components/request/url-bar.component.ts b/packages/oc-docs/e2e/components/request/url-bar.component.ts
new file mode 100644
index 00000000..1afba089
--- /dev/null
+++ b/packages/oc-docs/e2e/components/request/url-bar.component.ts
@@ -0,0 +1,9 @@
+import { BaseComponent } from '../base.component';
+
+export class RequestUrlBarComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('request-url-bar');
+
+ readonly method = this.root.getByTestId('request-method');
+ readonly url = this.root.getByTestId('request-url');
+ readonly tryButton = this.root.getByTestId('request-try-button');
+}
diff --git a/packages/oc-docs/e2e/components/script/script-content.component.ts b/packages/oc-docs/e2e/components/script/script-content.component.ts
new file mode 100644
index 00000000..cc271bd1
--- /dev/null
+++ b/packages/oc-docs/e2e/components/script/script-content.component.ts
@@ -0,0 +1,9 @@
+import { BaseComponent } from '../base.component';
+
+export class ScriptContentComponent extends BaseComponent {
+ readonly root = this.page.getByTestId('script-code');
+
+ readonly code = this.root.locator('code');
+
+ readonly copyButton = this.root.getByTestId('script-code-copy');
+}
diff --git a/packages/oc-docs/e2e/components/search/search.component.ts b/packages/oc-docs/e2e/components/search/search.component.ts
new file mode 100644
index 00000000..8ec975ba
--- /dev/null
+++ b/packages/oc-docs/e2e/components/search/search.component.ts
@@ -0,0 +1,44 @@
+import type { Page, Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+/**
+ * The endpoint search palette. A page-wide control (its panel is a fixed
+ * overlay), so it omits a container root. Parts are found by accessible role or
+ * test id, never by class.
+ */
+export class SearchComponent extends BaseComponent {
+ constructor(page: Page) {
+ super(page);
+ }
+
+ /** Inline combobox field (desktop / once revealed below desktop). */
+ readonly field = this.root.getByRole('combobox', { name: 'Search endpoints' });
+ /** The panel element (open state is reflected by its `data-open` attribute). */
+ readonly panel = this.root.getByTestId('search-panel');
+ readonly openPanel = this.root.locator('[data-testid="search-panel"][data-open="true"]');
+ readonly filters = this.root.getByTestId('search-filters');
+ readonly resultsList = this.root.getByTestId('search-results');
+ /** The scrollable results container (results overflow it and scroll). */
+ readonly resultsScroll = this.root.getByTestId('search-scroll');
+ readonly results = this.root.getByTestId('search-result');
+ readonly resultMethods = this.root.getByTestId('search-result-method');
+ /** The keyboard-highlighted result option. */
+ readonly activeOption = this.root.locator('[role="option"][aria-selected="true"]');
+ readonly clearButton = this.root.getByRole('button', { name: 'Clear search' });
+ /** Below-desktop Topbar trigger that reveals the search. */
+ readonly toggleIcon = this.root.getByRole('button', { name: /^search$/i });
+ readonly folderButton = this.root.getByRole('button', { name: 'Folder', exact: true });
+ readonly folderMenu = this.root.getByRole('listbox', { name: 'Filter by folder' });
+
+ methodChip(label: string): Locator {
+ return this.root.getByRole('button', { name: label, exact: true });
+ }
+
+ folderOption(name: string): Locator {
+ return this.folderMenu.getByRole('button', { name, exact: true });
+ }
+
+ result(text: string): Locator {
+ return this.results.filter({ hasText: text });
+ }
+}
diff --git a/packages/oc-docs/e2e/components/secret-value.component.ts b/packages/oc-docs/e2e/components/secret-value.component.ts
new file mode 100644
index 00000000..3c4e1eda
--- /dev/null
+++ b/packages/oc-docs/e2e/components/secret-value.component.ts
@@ -0,0 +1,19 @@
+import type { Locator, Page } from '@playwright/test';
+import { BaseComponent } from './base.component';
+
+export class SecretValueComponent extends BaseComponent {
+ readonly value: Locator;
+
+ readonly toggle: Locator;
+
+ constructor(page: Page, testId: string) {
+ super(page);
+ this.value = page.getByTestId(`${testId}-text`);
+ this.toggle = page.getByTestId(`${testId}-toggle`);
+ }
+
+ // Reveal the raw value.
+ async toggleReveal(): Promise {
+ await this.toggle.click();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/sidebar.component.ts b/packages/oc-docs/e2e/components/sidebar.component.ts
new file mode 100644
index 00000000..03ee5a5b
--- /dev/null
+++ b/packages/oc-docs/e2e/components/sidebar.component.ts
@@ -0,0 +1,61 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from './base.component';
+
+export class SidebarComponent extends BaseComponent {
+ readonly items = this.page.getByTestId('sidebar-item');
+ readonly inline = this.page.getByTestId('app-sidebar');
+ readonly overview = this.page.getByTestId('sidebar-overview');
+ readonly environments = this.page.getByTestId('sidebar-environments');
+ readonly collapseButton = this.page.getByTestId('sidebar-collapse');
+ readonly expandButton = this.page.getByTestId('sidebar-expand');
+ readonly drawer = this.page.getByTestId('sidebar-drawer');
+ readonly backdrop = this.page.getByTestId('sidebar-backdrop');
+ readonly hamburger = this.page.getByTestId('topbar-menu');
+
+ item(name: string): Locator {
+ return this.items.filter({ hasText: name });
+ }
+
+ folderChevron(name: string): Locator {
+ return this.item(name).first().locator('.navlink-chevron');
+ }
+
+ async toggleFolder(name: string): Promise {
+ await this.folderChevron(name).click();
+ }
+
+ exampleToggle(requestName: string): Locator {
+ return this.item(requestName).first().getByTestId('sidebar-example-toggle');
+ }
+
+ exampleRow(exampleName: string): Locator {
+ return this.page.getByTestId('sidebar-example').filter({ hasText: exampleName });
+ }
+
+ async toggleExamples(requestName: string): Promise {
+ await this.exampleToggle(requestName).click();
+ }
+
+ async open(paths: string[]): Promise {
+ for (const name of paths) {
+ await this.item(name).first().click();
+ }
+ }
+
+ async collapse(): Promise {
+ await this.inline.hover();
+ await this.collapseButton.click();
+ }
+
+ async expand(): Promise {
+ await this.expandButton.click();
+ }
+
+ async openDrawer(): Promise {
+ await this.hamburger.click();
+ }
+
+ async closeDrawerViaBackdrop(): Promise {
+ await this.backdrop.click({ position: { x: 375, y: 400 } });
+ }
+}
diff --git a/packages/oc-docs/e2e/components/tooltip.component.ts b/packages/oc-docs/e2e/components/tooltip.component.ts
new file mode 100644
index 00000000..cee2d6e0
--- /dev/null
+++ b/packages/oc-docs/e2e/components/tooltip.component.ts
@@ -0,0 +1,35 @@
+import type { Locator, Page } from '@playwright/test';
+import { BaseComponent } from './base.component';
+
+export class TooltipComponent extends BaseComponent {
+ readonly truncatableCells: Locator;
+
+ readonly popup: Locator;
+
+ constructor(page: Page) {
+ super(page);
+ this.truncatableCells = page.getByTestId('truncated-text');
+ this.popup = page.getByTestId('tooltip');
+ }
+
+ /** The index and full text of the first cell whose text is clipped, or null if none is clipped. */
+ async findFirstClippedCell(): Promise<{ index: number; fullText: string } | null> {
+ return this.truncatableCells.evaluateAll<{ index: number; fullText: string } | null, HTMLElement>((cells) => {
+ const clippedIndex = cells.findIndex((cell) => cell.scrollWidth > cell.clientWidth + 1);
+ if (clippedIndex < 0) return null;
+ return { index: clippedIndex, fullText: (cells[clippedIndex].textContent || '').trim() };
+ });
+ }
+
+ /** The index of the first cell whose text fits within its width, or -1 if every cell is clipped. */
+ async findFirstUnclippedCellIndex(): Promise {
+ return this.truncatableCells.evaluateAll((cells) =>
+ cells.findIndex((cell) => cell.scrollWidth <= cell.clientWidth + 1)
+ );
+ }
+
+ /** Hover the truncatable cell at `index` to trigger (or suppress) its tooltip. */
+ async hoverCell(index: number): Promise {
+ await this.truncatableCells.nth(index).hover();
+ }
+}
diff --git a/packages/oc-docs/e2e/components/variable-card/variable-card.component.ts b/packages/oc-docs/e2e/components/variable-card/variable-card.component.ts
new file mode 100644
index 00000000..1f1ea38f
--- /dev/null
+++ b/packages/oc-docs/e2e/components/variable-card/variable-card.component.ts
@@ -0,0 +1,28 @@
+import type { Locator } from '@playwright/test';
+import { BaseComponent } from '../base.component';
+
+export class VariableCardComponent extends BaseComponent {
+ readonly card = this.page.getByTestId('variable-info-card');
+ readonly name = this.card.getByTestId('variable-info-card-name');
+ readonly scopeBadge = this.card.getByTestId('variable-info-card-scope');
+ readonly value = this.card.getByTestId('variable-info-card-value');
+ readonly copyButton = this.card.getByTestId('variable-info-card-copy');
+ readonly revealToggle = this.card.getByTestId('variable-info-card-reveal');
+ readonly note = this.card.getByTestId('variable-info-card-note');
+ readonly warning = this.card.getByTestId('variable-info-card-warning');
+ // Read-only guard: the card must contain no editable control. Native inputs and third-party
+ // CodeMirror carry no test ids, so this absence check matches them structurally.
+ readonly editors = this.card.locator('textarea, input, .CodeMirror');
+
+ token(name: string): Locator {
+ return this.root.getByTestId(`variable-token-${name}`).first();
+ }
+
+ async hoverToken(name: string): Promise {
+ await this.token(name).hover();
+ }
+
+ async pinToken(name: string): Promise {
+ await this.token(name).click();
+ }
+}
diff --git a/packages/oc-docs/e2e/config/app.config.ts b/packages/oc-docs/e2e/config/app.config.ts
new file mode 100644
index 00000000..e77e909a
--- /dev/null
+++ b/packages/oc-docs/e2e/config/app.config.ts
@@ -0,0 +1,11 @@
+export interface AppConfig {
+ /** Base URL the docs app is served from (used as Playwright's `baseURL`). */
+ baseURL: string;
+ /** Command Playwright runs to start the app (the `webServer`). */
+ webServerCommand: string;
+}
+
+export const appConfig: AppConfig = {
+ baseURL:'http://127.0.0.1:3001',
+ webServerCommand: 'npm run dev'
+};
diff --git a/packages/oc-docs/e2e/pages/base.page.ts b/packages/oc-docs/e2e/pages/base.page.ts
new file mode 100644
index 00000000..520416ea
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/base.page.ts
@@ -0,0 +1,23 @@
+import type { Page } from '@playwright/test';
+
+export abstract class BasePage {
+ readonly root = this.page.locator('#root');
+
+ constructor(protected readonly page: Page) {}
+
+ /** Navigate to a path on the docs app (defaults to the app root). */
+ protected async navigate(path = '/'): Promise {
+ await this.page.goto(path);
+ }
+
+ /** Open a path on the docs app (defaults to the root) and wait for it to render. */
+ async goto(path = '/'): Promise {
+ await this.navigate(path);
+ await this.root.waitFor({ state: 'visible' });
+ }
+
+ /** Reload the current page. */
+ async reload(): Promise {
+ await this.page.reload();
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/environments.page.ts b/packages/oc-docs/e2e/pages/environments.page.ts
new file mode 100644
index 00000000..93a7c425
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/environments.page.ts
@@ -0,0 +1,28 @@
+import type { Locator } from '@playwright/test';
+import { BasePage } from './base.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { EnvironmentTableComponent } from '../components/environments/environment-table.component';
+
+export class EnvironmentsPage extends BasePage {
+
+ readonly root = this.page.getByTestId('environments-page');
+ readonly title = this.page.getByTestId('environments-title');
+ readonly tabs = this.page.getByTestId('environment-tab');
+ readonly variablesGroup = this.page.getByTestId('environment-variables');
+ readonly secretVariablesGroup = this.page.getByTestId('environment-secret-variables');
+ readonly externalSecretsGroup = this.page.getByTestId('environment-external-secrets');
+ readonly emptyState = this.page.getByTestId('environments-empty');
+
+ readonly table = new EnvironmentTableComponent(this.page);
+ readonly sidebar = new SidebarComponent(this.page);
+
+ async open(): Promise {
+ await this.navigate('/');
+ await this.page.getByTestId('sidebar-environments').click();
+ await this.root.waitFor({ state: 'visible' });
+ }
+
+ tab(name: string): Locator {
+ return this.tabs.filter({ hasText: name });
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/folder.page.ts b/packages/oc-docs/e2e/pages/folder.page.ts
new file mode 100644
index 00000000..ca31e8bf
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/folder.page.ts
@@ -0,0 +1,25 @@
+import { BasePage } from './base.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { BreadcrumbComponent } from '../components/breadcrumb.component';
+import { FolderConfigurationComponent } from '../components/folder/folder-configuration.component';
+import { VariableCardComponent } from '../components/variable-card/variable-card.component';
+
+export class FolderPage extends BasePage {
+ readonly root = this.page.getByTestId('folder-page');
+ readonly title = this.page.getByTestId('folder-title');
+ readonly requestCount = this.page.getByTestId('folder-request-count');
+ readonly folderMarkdownDocs = this.page.getByTestId('folder-docs');
+ readonly folderMarkdownDocsToggle = this.page.getByTestId('folder-docs-toggle');
+ readonly emptyState = this.page.getByTestId('folder-config-empty');
+
+ readonly sidebar = new SidebarComponent(this.page);
+ readonly breadcrumb = new BreadcrumbComponent(this.page, 'folder-breadcrumb');
+ readonly configuration = new FolderConfigurationComponent(this.page);
+ readonly variableCard = new VariableCardComponent(this.page, this.root);
+
+ async open(trail: string[]): Promise {
+ await this.navigate('/');
+ await this.sidebar.open(trail);
+ await this.root.waitFor({ state: 'visible' });
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/overview.page.ts b/packages/oc-docs/e2e/pages/overview.page.ts
new file mode 100644
index 00000000..a8919c86
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/overview.page.ts
@@ -0,0 +1,23 @@
+import type { Locator } from '@playwright/test';
+import { BasePage } from './base.page';
+import { MarkdownComponent } from '../components/markdown.component';
+import { HeaderSection } from '../components/overview/header.component';
+import { StatsSection } from '../components/overview/collection-stats.component';
+import { EnvironmentsSection } from '../components/overview/environments.component';
+import { ConfigurationSection } from '../components/overview/collection-configuration.component';
+import { VariableCardComponent } from '../components/variable-card/variable-card.component';
+
+export class OverviewPage extends BasePage {
+ readonly root = this.page.getByTestId('overview');
+
+ readonly header = new HeaderSection(this.page);
+ readonly stats = new StatsSection(this.page);
+ readonly environments = new EnvironmentsSection(this.page);
+ readonly configuration = new ConfigurationSection(this.page);
+ readonly docMarkdown = new MarkdownComponent(this.page, this.page.getByTestId('overview-markdown-documentation'));
+ readonly variableCard = new VariableCardComponent(this.page, this.root);
+
+ sectionLabel(name: string): Locator {
+ return this.page.getByTestId('overview-section-label').filter({ hasText: name });
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/request.page.ts b/packages/oc-docs/e2e/pages/request.page.ts
new file mode 100644
index 00000000..e28cda63
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/request.page.ts
@@ -0,0 +1,37 @@
+import type { Locator } from '@playwright/test';
+import { BasePage } from './base.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { BreadcrumbComponent } from '../components/breadcrumb.component';
+import { RequestUrlBarComponent } from '../components/request/url-bar.component';
+import { CodeSnippetComponent } from '../components/request/code-snippet.component';
+import { ExamplesComponent } from '../components/request/examples.component';
+import { ExecutionContextComponent } from '../components/request/execution-context.component';
+import { VariableCardComponent } from '../components/variable-card/variable-card.component';
+
+export class RequestPage extends BasePage {
+ readonly root = this.page.getByTestId('request-page');
+ readonly title = this.page.getByTestId('request-title');
+ readonly description = this.page.getByTestId('request-description');
+
+ readonly sidebar = new SidebarComponent(this.page);
+ readonly breadcrumb = new BreadcrumbComponent(this.page, 'request-breadcrumb');
+ readonly urlBar = new RequestUrlBarComponent(this.page);
+ readonly codeSnippet = new CodeSnippetComponent(this.page);
+
+ readonly examples = new ExamplesComponent(this.page);
+ readonly executionContext = new ExecutionContextComponent(this.page);
+
+ readonly variableCard = new VariableCardComponent(this.page, this.root);
+ readonly bodyVariableCard = new VariableCardComponent(this.page, this.section('body'));
+
+ async open(path: string[]): Promise {
+ await this.navigate('/');
+ await this.sidebar.open(path);
+ await this.root.waitFor({ state: 'visible' });
+ }
+
+ section(label: string): Locator {
+ const slug = label.toLowerCase().replace(/\s+/g, '-');
+ return this.page.getByTestId(`request-section-${slug}`);
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/script.page.ts b/packages/oc-docs/e2e/pages/script.page.ts
new file mode 100644
index 00000000..00bcee8b
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/script.page.ts
@@ -0,0 +1,19 @@
+import { BasePage } from './base.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { BreadcrumbComponent } from '../components/breadcrumb.component';
+import { ScriptContentComponent } from '../components/script/script-content.component';
+
+export class ScriptPage extends BasePage {
+ readonly root = this.page.getByTestId('script-page');
+
+ readonly sidebar = new SidebarComponent(this.page);
+ readonly breadcrumb = new BreadcrumbComponent(this.page, 'script-breadcrumb');
+ readonly title = this.page.getByTestId('script-title');
+ readonly content = new ScriptContentComponent(this.page);
+
+ async open(path: string[]): Promise {
+ await this.navigate('/');
+ await this.sidebar.open(path);
+ await this.root.waitFor({ state: 'visible' });
+ }
+}
diff --git a/packages/oc-docs/e2e/pages/unsupported-request.page.ts b/packages/oc-docs/e2e/pages/unsupported-request.page.ts
new file mode 100644
index 00000000..6b74705a
--- /dev/null
+++ b/packages/oc-docs/e2e/pages/unsupported-request.page.ts
@@ -0,0 +1,21 @@
+import { BasePage } from './base.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { BreadcrumbComponent } from '../components/breadcrumb.component';
+import { RequestUrlBarComponent } from '../components/request/url-bar.component';
+
+export class UnsupportedRequestPage extends BasePage {
+ readonly sidebar = new SidebarComponent(this.page);
+ readonly breadcrumb = new BreadcrumbComponent(this.page, 'unsupported-request-breadcrumb');
+ readonly urlBar = new RequestUrlBarComponent(this.page);
+
+ readonly root = this.page.getByTestId('unsupported-request');
+ readonly title = this.page.getByTestId('unsupported-request-title');
+ readonly message = this.page.getByTestId('unsupported-request-empty');
+ readonly docs = this.root.getByTestId('overview-markdown-documentation');
+
+ async open(path: string[]): Promise {
+ await this.navigate('/');
+ await this.sidebar.open(path);
+ await this.root.waitFor({ state: 'visible' });
+ }
+}
diff --git a/packages/oc-docs/e2e/playwright/index.ts b/packages/oc-docs/e2e/playwright/index.ts
new file mode 100644
index 00000000..26cbd136
--- /dev/null
+++ b/packages/oc-docs/e2e/playwright/index.ts
@@ -0,0 +1,12 @@
+import { mergeTests } from '@playwright/test';
+import { test as pagesTest } from './pages.fixture';
+
+/**
+ * Entry point for the test harness — specs import everything (`test`, `expect`)
+ * from here.
+ *
+ * `mergeTests` combines the fixtures from every `*.fixture.ts` file in this folder
+ * into one `test`.
+ */
+export const test = mergeTests(pagesTest);
+export { expect } from '@playwright/test';
diff --git a/packages/oc-docs/e2e/playwright/pages.fixture.ts b/packages/oc-docs/e2e/playwright/pages.fixture.ts
new file mode 100644
index 00000000..c831dda1
--- /dev/null
+++ b/packages/oc-docs/e2e/playwright/pages.fixture.ts
@@ -0,0 +1,87 @@
+import { test as base } from '@playwright/test';
+import { OverviewPage } from '../pages/overview.page';
+import { EnvironmentsPage } from '../pages/environments.page';
+import { RequestPage } from '../pages/request.page';
+import { ScriptPage } from '../pages/script.page';
+import { FolderPage } from '../pages/folder.page';
+import { UnsupportedRequestPage } from '../pages/unsupported-request.page';
+import { SidebarComponent } from '../components/sidebar.component';
+import { TooltipComponent } from '../components/tooltip.component';
+import { PlaygroundComponent } from '../components/playground.component';
+import { RequestBodyComponent } from '../components/playground/request-body.component';
+import { EnvEditorComponent } from '../components/environments/env-editor.component';
+import { CollectionSettingsComponent } from '../components/collection-settings/collection-settings.component';
+import { ThemeToggleComponent } from '../components/layout/theme-toggle.component';
+import { PageHeaderComponent } from '../components/layout/page-header.component';
+import { SearchComponent } from '../components/search/search.component';
+import { EnvSwitcherComponent } from '../components/layout/env-switcher.component';
+
+type Fixtures = {
+ overviewPage: OverviewPage;
+ environmentsPage: EnvironmentsPage;
+ requestPage: RequestPage;
+ scriptPage: ScriptPage;
+ folderPage: FolderPage;
+ unsupportedRequestPage: UnsupportedRequestPage;
+ sidebar: SidebarComponent;
+ tooltip: TooltipComponent;
+ playground: PlaygroundComponent;
+ requestBody: RequestBodyComponent;
+ envEditor: EnvEditorComponent;
+ collectionSettings: CollectionSettingsComponent;
+ pageHeader: PageHeaderComponent;
+ envSwitcher: EnvSwitcherComponent;
+ themeToggle: ThemeToggleComponent;
+ search: SearchComponent;
+};
+
+export const test = base.extend({
+ overviewPage: async ({ page }, use) => {
+ await use(new OverviewPage(page));
+ },
+ environmentsPage: async ({ page }, use) => {
+ await use(new EnvironmentsPage(page));
+ },
+ requestPage: async ({ page }, use) => {
+ await use(new RequestPage(page));
+ },
+ scriptPage: async ({ page }, use) => {
+ await use(new ScriptPage(page));
+ },
+ folderPage: async ({ page }, use) => {
+ await use(new FolderPage(page));
+ },
+ unsupportedRequestPage: async ({ page }, use) => {
+ await use(new UnsupportedRequestPage(page));
+ },
+ sidebar: async ({ page }, use) => {
+ await use(new SidebarComponent(page));
+ },
+ tooltip: async ({ page }, use) => {
+ await use(new TooltipComponent(page));
+ },
+ pageHeader: async ({ page }, use) => {
+ await use(new PageHeaderComponent(page));
+ },
+ envSwitcher: async ({ page }, use) => {
+ await use(new EnvSwitcherComponent(page));
+ },
+ playground: async ({ page }, use) => {
+ await use(new PlaygroundComponent(page));
+ },
+ requestBody: async ({ page }, use) => {
+ await use(new RequestBodyComponent(page));
+ },
+ envEditor: async ({ page }, use) => {
+ await use(new EnvEditorComponent(page));
+ },
+ collectionSettings: async ({ page }, use) => {
+ await use(new CollectionSettingsComponent(page));
+ },
+ themeToggle: async ({ page }, use) => {
+ await use(new ThemeToggleComponent(page));
+ },
+ search: async ({ page }, use) => {
+ await use(new SearchComponent(page));
+ }
+});
diff --git a/packages/oc-docs/e2e/tests/app/app.spec.ts b/packages/oc-docs/e2e/tests/app/app.spec.ts
new file mode 100644
index 00000000..6f027b05
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/app/app.spec.ts
@@ -0,0 +1,7 @@
+import { test, expect } from '../../playwright';
+
+test('app loads and renders the collection', async ({ page }) => {
+ await page.goto('/');
+ await expect(page.getByTestId('app-shell')).toBeVisible();
+ await expect(page.getByRole('heading', { name: 'Bruno Testbench' }).first()).toBeVisible();
+});
diff --git a/packages/oc-docs/e2e/tests/collection-settings/collection-settings.spec.ts b/packages/oc-docs/e2e/tests/collection-settings/collection-settings.spec.ts
new file mode 100644
index 00000000..55095acf
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/collection-settings/collection-settings.spec.ts
@@ -0,0 +1,82 @@
+import { test, expect } from '../../playwright';
+
+const TABS = ['overview', 'headers', 'variables', 'auth', 'scripts', 'tests'];
+
+test.describe('collection settings', () => {
+ test.use({ viewport: { width: 1280, height: 900 } });
+
+ test.beforeEach(async ({ page, collectionSettings }) => {
+ await page.goto('/#/?pg=1&dock=bottom');
+ await collectionSettings.open();
+ });
+
+ test('renders the six tabs', async ({ collectionSettings }) => {
+ for (const id of TABS) {
+ await expect(collectionSettings.tab(id)).toBeVisible();
+ }
+ });
+
+ test('overview renders the docs markdown or an empty state', async ({ collectionSettings }) => {
+ await expect(collectionSettings.overviewMarkdown.or(collectionSettings.overviewEmpty)).toBeVisible();
+ });
+
+ test('headers toggles between key/value and bulk edit', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('headers');
+ await expect(collectionSettings.bulkEditToggle).toHaveText('Bulk edit');
+ await collectionSettings.bulkEditToggle.click();
+ await expect(collectionSettings.bulkEditToggle).toHaveText('Key/Value edit');
+ await collectionSettings.bulkEditToggle.click();
+ await expect(collectionSettings.bulkEditToggle).toHaveText('Bulk edit');
+ });
+
+ test('vars shows the collection variables table', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('variables');
+ await expect(collectionSettings.varsTable).toBeVisible();
+ });
+
+ test('auth edits basic credentials', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('auth');
+ await collectionSettings.selectAuthMode('basic');
+ await expect(collectionSettings.authField('username')).toBeVisible();
+ await expect(collectionSettings.authField('password')).toBeVisible();
+ await expect(collectionSettings.authField('password')).toHaveAttribute('type', 'password');
+ });
+
+ test('bearer and api key render their fields', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('auth');
+
+ await collectionSettings.selectAuthMode('bearer');
+ await expect(collectionSettings.authField('token')).toHaveAttribute('type', 'password');
+
+ await collectionSettings.selectAuthMode('apikey');
+ await expect(collectionSettings.authField('key')).toBeVisible();
+ await expect(collectionSettings.authField('value')).toHaveAttribute('type', 'text');
+ await expect(collectionSettings.authField('placement')).toBeVisible();
+ });
+
+ test('does not offer Digest or AWS Signature v4 as selectable auth modes', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('auth');
+ await collectionSettings.authMode.click();
+
+ await expect(collectionSettings.authModeOption('basic')).toBeVisible();
+ await expect(collectionSettings.authModeOption('digest')).toHaveCount(0);
+ await expect(collectionSettings.authModeOption('awsv4')).toHaveCount(0);
+ });
+
+ test('scripts shows pre-request and post-response editors', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('scripts');
+ await expect(collectionSettings.scriptTab('pre-request')).toBeVisible();
+ await expect(collectionSettings.scriptTab('post-response')).toBeVisible();
+ });
+
+ test('persists an edited auth value across tab switches', async ({ collectionSettings }) => {
+ await collectionSettings.openTab('auth');
+ await collectionSettings.selectAuthMode('basic');
+ await collectionSettings.authField('username').fill('admin');
+
+ await collectionSettings.openTab('variables');
+ await collectionSettings.openTab('auth');
+
+ await expect(collectionSettings.authField('username')).toHaveValue('admin');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/environments/environments.spec.ts b/packages/oc-docs/e2e/tests/environments/environments.spec.ts
new file mode 100644
index 00000000..96b37866
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/environments/environments.spec.ts
@@ -0,0 +1,113 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Environments page', () => {
+ test.beforeEach(async ({ environmentsPage }) => {
+ await environmentsPage.open();
+ });
+
+ test('opens from the sidebar and shows a tab per environment', async ({ environmentsPage }) => {
+ await expect(environmentsPage.title).toHaveText('Environments');
+ await expect(environmentsPage.tabs).toHaveCount(2);
+ await expect(environmentsPage.tab('Local')).toBeVisible();
+ await expect(environmentsPage.tab('Prod')).toBeVisible();
+ });
+
+ test('selects the first environment by default', async ({ environmentsPage }) => {
+ await expect(environmentsPage.tab('Local')).toHaveAttribute('aria-selected', 'true');
+ await expect(environmentsPage.tab('Prod')).toHaveAttribute('aria-selected', 'false');
+ });
+
+ test('lists the active environment variables with their value and data type', async ({ environmentsPage }) => {
+ const { table } = environmentsPage;
+
+ await test.step('the Variables group is shown', async () => {
+ await expect(environmentsPage.variablesGroup).toBeVisible();
+ });
+
+ await test.step('the host variable shows its value and a string data type', async () => {
+ await expect(table.variableRow('host')).toBeVisible();
+ await expect(table.valueOf('host')).toContainText('http://localhost:8081');
+ await expect(table.dataTypeOf('host')).toHaveText('string');
+ });
+ });
+
+ test('labels number, boolean and object variables with their data type', async ({ environmentsPage }) => {
+ const { table } = environmentsPage;
+
+ await test.step('a number variable shows its value and a number data type', async () => {
+ await expect(table.valueOf('retryCount')).toContainText('3');
+ await expect(table.dataTypeOf('retryCount')).toHaveText('number');
+ });
+
+ await test.step('a boolean variable shows a boolean data type', async () => {
+ await expect(table.dataTypeOf('featureEnabled')).toHaveText('boolean');
+ });
+
+ await test.step('an object variable shows an object data type', async () => {
+ await expect(table.dataTypeOf('defaultUser')).toHaveText('object');
+ });
+ });
+
+ test('shows a "(Secret)" placeholder for a secret variable — display-only, never empty, no reveal toggle', async ({
+ environmentsPage
+ }) => {
+ const { table } = environmentsPage;
+ await expect(environmentsPage.secretVariablesGroup).toBeVisible();
+
+ await expect(table.secretValueOf('bearer_auth_token')).toContainText('(Secret)');
+ await expect(table.secretValueOf('bearer_auth_token')).not.toContainText('(empty)');
+ await expect(table.secretRevealToggleOf('bearer_auth_token')).toHaveCount(0);
+ });
+
+ test('switches the table when another environment tab is selected', async ({ environmentsPage }) => {
+ const { table } = environmentsPage;
+
+ await expect(table.valueOf('host')).toContainText('http://localhost:8081');
+
+ await environmentsPage.tab('Prod').click();
+
+ await expect(environmentsPage.tab('Prod')).toHaveAttribute('aria-selected', 'true');
+ await expect(table.valueOf('host')).toContainText('https://echo.usebruno.com');
+ });
+
+ test('renders an accessible columnar table with Name, Value and Data Type headers', async ({ environmentsPage }) => {
+ const { table } = environmentsPage;
+ await expect(table.columnHeader('name')).toHaveText('Name');
+ await expect(table.columnHeader('value')).toHaveText('Value');
+ await expect(table.columnHeader('type')).toHaveText('Data Type');
+ });
+
+ test('collapses the description row for variables that have no description', async ({ environmentsPage }) => {
+ const { table } = environmentsPage;
+
+ await expect(table.variableDescriptions).toBeHidden();
+ await expect(table.secretVariableDescriptions).toBeHidden();
+ });
+
+ test('hides the External Secret Variables section when the environment has none', async ({ environmentsPage }) => {
+ await expect(environmentsPage.tab('Local')).toHaveAttribute('aria-selected', 'true');
+ await expect(environmentsPage.externalSecretsGroup).toBeHidden();
+ });
+
+ test('shows external secrets with the manager label and reference for the Prod environment', async ({
+ environmentsPage
+ }) => {
+ const { table } = environmentsPage;
+
+ await environmentsPage.tab('Prod').click();
+
+ await test.step('the External Secret Variables group is shown with its manager', async () => {
+ await expect(environmentsPage.externalSecretsGroup).toBeVisible();
+ await expect(environmentsPage.externalSecretsGroup).toContainText('AWS Secrets Manager');
+ });
+
+ await test.step('each external secret lists its name and secret reference', async () => {
+ await expect(table.externalSecretRow('dbPassword')).toContainText('prod/db/credentials');
+ await expect(table.externalSecretRow('apiKey')).toContainText('prod/payment-gateway/api-key');
+ });
+
+ await test.step('external secrets without a type show an empty data type', async () => {
+ await expect(table.externalSecretRow('dbPassword')).toContainText('(empty)');
+ });
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/folder/folder.spec.ts b/packages/oc-docs/e2e/tests/folder/folder.spec.ts
new file mode 100644
index 00000000..87426ae5
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/folder/folder.spec.ts
@@ -0,0 +1,58 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Folder page', () => {
+ test('displays the folder name and how many requests it contains', async ({ folderPage }) => {
+ await folderPage.open(['Realtime']);
+ await expect(folderPage.title).toHaveText('Realtime');
+ await expect(folderPage.requestCount).toHaveText('3 requests');
+ });
+
+ test('shows the "No folder configuration" empty state when the folder has no config', async ({ folderPage }) => {
+ await folderPage.open(['Realtime']);
+ await expect(folderPage.emptyState).toBeVisible();
+ await expect(folderPage.emptyState).toContainText('No folder configuration');
+ await expect(folderPage.configuration.root).toBeHidden();
+ });
+
+ test('renders the configuration with inherited auth and folder-level scripts', async ({ folderPage }) => {
+ await folderPage.open(['billing']);
+
+ await test.step('the configuration is shown instead of the empty state', async () => {
+ await expect(folderPage.configuration.root).toBeVisible();
+ await expect(folderPage.emptyState).toBeHidden();
+ });
+
+ await test.step('the auth group shows the inherited-from-collection badge', async () => {
+ await expect(folderPage.configuration.auth).toBeVisible();
+ await expect(folderPage.configuration.auth).toContainText('Inherited from collection');
+ });
+
+ await test.step('the script group is shown', async () => {
+ await expect(folderPage.configuration.script).toBeVisible();
+ });
+ });
+
+ test('shows the Tests group when the folder defines folder-scoped tests', async ({ folderPage }) => {
+ await folderPage.open(['billing', 'customers']);
+ await expect(folderPage.title).toHaveText('customers');
+ await expect(folderPage.configuration.tests).toBeVisible();
+ });
+
+ test('renders the folder docs as markdown and collapses long content behind a "View more" toggle', async ({
+ folderPage
+ }) => {
+ await folderPage.open(['billing']);
+
+ await test.step('the markdown is rendered with formatting', async () => {
+ await expect(folderPage.folderMarkdownDocs).toBeVisible();
+ await expect(folderPage.folderMarkdownDocs).toContainText('Endpoints for managing');
+ await expect(folderPage.folderMarkdownDocs.locator('strong').first()).toHaveText('customers');
+ });
+
+ await test.step('long docs collapse to a preview with a "View more" toggle', async () => {
+ await expect(folderPage.folderMarkdownDocsToggle).toHaveText('View more');
+ await folderPage.folderMarkdownDocsToggle.click();
+ await expect(folderPage.folderMarkdownDocsToggle).toHaveText('View less');
+ });
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/layout/page-header.spec.ts b/packages/oc-docs/e2e/tests/layout/page-header.spec.ts
new file mode 100644
index 00000000..e5a74763
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/layout/page-header.spec.ts
@@ -0,0 +1,78 @@
+import { test, expect } from '../../playwright';
+
+/**
+ * The page header (sticky top navigation bar): brand cluster, Open-in-Bruno
+ * CTA and theme toggle. These tests cover what the mounted app actually
+ * renders — the search and env-switcher slots ship empty here, so they aren't
+ * exercised in this suite.
+ */
+test.use({ colorScheme: 'light' });
+
+const DESKTOP = { width: 1280, height: 900 };
+const MOBILE = { width: 390, height: 800 };
+
+test.describe('Page header', () => {
+ test('shows brand (name + version) and a pinned bar', async ({ page, pageHeader }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ await expect(pageHeader.root).toBeVisible();
+ await expect(pageHeader.brandName).toContainText('Bruno Testbench');
+ await expect(pageHeader.brandVersion).toHaveText('Version : 1.0.0');
+
+ // Sticky: header stays at the top after the page scrolls.
+ await page.mouse.wheel(0, 600);
+ const box = await pageHeader.root.boundingBox();
+ if (box === null) throw new Error('header has no bounding box');
+ expect(box.y).toBeLessThanOrEqual(1);
+ });
+
+ test('shows the initials avatar derived from the collection name', async ({ page, pageHeader }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ // sampleCollection name is "Bruno Testbench" → "BT".
+ await expect(pageHeader.brandInitials).toBeVisible();
+ await expect(pageHeader.brandInitials).toHaveText('BT');
+ });
+
+ test('shows the theme toggle in the header', async ({ page, themeToggle }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ await expect(themeToggle.button).toBeVisible();
+ });
+
+ test('shows the Open-in-Bruno CTA linking to Fetch-in-Bruno when the collection has a git url', async ({ page, pageHeader }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ await expect(pageHeader.openInBruno).toBeVisible();
+ const href = await pageHeader.openInBruno.getAttribute('href');
+ expect(href).toMatch(/^https:\/\/fetch\.usebruno\.com\?url=/);
+ expect(await pageHeader.openInBruno.getAttribute('target')).toBe('_blank');
+ expect(await pageHeader.openInBruno.getAttribute('rel')).toContain('noopener');
+ });
+
+ test('mobile condenses: hamburger shows, Open-in-Bruno becomes a glyph, brand compact', async ({ page, pageHeader }) => {
+ await page.setViewportSize(MOBILE);
+ await page.goto('/');
+
+ // Below desktop the sidebar trigger appears.
+ await expect(pageHeader.menuButton).toBeVisible();
+ // Open-in-Bruno condenses to the Bruno glyph below the desktop layout (the
+ // capability gate still hides it on real touch devices; this browser is
+ // pointer-capable, so the glyph shows). No full "Open in Bruno" label.
+ await expect(pageHeader.openInBruno).toBeVisible();
+ await expect(pageHeader.openInBruno).toHaveClass(/is-icon/);
+
+ // Compact brand: avatar + "Docs" only — no full name, no version.
+ await expect(pageHeader.brandName).toHaveText('Docs');
+ await expect(pageHeader.brandVersion).toHaveCount(0);
+ await expect(pageHeader.root).not.toContainText('Bruno Testbench');
+
+ // No horizontal overflow.
+ const scrollW = await page.evaluate(() => document.documentElement.scrollWidth);
+ expect(scrollW).toBeLessThanOrEqual(MOBILE.width + 1);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/overview/overview-documentation.spec.ts b/packages/oc-docs/e2e/tests/overview/overview-documentation.spec.ts
new file mode 100644
index 00000000..c60d13a3
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/overview/overview-documentation.spec.ts
@@ -0,0 +1,41 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Overview documentation (rendered Markdown)', () => {
+ test.beforeEach(async ({ overviewPage }) => {
+ await overviewPage.goto();
+ });
+
+ test('renders the "Getting Started", "Authentication" and "Rate Limits" section headings', async ({ overviewPage }) => {
+ const { docMarkdown } = overviewPage;
+ await expect(docMarkdown.heading('Getting Started')).toBeVisible();
+ await expect(docMarkdown.heading('Authentication')).toBeVisible();
+ await expect(docMarkdown.heading('Rate Limits')).toBeVisible();
+ });
+
+ test('renders the intro paragraph and shows the product name "OpenCollection" in bold', async ({ overviewPage }) => {
+ const { docMarkdown } = overviewPage;
+ await expect(docMarkdown.paragraph('comprehensive API collection for testing')).toBeVisible();
+ await expect(docMarkdown.boldText('OpenCollection')).toBeVisible();
+ });
+
+ test('renders the getting-started steps as an ordered list', async ({ overviewPage }) => {
+ const { docMarkdown } = overviewPage;
+ await expect(docMarkdown.numberedItem('Select an environment')).toBeVisible();
+ await expect(docMarkdown.numberedItem('Try out the various API endpoints')).toBeVisible();
+ await expect(docMarkdown.numberedItem('Check the response examples')).toBeVisible();
+ });
+
+ test('renders the environments table with its column headers and Local/Prod rows', async ({ overviewPage }) => {
+ const { docMarkdown } = overviewPage;
+ await expect(docMarkdown.table()).toBeVisible();
+ await expect(docMarkdown.columnHeader('Environment')).toBeVisible();
+ await expect(docMarkdown.columnHeader('Base URL')).toBeVisible();
+ await expect(docMarkdown.columnHeader('Auth')).toBeVisible();
+ await expect(docMarkdown.cell('Local')).toBeVisible();
+ await expect(docMarkdown.cell('Prod')).toBeVisible();
+ });
+
+ test('renders the example request as a fenced code block', async ({ overviewPage }) => {
+ await expect(overviewPage.docMarkdown.code('curl -H')).toBeVisible();
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/overview/overview.spec.ts b/packages/oc-docs/e2e/tests/overview/overview.spec.ts
new file mode 100644
index 00000000..853f94e3
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/overview/overview.spec.ts
@@ -0,0 +1,123 @@
+import { test, expect } from '../../playwright';
+import type { Locator } from '@playwright/test';
+
+const boundingBoxOf = async (locator: Locator) => {
+ const box = await locator.boundingBox();
+ if (box === null) throw new Error('expected the element to have a bounding box');
+ return box;
+};
+
+test.describe('Collection Overview', () => {
+ test.beforeEach(async ({ overviewPage }) => {
+ await overviewPage.goto();
+ });
+
+ test('header shows the collection version ("Version : 1.0.0") and name ("Bruno Testbench")', async ({ overviewPage }) => {
+ await test.step('the raw version is shown, unformatted', async () => {
+ await expect(overviewPage.header.collectionVersion).toHaveText('Version : 1.0.0');
+ });
+
+ await test.step('the collection name is shown as the page title', async () => {
+ await expect(overviewPage.header.collectionName).toHaveText('Bruno Testbench');
+ });
+ });
+
+ test('shows three stat cards with the request (41), folder (7) and environment (2) counts', async ({ overviewPage }) => {
+ await expect(overviewPage.stats.cards).toHaveCount(3);
+ await expect(overviewPage.stats.valueFor('Requests')).toHaveText('41');
+ await expect(overviewPage.stats.valueFor('Folders')).toHaveText('7');
+ await expect(overviewPage.stats.valueFor('Environments')).toHaveText('2');
+ });
+
+ test('renders the collection documentation under the "Overview" section', async ({ overviewPage }) => {
+ await expect(overviewPage.sectionLabel('Overview')).toBeVisible();
+ await expect(overviewPage.docMarkdown.root).toBeVisible();
+ await expect(overviewPage.docMarkdown.heading('Getting Started')).toBeVisible();
+ });
+
+ test.describe('Collection Configuration', () => {
+ test('shows the Headers, Auth, Variables, Script and Tests groups with their values', async ({ overviewPage }) => {
+ const { configuration } = overviewPage;
+ await expect(overviewPage.sectionLabel('Collection Configuration')).toBeVisible();
+
+ await test.step('the Headers group lists the collection-level header and its value', async () => {
+ await expect(configuration.subHeading('Headers')).toBeVisible();
+ await expect(configuration.root.getByText('collection-header-value')).toBeVisible();
+ });
+
+ await test.step('the Auth group shows the resolved auth mode (Bearer Token)', async () => {
+ await expect(configuration.subHeading('Auth')).toBeVisible();
+ await expect(configuration.root.getByText('Bearer Token')).toBeVisible();
+ });
+
+ await test.step('the Variables group lists the collection-level pre-request variables', async () => {
+ await expect(configuration.subHeading('Variables')).toBeVisible();
+ await expect(configuration.root.getByText('collection_pre_var_value', { exact: true })).toBeVisible();
+ await expect(configuration.root.getByText('collection-var-value', { exact: true })).toBeVisible();
+ });
+
+ await test.step('the Script and Tests groups are present', async () => {
+ await expect(configuration.subHeading('Script')).toBeVisible();
+ await expect(configuration.subHeading('Tests')).toBeVisible();
+ });
+ });
+
+ test('keeps the auth token masked until the reveal toggle is clicked', async ({ overviewPage }) => {
+ const { secret } = overviewPage.configuration;
+
+ await test.step('the token is shown as stars, not the raw value', async () => {
+ await expect(secret.value).toContainText('*');
+ await expect(secret.value).not.toHaveText('{{bearer_auth_token}}');
+ });
+
+ await test.step('clicking the reveal toggle shows the raw token', async () => {
+ await secret.toggleReveal();
+ await expect(secret.value).toHaveText('{{bearer_auth_token}}');
+ });
+ });
+
+ test('copies a config code snippet and confirms with a "Copied" label', async ({ overviewPage, context }) => {
+ await context.grantPermissions(['clipboard-read', 'clipboard-write']);
+ const { configuration } = overviewPage;
+
+ await test.step('clicking the copy button switches its label to "Copied"', async () => {
+ await configuration.copyToClipboard();
+ await expect(configuration.copyButton).toHaveAttribute('aria-label', 'Copied');
+ });
+ });
+ });
+
+ test('mobile: every Disabled chip stays pinned at the row end without overflowing', async ({ overviewPage, page }) => {
+ await page.setViewportSize({ width: 360, height: 800 });
+ const { configuration } = overviewPage;
+
+ const rows = configuration.disabledRows;
+ const count = await rows.count();
+ expect(count).toBeGreaterThan(0);
+
+ const card = await boundingBoxOf(configuration.root);
+
+ for (let i = 0; i < count; i += 1) {
+ const row = rows.nth(i);
+ const value = row.getByTestId('property-value');
+ const chip = await boundingBoxOf(row.getByTestId('disabled-badge'));
+ const valueBox = await boundingBoxOf(value);
+
+ await test.step(`row ${i}: the chip sits at the end — to the right of the value`, () => {
+ expect(chip.x).toBeGreaterThanOrEqual(valueBox.x + valueBox.width);
+ });
+
+ await test.step(`row ${i}: the chip stays within the config card, never clipped or overflowing`, () => {
+ expect(chip.x + chip.width).toBeLessThanOrEqual(card.x + card.width);
+ });
+
+ await test.step(`row ${i}: the value keeps its truncation styling, so a long value ellipsizes rather than pushing the chip off`, async () => {
+ const style = await value.evaluate((el) => {
+ const cs = getComputedStyle(el);
+ return { overflow: cs.overflow, textOverflow: cs.textOverflow, whiteSpace: cs.whiteSpace };
+ });
+ expect(style).toEqual({ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' });
+ });
+ }
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/dropdown-stacking.spec.ts b/packages/oc-docs/e2e/tests/playground/dropdown-stacking.spec.ts
new file mode 100644
index 00000000..15d3ae0e
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/dropdown-stacking.spec.ts
@@ -0,0 +1,61 @@
+import { test, expect } from '../../playwright';
+import { EnvSwitcherComponent } from '../../components/layout/env-switcher.component';
+import type { Locator } from '@playwright/test';
+
+/**
+ * Regression: the environment selector dropdown must stack above the playground
+ * docks in every dock mode. Its menu is portaled to with --z-popover so
+ * it clears the docks (all at or below --z-modal). We assert not just visibility
+ * but that the option is the topmost element at its own centre — a menu hidden
+ * behind a dock is "visible" to the DOM but not the hit-test.
+ */
+
+const DESKTOP = { width: 1280, height: 900 };
+
+const isTopmost = async (option: Locator): Promise => {
+ const box = await option.boundingBox();
+ if (!box) return false;
+ const x = box.x + box.width / 2;
+ const y = box.y + box.height / 2;
+ return option.page().evaluate(
+ ({ x, y }) => {
+ const el = document.elementFromPoint(x, y);
+ return !!el?.closest('[role="menu"]');
+ },
+ { x, y }
+ );
+};
+
+test.describe('env selector dropdown stacks above the docks', () => {
+ test.use({ viewport: DESKTOP });
+
+ for (const dock of ['inline', 'bottom'] as const) {
+ test(`top-nav env dropdown clears the ${dock} dock`, async ({ page, playground }) => {
+ await playground.open(dock);
+ await expect(playground.panel(dock)).toBeVisible();
+
+ const envSwitcher = new EnvSwitcherComponent(page);
+ await envSwitcher.open();
+
+ await expect(envSwitcher.menu).toBeVisible();
+ await expect(envSwitcher.option('Prod')).toBeVisible();
+ expect(await isTopmost(envSwitcher.option('Prod'))).toBe(true);
+ });
+ }
+
+ test('playground env dropdown clears the modal dock', async ({ page, playground }) => {
+ await playground.open('modal');
+ await expect(playground.modalPanel).toBeVisible();
+
+ // The playground env switcher lives in the playground sidebar, so it must be
+ // on screen before we can open it.
+ await expect(playground.sidebarPanel).toBeVisible();
+
+ const envSwitcher = new EnvSwitcherComponent(page, 'playground-env-switcher');
+ await envSwitcher.open();
+
+ await expect(envSwitcher.menu).toBeVisible();
+ await expect(envSwitcher.option('Prod')).toBeVisible();
+ expect(await isTopmost(envSwitcher.option('Prod'))).toBe(true);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/env-add-variable.spec.ts b/packages/oc-docs/e2e/tests/playground/env-add-variable.spec.ts
new file mode 100644
index 00000000..50e5938d
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/env-add-variable.spec.ts
@@ -0,0 +1,21 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Environment variables — adding rows (card view)', () => {
+ test.use({ viewport: { width: 1400, height: 900 } });
+
+ test('a filled name and value in the trailing blank card adds a new variable row', async ({ playground, envEditor }) => {
+ await playground.open('inline');
+ await playground.openEnvironments();
+
+ await expect(envEditor.nameInputs.first()).toBeVisible();
+ const before = await envEditor.nameInputs.count();
+
+ await envEditor.nameInputs.last().fill('newVariable');
+ await expect(envEditor.nameInputs).toHaveCount(before);
+
+ await envEditor.valueInputs.last().fill('newValue');
+ await expect(envEditor.nameInputs).toHaveCount(before + 1);
+ await expect(envEditor.nameInputs.nth(before - 1)).toHaveValue('newVariable');
+ await expect(envEditor.valueInputs.nth(before - 1)).toHaveValue('newValue');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/keyvalue-table.spec.ts b/packages/oc-docs/e2e/tests/playground/keyvalue-table.spec.ts
new file mode 100644
index 00000000..ecf07b77
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/keyvalue-table.spec.ts
@@ -0,0 +1,59 @@
+import { test, expect } from '../../playwright';
+
+test.describe('KeyValueTable — tooltips & mobile scroll', () => {
+ test.beforeEach(async ({ page, playground }) => {
+ await page.goto('/#/?pg=1&dock=bottom');
+ await playground.openSidebarItem('get users');
+ await playground.selectTab('headers');
+ await expect(playground.keyValueTable.root).toBeVisible();
+ });
+
+ test('a typed cell carries a native title tooltip with its full value', async ({ page, playground }) => {
+ const { keyValueTable } = playground;
+ const nameInput = keyValueTable.nameInputs.first();
+ await nameInput.click();
+ await page.keyboard.type('-A-Very-Long-Custom-Header-Name-That-Truncates');
+ // The full value is exposed as a native title tooltip so a truncated cell stays readable.
+ const value = await nameInput.inputValue();
+ expect(value.length).toBeGreaterThan(0);
+ await expect(nameInput).toHaveAttribute('title', value);
+ });
+
+ test('the table has a min-width and a horizontally-scrollable container', async ({ page, playground }) => {
+ const { keyValueTable } = playground;
+ await expect(keyValueTable.container).toHaveCSS('overflow-x', 'auto');
+ await expect(keyValueTable.table).toHaveCSS('min-width', '448px'); // 28rem @16px
+
+ // Narrow the viewport below the min-width → the container actually overflows and scrolls.
+ await page.setViewportSize({ width: 360, height: 800 });
+ const overflows = await keyValueTable.container.evaluate((el) => el.scrollWidth > el.clientWidth + 1);
+ expect(overflows).toBe(true);
+ });
+
+ test('offers {{variable}} autocomplete in the value cell but not the name cell', async ({ page, playground }) => {
+ const { keyValueTable } = playground;
+ // Value cell: a `{{` reference surfaces the collection's variables.
+ await keyValueTable.valueInputs.last().click();
+ await page.keyboard.type('{{coll');
+ await expect(keyValueTable.autocomplete).toBeVisible();
+
+ await page.keyboard.press('Escape');
+ await expect(keyValueTable.autocomplete).toHaveCount(0);
+
+ // Name cell: the same reference must not open the dropdown — the app only
+ // autocompletes variables in value cells, never in param/variable name cells.
+ await keyValueTable.nameInputs.last().click();
+ await page.keyboard.type('{{coll');
+ await page.waitForTimeout(250);
+ await expect(keyValueTable.autocomplete).toHaveCount(0);
+ });
+
+ test('flags a header name that contains a space with an inline error', async ({ page, playground }) => {
+ const { keyValueTable } = playground;
+ await keyValueTable.nameInputs.last().click();
+ await page.keyboard.type('Bad Name');
+ const error = keyValueTable.cellErrors.first();
+ await expect(error).toBeVisible();
+ await expect(error).toHaveAttribute('aria-label', 'Header name cannot contain spaces or newlines');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/playground-examples.spec.ts b/packages/oc-docs/e2e/tests/playground/playground-examples.spec.ts
new file mode 100644
index 00000000..0056ddba
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/playground-examples.spec.ts
@@ -0,0 +1,104 @@
+import { test, expect } from '../../playwright';
+
+const openAt = (dock: string): string => `/#/?pg=1&dock=${dock}`;
+const LIST_USERS_EXAMPLE = 'List Users';
+const LIST_USERS_SLUG = 'list-users';
+const UNAUTHORIZED_EXAMPLE = 'Unauthorized';
+
+test.describe('Playground - Examples', () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto(openAt('bottom'));
+ });
+
+ test('expanding a request in the sidebar reveals its examples', async ({ playground }) => {
+ await expect(playground.exampleToggle('get users')).toBeVisible();
+ await expect(playground.exampleRow(LIST_USERS_EXAMPLE)).toHaveCount(0);
+
+ await playground.exampleToggle('get users').click();
+
+ await expect(playground.exampleRow(LIST_USERS_EXAMPLE)).toBeVisible();
+ await expect(playground.exampleRow(UNAUTHORIZED_EXAMPLE)).toBeVisible();
+ });
+
+ test('selecting an example shows a read-only example view with the expected status', async ({ playground }) => {
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(LIST_USERS_EXAMPLE).click();
+
+ const exampleView = playground.exampleView;
+ await expect(exampleView).toBeVisible();
+ await expect(exampleView).toContainText('200');
+ await expect(exampleView).toContainText('OK');
+
+ // Only the example row is highlighted, not its parent request row.
+ await expect(playground.exampleRow(LIST_USERS_EXAMPLE)).toHaveClass(/active/);
+ await expect(playground.treeItems.filter({ hasText: 'get users' })).not.toHaveClass(/active/);
+ await expect(playground.exampleViewRequest).toBeVisible();
+ await expect(playground.exampleViewResponse).toBeVisible();
+
+ // Read-only: no editable form controls anywhere in the example view.
+ await expect(playground.exampleViewControls).toHaveCount(0);
+ });
+
+ test('switching to another example updates the view to its own status and stays read-only', async ({ playground }) => {
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(UNAUTHORIZED_EXAMPLE).click();
+
+ const exampleView = playground.exampleView;
+ await expect(exampleView).toContainText('401');
+ await expect(exampleView).toContainText('Unauthorized');
+ await expect(playground.exampleViewControls).toHaveCount(0);
+ });
+
+ test('deep-links the example: pgEx in the url, reload restores the example view', async ({ page, playground }) => {
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(LIST_USERS_EXAMPLE).click();
+ await expect(playground.exampleView).toBeVisible();
+ await expect(page).toHaveURL(new RegExp(`[?&]pgEx=${LIST_USERS_SLUG}(?:&|$)`));
+
+ await page.reload();
+ await expect(playground.exampleView).toBeVisible();
+ await expect(playground.exampleView).toContainText('200');
+ });
+
+ test('an unknown example slug in the url falls back to the live request and stays open', async ({ page, playground }) => {
+ // Open a real example to obtain its request slug, then swap in a bogus pgEx.
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(LIST_USERS_EXAMPLE).click();
+ await expect(playground.exampleView).toBeVisible();
+
+ const stale = page.url().replace(`pgEx=${LIST_USERS_SLUG}`, 'pgEx=does-not-exist');
+ await page.goto(stale);
+
+ // Unmatched example: no example view, the live request opens instead, no crash.
+ await expect(playground.runner).toBeVisible();
+ await expect(playground.exampleView).toHaveCount(0);
+ await expect(page).toHaveURL(/[?&]pgReq=/);
+ });
+
+ test('switching docks keeps the example view and its pgEx in the url', async ({ page, playground }) => {
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(LIST_USERS_EXAMPLE).click();
+ await expect(playground.exampleView).toBeVisible();
+ await expect(page).toHaveURL(new RegExp(`[?&]pgEx=${LIST_USERS_SLUG}(?:&|$)`));
+
+ // A dock switch is presentation only: the example must survive it.
+ await playground.selectDock('modal');
+ await expect(playground.panel('modal')).toBeVisible();
+ await expect(playground.exampleView).toBeVisible();
+ await expect(playground.exampleView).toContainText('200');
+ await expect(page).toHaveURL(new RegExp(`[?&]pgEx=${LIST_USERS_SLUG}(?:&|$)`));
+ });
+
+ test('browser back and forward move between examples in the playground', async ({ page, playground }) => {
+ await playground.exampleToggle('get users').click();
+ await playground.exampleRow(LIST_USERS_EXAMPLE).click();
+ await expect(playground.exampleView).toContainText('200');
+ await playground.exampleRow(UNAUTHORIZED_EXAMPLE).click();
+ await expect(playground.exampleView).toContainText('401');
+
+ await page.goBack();
+ await expect(playground.exampleView).toContainText('200');
+ await page.goForward();
+ await expect(playground.exampleView).toContainText('401');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/playground-mobile.spec.ts b/packages/oc-docs/e2e/tests/playground/playground-mobile.spec.ts
new file mode 100644
index 00000000..0957c2ef
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/playground-mobile.spec.ts
@@ -0,0 +1,48 @@
+import { test, expect } from '../../playwright';
+
+// A phone user agent flips useIsMobilePhone to true (it reads navigator.userAgent,
+// not the viewport). The viewport is set to a phone size for realism.
+const IPHONE_UA =
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
+
+// The dock param is ignored on a phone (MobileDock renders regardless); a
+// non-default dock is used here to prove it is overridden.
+const OPEN_ON_PHONE = '/#/?pg=1&dock=bottom';
+
+test.describe('playground on a phone', () => {
+ test.use({ userAgent: IPHONE_UA, viewport: { width: 390, height: 844 } });
+
+ test('opens fullscreen with no dock switcher or collapse', async ({ page, playground }) => {
+ await page.goto(OPEN_ON_PHONE);
+ await expect(playground.mobilePanel).toBeVisible();
+ await expect(playground.runner).toBeVisible();
+ await expect(playground.switcher).toHaveCount(0);
+ await expect(playground.collapseButton).toHaveCount(0);
+ await expect(playground.sidebarToggle).toBeVisible();
+ await expect(playground.closeButton).toBeVisible();
+ // The desktop dock shells never mount on a phone.
+ await expect(playground.bottomPanel).toHaveCount(0);
+ });
+
+ test('sidebar is an overlay: starts closed, opens on toggle, closes on navigate', async ({ page, playground }) => {
+ await page.goto(OPEN_ON_PHONE);
+ await expect(playground.mobilePanel).toBeVisible();
+ await expect(playground.sidebarPanel).toHaveCount(0);
+
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toBeVisible();
+
+ // Opening the environments view is a navigate; the overlay sidebar closes.
+ await playground.gear.click();
+ await expect(playground.sidebarPanel).toHaveCount(0);
+ });
+
+ test('closes from the header and clears the url state', async ({ page, playground }) => {
+ await page.goto(OPEN_ON_PHONE);
+ await expect(playground.mobilePanel).toBeVisible();
+
+ await playground.close();
+ await expect(playground.header).toHaveCount(0);
+ await expect(page).toHaveURL(/#\/$/);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/playground.spec.ts b/packages/oc-docs/e2e/tests/playground/playground.spec.ts
new file mode 100644
index 00000000..d20af77b
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/playground.spec.ts
@@ -0,0 +1,289 @@
+import { test, expect } from '../../playwright';
+
+const DESKTOP = { width: 1280, height: 900 };
+const openAt = (dock: string, pgReq?: string): string =>
+ `/#/?pg=1&dock=${dock}${pgReq ? `&pgReq=${pgReq}` : ''}`;
+
+test.describe('playground docks (desktop)', () => {
+ test.use({ viewport: DESKTOP });
+
+ test('opens in the bottom dock from a deep link and embeds the playground', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.header).toBeVisible();
+ await expect(playground.bottomPanel).toBeVisible();
+ await expect(playground.runner).toBeVisible();
+ });
+
+ test('switches between docks from the switcher and marks the active one', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.dockButton('bottom')).toHaveClass(/active/);
+
+ await playground.selectDock('inline');
+ await expect(playground.inlinePanel).toBeVisible();
+ await expect(playground.dockButton('inline')).toHaveClass(/active/);
+
+ await playground.selectDock('modal');
+ await expect(playground.modalPanel).toBeVisible();
+ await expect(playground.dockButton('modal')).toHaveClass(/active/);
+ });
+
+ test('inline dock reflows alongside the docs sidebar and content', async ({ page, playground, sidebar }) => {
+ // Wide viewport so the docs column stays >=1024 (desktop) alongside the
+ // inline dock; at narrower widths the docs sidebar collapses to a drawer.
+ await page.setViewportSize({ width: 1920, height: 900 });
+ await page.goto(openAt('inline'));
+ await expect(sidebar.inline).toBeVisible();
+ await expect(page.getByTestId('page')).toBeVisible();
+ await expect(playground.inlinePanel).toBeVisible();
+ });
+
+ test('closes from the header and clears the url state', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.bottomPanel).toBeVisible();
+
+ await playground.close();
+ await expect(playground.header).toHaveCount(0);
+ await expect(page).toHaveURL(/#\/$/);
+ });
+
+ test('collapses the bottom dock to its header, then restores it', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.content).toBeVisible();
+
+ await playground.toggleCollapse();
+ await expect(playground.content).toHaveCount(0);
+ await expect(playground.header).toBeVisible();
+
+ await playground.toggleCollapse();
+ await expect(playground.content).toBeVisible();
+ });
+
+ test('opens from the Try button and embeds the playground', async ({ requestPage, playground, page }) => {
+ await requestPage.open(['billing', 'customers', 'Get Customers - Filter by Date Range']);
+ await requestPage.urlBar.tryButton.click();
+ await expect(playground.header).toBeVisible();
+ await expect(page).toHaveURL(/pg=1/);
+ await expect(playground.runner).toBeVisible();
+ });
+
+ // Regression: reopening a request after navigating away from it (to the gear /
+ // Environments) then closing must re-apply the request, not reopen on the
+ // stale Environments/empty view. The applied-slug guard has to reset on close.
+ test('reopening a request after leaving it for Environments shows the request again', async ({
+ requestPage,
+ playground,
+ }) => {
+ await requestPage.open(['billing', 'customers', 'Get Customers - Filter by Date Range']);
+
+ // Open request A in the playground.
+ await requestPage.urlBar.tryButton.click();
+ await expect(playground.view).toContainText('Get Customers');
+
+ // Leave it: open the Environments view via the gear.
+ await playground.gear.click();
+ await expect(playground.view).toContainText('Environments');
+
+ // Close, then reopen the SAME request in-session (no reload) via Try.
+ await playground.close();
+ await expect(playground.header).toHaveCount(0);
+ await requestPage.urlBar.tryButton.click();
+
+ // It must show request A again, not the Environments view it was left on.
+ await expect(playground.header).toBeVisible();
+ await expect(playground.view).toContainText('Get Customers');
+ await expect(playground.view).not.toContainText('Environments');
+ });
+
+ test('sidebar shows the collection node, env switcher, gear and tree', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ await expect(playground.collectionNode).toBeVisible();
+ await expect(playground.envSwitcher).toBeVisible();
+ await expect(playground.gear).toBeVisible();
+ await expect(playground.treeItems.first()).toBeVisible();
+ });
+
+ test('header toggle hides and restores the playground sidebar', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ await expect(playground.sidebarToggle).toHaveAttribute('aria-pressed', 'true');
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toHaveCount(0);
+ await expect(playground.sidebarToggle).toHaveAttribute('aria-pressed', 'false');
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toBeVisible();
+ await expect(playground.sidebarToggle).toHaveAttribute('aria-pressed', 'true');
+ });
+
+ test('clicking a request in the sidebar loads it, gear opens environments', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await playground.treeItems.filter({ hasText: 'get users' }).first().click();
+ await expect(page).toHaveURL(/pgReq=/);
+ await expect(playground.view).toContainText('get users');
+
+ await playground.gear.click();
+ await expect(playground.view).toContainText('Environments');
+ });
+
+ test('clicking the collection root opens the collection view', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await playground.collectionRootLink.click();
+ await expect(playground.view).toContainText(/Overview|Headers|Vars|Auth|Scripts|Tests/);
+ });
+
+ // Clicking a folder row opens its settings AND expands it in the tree (matches
+ // docs), so its children become visible; the chevron alone toggles collapse.
+ test('clicking a folder opens its settings and expands it in the tree', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ // customers is nested under the collapsed billing folder, so it is hidden.
+ await expect(playground.treeItems.filter({ hasText: /^customers$/ })).toHaveCount(0);
+ await playground.treeItems.filter({ hasText: /^billing$/ }).first().click();
+ // billing expands: its child folder is revealed and the URL carries the folder.
+ await expect(playground.treeItems.filter({ hasText: /^customers$/ }).first()).toBeVisible();
+ await expect(page).toHaveURL(/pgReq=billing(?!%2F)/);
+ });
+
+ // Clicking the collection root re-expands the tree too, not just opens the view.
+ test('clicking the collection root re-expands the tree', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ // Collapse the collection from its chevron -> top-level items disappear.
+ await playground.collectionCollapseToggle.click();
+ await expect(playground.treeItems.filter({ hasText: /^billing$/ })).toHaveCount(0);
+ // Clicking the root row brings the tree back and shows the collection view.
+ await playground.collectionRootLink.click();
+ await expect(playground.treeItems.filter({ hasText: /^billing$/ }).first()).toBeVisible();
+ await expect(playground.view).toContainText(/Overview|Headers|Vars|Auth|Scripts|Tests/);
+ });
+
+ // Regression: an example keeps the URL slug on its parent request, so clicking
+ // that request row must still leave the example and show the request view.
+ test('clicking a request while its example is open returns to the request view', async ({ page, playground }) => {
+ await page.goto(openAt('bottom', 'billing/customers/get-all-customers'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ // Open the request's examples and select one -> example view.
+ await playground.exampleToggle('Get All Customers').click();
+ await playground.exampleRow('200 OK - first page').click();
+ await expect(playground.exampleView).toBeVisible();
+ // Clicking the parent request row leaves the example for the request view,
+ // even though the URL slug stays on that same request.
+ await playground.treeItems.filter({ hasText: 'Get All Customers' }).first().click();
+ await expect(playground.exampleView).toHaveCount(0);
+ await expect(playground.view).toContainText('Get All Customers');
+ });
+
+ test('inline dock: sidebar is closed by default and overlays the view when opened', async ({ page, playground }) => {
+ await page.goto(openAt('inline'));
+ await expect(playground.sidebarPanel).toHaveCount(0); // closed by default in inline
+ await playground.sidebarToggle.click(); // open it as an overlay
+ await expect(playground.sidebarPanel).toBeVisible();
+ await expect(playground.view).toBeVisible();
+ const viewBox = await playground.view.boundingBox();
+ const sideBox = await playground.sidebarPanel.boundingBox();
+ // overlay: sidebar starts at (or within 5px of) the view's left edge, not to its left
+ expect(sideBox!.x).toBeLessThanOrEqual(viewBox!.x + 5);
+ expect(viewBox!.x).toBeLessThanOrEqual(sideBox!.x + 5);
+ });
+
+ test('inline dock: clicking outside the overlay sidebar closes it', async ({ page, playground }) => {
+ await page.goto(openAt('inline'));
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toBeVisible();
+ // Click the view area outside the sidebar (its backdrop), mirroring the docs
+ // navigation drawer: an outside click dismisses the overlay. The backdrop
+ // spans the whole dock from its left edge, so click just past the sidebar's
+ // right edge to land on the exposed view area, not the panel.
+ const side = await playground.sidebarPanel.boundingBox();
+ await playground.sidebarBackdrop.click({ position: { x: side!.width + 40, y: 30 } });
+ await expect(playground.sidebarPanel).toHaveCount(0);
+ });
+
+ test('inline dock: clicking outside the playground closes the overlay sidebar', async ({ page, playground }) => {
+ // Wide viewport so the docs column stays desktop and is clickable to the
+ // left of the inline dock (rather than collapsing to a drawer).
+ await page.setViewportSize({ width: 1920, height: 900 });
+ await page.goto(openAt('inline'));
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toBeVisible();
+ // Click the docs page, entirely outside the playground dock.
+ await page.getByTestId('page').click({ position: { x: 100, y: 300 } });
+ await expect(playground.sidebarPanel).toHaveCount(0);
+ });
+
+ test('inline dock: selecting a request auto-closes the overlay sidebar', async ({ page, playground }) => {
+ await page.goto(openAt('inline'));
+ await playground.sidebarToggle.click();
+ await expect(playground.sidebarPanel).toBeVisible();
+ await playground.treeItems.filter({ hasText: 'get users' }).first().click();
+ await expect(playground.sidebarPanel).toHaveCount(0); // auto-closed on select
+ await expect(playground.view).toContainText('get users');
+ });
+
+ test('request and response stack when the playground is narrow and sit side-by-side when wide', async ({ page, playground }) => {
+ // bottom dock is full width -> side by side
+ await page.goto(openAt('bottom'));
+ await playground.treeItems.filter({ hasText: 'get users' }).first().click();
+ // assert horizontal: playground view is visible and rendered without error
+ await expect(page.getByTestId('playground-view')).toBeVisible();
+
+ // inline dock (narrowest placement) -> stacked orientation when viewport is narrow
+ await playground.selectDock('inline');
+ await expect(page.getByTestId('playground-view')).toBeVisible();
+ });
+
+ test('playground stays open when navigating docs pages', async ({ page, playground }) => {
+ // Inline dock keeps the playground on the right, so the docs sidebar on the
+ // left is unobstructed (the bottom dock would overlap the lower tree rows).
+ // Wide viewport so the docs column stays desktop (inline sidebar visible to
+ // click) rather than collapsing to a drawer.
+ await page.setViewportSize({ width: 1920, height: 900 });
+ await page.goto(openAt('inline'));
+ await expect(playground.header).toBeVisible();
+ // click a docs sidebar item (the docs sidebar, not the playground one)
+ await page.getByTestId('sidebar').getByTestId('sidebar-item').first().click();
+ await expect(playground.header).toBeVisible(); // playground did NOT close
+ await expect(page).toHaveURL(/pg=1/); // playground params preserved
+ });
+
+ test('deep-link / reload to a nested request reveals its ancestor folders', async ({ page, playground }) => {
+ await page.goto(openAt('bottom', 'billing/customers/get-all-customers'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ // billing + customers auto-expand, so the request row is rendered in the tree.
+ await expect(playground.treeItems.filter({ hasText: 'Get All Customers' }).first()).toBeVisible();
+ // Still revealed after a full reload while sitting on the request.
+ await page.reload();
+ await expect(playground.treeItems.filter({ hasText: 'Get All Customers' }).first()).toBeVisible();
+ });
+
+ // Opening a folder / environments / collection-settings must persist in the URL
+ // (pgReq) so a reload restores that view instead of snapping back to the request.
+ test('opening a folder persists in the url and survives reload', async ({ page, playground }) => {
+ await page.goto(openAt('bottom', 'billing/customers/get-all-customers'));
+ await expect(playground.sidebarPanel).toBeVisible();
+ await playground.treeItems.filter({ hasText: /^billing$/ }).first().click();
+ // pgReq switches to the folder slug (billing), no longer the request path.
+ await expect(page).toHaveURL(/pgReq=billing(?!%2Fcustomers)/);
+ await page.reload();
+ await expect(page).toHaveURL(/pgReq=billing(?!%2Fcustomers)/);
+ await expect(playground.view).toBeVisible();
+ });
+
+ test('opening environments persists in the url and survives reload', async ({ page, playground }) => {
+ await page.goto(openAt('bottom', 'billing/customers/get-all-customers'));
+ await playground.gear.click();
+ await expect(page).toHaveURL(/pgReq=(~|%7E)environments/);
+ await page.reload();
+ await expect(page).toHaveURL(/pgReq=(~|%7E)environments/);
+ await expect(playground.view).toBeVisible();
+ });
+
+ test('opening collection settings persists in the url and survives reload', async ({ page, playground }) => {
+ await page.goto(openAt('bottom', 'billing/customers/get-all-customers'));
+ await playground.collectionNode.click();
+ await expect(page).toHaveURL(/pgReq=(~|%7E)collection/);
+ await page.reload();
+ await expect(page).toHaveURL(/pgReq=(~|%7E)collection/);
+ await expect(playground.view).toBeVisible();
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/request-body.spec.ts b/packages/oc-docs/e2e/tests/playground/request-body.spec.ts
new file mode 100644
index 00000000..b3541a30
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/request-body.spec.ts
@@ -0,0 +1,28 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Request body types', () => {
+ test.beforeEach(async ({ page, playground }) => {
+ await playground.open('bottom');
+ await playground.openRequest('get users');
+ await expect(page).toHaveURL(/pgReq=/);
+ await playground.selectTab('body');
+ });
+
+ test('selecting Multipart Form shows the multipart field editor', async ({ requestBody }) => {
+ await requestBody.selectType('multipart-form');
+ await expect(requestBody.multipart).toBeVisible();
+ });
+
+ test('selecting File / Binary shows the referenced-path view', async ({ requestBody }) => {
+ await requestBody.selectType('file');
+ await expect(requestBody.file).toBeVisible();
+ });
+
+ test('switching back to None clears the editor to the empty prompt', async ({ requestBody }) => {
+ await requestBody.selectType('multipart-form');
+ await expect(requestBody.multipart).toBeVisible();
+ await requestBody.selectType('none');
+ await expect(requestBody.empty).toBeVisible();
+ await expect(requestBody.multipart).toHaveCount(0);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/playground/unsupported-request.spec.ts b/packages/oc-docs/e2e/tests/playground/unsupported-request.spec.ts
new file mode 100644
index 00000000..6c3667a8
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/playground/unsupported-request.spec.ts
@@ -0,0 +1,35 @@
+import { test, expect } from '../../playwright';
+
+const DESKTOP = { width: 1280, height: 900 };
+const openAt = (dock: string): string => `/#/?pg=1&dock=${dock}`;
+
+const UNSUPPORTED = [
+ { paths: ['Realtime', 'Live Updates'], name: 'Live Updates', typeLabel: 'Websocket' },
+ { paths: ['Realtime', 'GraphQL API'], name: 'GraphQL API', typeLabel: 'GraphQL' },
+ { paths: ['Realtime', 'Order Service'], name: 'Order Service', typeLabel: 'gRPC' }
+];
+
+test.describe('Playground — unsupported request types', () => {
+ test.use({ viewport: DESKTOP });
+
+ for (const { paths, name, typeLabel } of UNSUPPORTED) {
+ test(`shows a "not supported" notice when a ${typeLabel} request is opened`, async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await playground.openTreeItem(paths);
+
+ await expect(playground.unsupported).toBeVisible();
+ await expect(playground.unsupportedIcon).toBeVisible();
+ await expect(playground.unsupportedTitle).toHaveText(name);
+ await expect(playground.unsupportedMessage).toContainText('Request type not supported');
+ await expect(playground.unsupportedMessage).toContainText(`${typeLabel} isn't currently supported in this playground`);
+ });
+ }
+
+ test('does not render request docs inside the playground (showRequestDocs is off)', async ({ page, playground }) => {
+ await page.goto(openAt('bottom'));
+ await playground.openTreeItem(['Realtime', 'Live Updates']);
+
+ await expect(playground.unsupported).toBeVisible();
+ await expect(playground.view.getByTestId('overview-markdown-documentation')).toHaveCount(0);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/request/request-details.spec.ts b/packages/oc-docs/e2e/tests/request/request-details.spec.ts
new file mode 100644
index 00000000..6ebb9ef1
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/request/request-details.spec.ts
@@ -0,0 +1,104 @@
+import { test, expect } from '../../playwright';
+
+const FILTER_BY_DATE_RANGE = ['billing', 'customers', 'Get Customers - Filter by Date Range'];
+
+test.describe('Request page — Details', () => {
+ test.beforeEach(async ({ requestPage }) => {
+ await requestPage.open(FILTER_BY_DATE_RANGE);
+ });
+
+ test.describe('Breadcrumb', () => {
+ test('shows the folder paths to the request', async ({ requestPage }) => {
+ const { breadcrumb } = requestPage;
+ await expect(breadcrumb.segment('billing')).toBeVisible();
+ await expect(breadcrumb.segment('customers')).toBeVisible();
+ await expect(breadcrumb.current).toHaveText('Get Customers - Filter by Date Range');
+ });
+
+ test('returns to a parent folder when its segment is clicked', async ({ requestPage, page }) => {
+ await requestPage.breadcrumb.segment('customers').click();
+ await expect(page.getByTestId('folder-page')).toBeVisible();
+ await expect(page.getByTestId('folder-title')).toHaveText('customers');
+ });
+ });
+
+ test('shows the request name as the page title', async ({ requestPage }) => {
+ await expect(requestPage.title).toHaveText('Get Customers - Filter by Date Range');
+ });
+
+ test('shows the GET method and the request URL', async ({ requestPage }) => {
+ await expect(requestPage.urlBar.method).toHaveText('GET');
+ await expect(requestPage.urlBar.url).toContainText('{{baseUrl}}/billing/customers');
+ });
+
+ test('offers a "Try" action to open the request in the playground', async ({ requestPage }) => {
+ await expect(requestPage.urlBar.tryButton).toBeVisible();
+ });
+
+ test('renders the request description', async ({ requestPage }) => {
+ await expect(requestPage.description).toContainText('Retrieves customers created within a date range.');
+ });
+
+ test.describe('Params section', () => {
+ test('lists the query parameters', async ({ requestPage }) => {
+ const params = requestPage.section('Params');
+ await expect(params).toBeVisible();
+ await expect(params.getByText('created[gte]')).toBeVisible();
+ await expect(params.getByText('created[lte]')).toBeVisible();
+ await expect(params.getByText('per_page')).toBeVisible();
+ });
+
+ test('shows each parameter value', async ({ requestPage }) => {
+ const params = requestPage.section('Params');
+ await expect(params.getByText('2024-01-01')).toBeVisible();
+ await expect(params.getByText('2024-12-31')).toBeVisible();
+ });
+ });
+
+ test.describe('Auth section', () => {
+ test('shows the auth mode inherited from the collection', async ({ requestPage }) => {
+ const auth = requestPage.section('Auth');
+ await expect(auth).toBeVisible();
+ await expect(auth.getByText('Inherited from collection')).toBeVisible();
+ await expect(auth.getByText('Bearer Token')).toBeVisible();
+ });
+ });
+
+ test.describe('Code snippet', () => {
+ test('shows a cURL command by default', async ({ requestPage }) => {
+ const { codeSnippet } = requestPage;
+ await expect(codeSnippet.languageTab('curl')).toHaveAttribute('aria-selected', 'true');
+ await expect(codeSnippet.code).toContainText('curl');
+ await expect(codeSnippet.code).toContainText('/billing/customers');
+ });
+
+ test('switches to the Python snippet when its tab is selected', async ({ requestPage }) => {
+ const { codeSnippet } = requestPage;
+ await codeSnippet.selectLanguage('python');
+ await expect(codeSnippet.languageTab('python')).toHaveAttribute('aria-selected', 'true');
+ await expect(codeSnippet.code).toContainText('requests');
+ });
+
+ test('the expanded view opens on the same language currently selected inline', async ({ requestPage }) => {
+ const { codeSnippet } = requestPage;
+ await codeSnippet.selectLanguage('python');
+ await codeSnippet.openExpandedView();
+ await expect(codeSnippet.modalLanguageTab('python')).toHaveAttribute('aria-selected', 'true');
+ });
+
+ test('switching the language in the modal does not change the language tab in the request details', async ({ requestPage }) => {
+ const { codeSnippet } = requestPage;
+ await expect(codeSnippet.languageTab('curl')).toHaveAttribute('aria-selected', 'true');
+
+ await codeSnippet.openExpandedView();
+ await codeSnippet.selectModalLanguage('python');
+
+ await expect(codeSnippet.modalLanguageTab('python')).toHaveAttribute('aria-selected', 'true');
+ await expect(codeSnippet.modalCode).toContainText('requests');
+
+ await expect(codeSnippet.languageTab('curl')).toHaveAttribute('aria-selected', 'true');
+ await expect(codeSnippet.languageTab('python')).toHaveAttribute('aria-selected', 'false');
+ await expect(codeSnippet.code).toContainText('curl');
+ });
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/request/request-examples.spec.ts b/packages/oc-docs/e2e/tests/request/request-examples.spec.ts
new file mode 100644
index 00000000..309f2f5d
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/request/request-examples.spec.ts
@@ -0,0 +1,61 @@
+import { test, expect } from '../../playwright';
+
+const GET_ALL_CUSTOMERS = ['billing', 'customers', 'Get All Customers'];
+const OK_EXAMPLE = '200 OK - first page';
+const BAD_REQUEST_EXAMPLE = '400 Bad Request - invalid per_page';
+
+test.describe('Request page — Examples', () => {
+ test.beforeEach(async ({ requestPage }) => {
+ await requestPage.open(GET_ALL_CUSTOMERS);
+ });
+
+ test('lists every saved example', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await expect(examples.root).toBeVisible();
+ await expect(examples.items).toHaveCount(2);
+ await expect(examples.example(OK_EXAMPLE)).toBeVisible();
+ await expect(examples.example(BAD_REQUEST_EXAMPLE)).toBeVisible();
+ });
+
+ test('shows the status code of each example', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await expect(examples.statusCode(OK_EXAMPLE)).toHaveText('200');
+ await expect(examples.statusCode(BAD_REQUEST_EXAMPLE)).toHaveText('400');
+ });
+
+ test.describe('Request pane', () => {
+ test('shows the query parameters by default', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await expect(examples.requestBody(OK_EXAMPLE)).toContainText('per_page');
+ await expect(examples.requestBody(OK_EXAMPLE)).toContainText('10');
+ });
+
+ test('switches to the Headers tab to reveal the request headers', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await examples.selectRequestTab(OK_EXAMPLE, 'headers');
+ await expect(examples.requestBody(OK_EXAMPLE)).toContainText('Accept');
+ await expect(examples.requestBody(OK_EXAMPLE)).toContainText('application/json');
+ });
+ });
+
+ test.describe('Response pane', () => {
+ test('shows the response body by default', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await expect(examples.responseBody(OK_EXAMPLE)).toContainText('cus_ABC123xyz');
+ await expect(examples.responseBody(OK_EXAMPLE)).toContainText('john.smith@example.com');
+ });
+
+ test('switches to the Headers tab to reveal the response headers', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await examples.selectResponseTab(OK_EXAMPLE, 'headers');
+ await expect(examples.responseBody(OK_EXAMPLE)).toContainText('x-total-count');
+ await expect(examples.responseBody(OK_EXAMPLE)).toContainText('42');
+ });
+ });
+
+ test('expands a collapsed example to reveal its response', async ({ requestPage }) => {
+ const { examples } = requestPage;
+ await examples.open(BAD_REQUEST_EXAMPLE);
+ await expect(examples.responseBody(BAD_REQUEST_EXAMPLE)).toContainText('invalid_request');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/request/request-execution-context.spec.ts b/packages/oc-docs/e2e/tests/request/request-execution-context.spec.ts
new file mode 100644
index 00000000..3b4aa894
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/request/request-execution-context.spec.ts
@@ -0,0 +1,155 @@
+import { test, expect } from '../../playwright';
+import type { ExecutionContextTab } from '../../components/request/execution-context.component';
+
+const GET_ALL_CUSTOMERS = ['billing', 'customers', 'Get All Customers'];
+const TABS: ExecutionContextTab[] = ['variables', 'scripts', 'asserts', 'tests'];
+
+test.describe('Request page — Execution Context', () => {
+ test.beforeEach(async ({ requestPage }) => {
+ await requestPage.open(GET_ALL_CUSTOMERS);
+ });
+
+ test.describe('tabs', () => {
+ test('shows a tab for each populated section, each with a count', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await expect(requestPage.section('Execution Context')).toBeVisible();
+ for (const name of TABS) {
+ await expect(executionContext.tab(name)).toBeVisible();
+ await expect(executionContext.tab(name)).toContainText(/\d/);
+ }
+ });
+
+ test('opens on the Variables tab and mounts only its panel', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await expect(executionContext.tab('variables')).toHaveAttribute('aria-selected', 'true');
+ await expect(executionContext.variablesPanel).toBeVisible();
+ await expect(executionContext.scriptsPanel).toBeHidden();
+ await expect(executionContext.assertsPanel).toBeHidden();
+ await expect(executionContext.testsPanel).toBeHidden();
+ });
+
+ test('selecting a tab reveals only that panel and marks it selected', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('asserts');
+
+ await expect(executionContext.tab('asserts')).toHaveAttribute('aria-selected', 'true');
+ await expect(executionContext.tab('variables')).toHaveAttribute('aria-selected', 'false');
+ await expect(executionContext.assertsPanel).toBeVisible();
+ await expect(executionContext.variablesPanel).toBeHidden();
+ });
+
+ test('is keyboard navigable across tabs with the arrow keys', async ({ requestPage, page }) => {
+ const { executionContext } = requestPage;
+ await executionContext.tab('variables').focus();
+
+ await page.keyboard.press('ArrowRight');
+
+ await expect(executionContext.tab('scripts')).toHaveAttribute('aria-selected', 'true');
+ await expect(executionContext.scriptsPanel).toBeVisible();
+
+ await page.keyboard.press('ArrowLeft');
+
+ await expect(executionContext.tab('variables')).toHaveAttribute('aria-selected', 'true');
+ });
+ });
+
+ test.describe('panel content', () => {
+ test('Variables lists the pre-request and post-response variables', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('variables');
+
+ await expect(executionContext.variablesPanel.getByText('Pre-Request')).toBeVisible();
+ await expect(executionContext.variable('expectedStatus')).toBeVisible();
+ await expect(executionContext.variable('customersPath')).toBeVisible();
+ await expect(executionContext.variablesPanel.getByText('Post-Response')).toBeVisible();
+ await expect(executionContext.variable('firstCustomerId')).toBeVisible();
+ });
+
+ test('Scripts lists the collection → folder → request chain around the HTTP call', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('scripts');
+
+ await expect(executionContext.scriptStep('Collection Pre-Request')).toBeVisible();
+ await expect(executionContext.scriptStep('Request Pre-Request')).toBeVisible();
+ await expect(executionContext.scriptStep('Collection Post-Response')).toBeVisible();
+ await expect(executionContext.scriptsPanel.getByText('HTTP')).toBeVisible();
+ });
+
+ test('Scripts navigates to a folder overview from a script source', async ({ requestPage, page }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('scripts');
+ await executionContext.scriptSource('customers').first().click();
+
+ await expect(page.getByTestId('folder-page')).toBeVisible();
+ await expect(page.getByTestId('folder-title')).toHaveText('customers');
+ });
+
+ test('Scripts navigates to the collection overview from the collection source', async ({ requestPage, page }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('scripts');
+ await executionContext.scriptSource('Bruno Testbench').first().click();
+
+ await expect(page.getByTestId('overview')).toBeVisible();
+ });
+
+ test('Asserts lists every assertion', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('asserts');
+
+ await expect(executionContext.assertion('res.status equals 200')).toBeVisible();
+ await expect(executionContext.assertion('res.body is an array')).toBeVisible();
+ await expect(executionContext.assertion('res.body.length greater than 0')).toBeVisible();
+ });
+
+ test('Tests lists every test case', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await executionContext.openTab('tests');
+
+ await expect(executionContext.testCase('status is 200 OK')).toBeVisible();
+ await expect(executionContext.testCase('response body is a non-empty array')).toBeVisible();
+ await expect(executionContext.testCase('every customer has an id and email')).toBeVisible();
+ await expect(executionContext.testCase('multi-level execution chain captured')).toBeVisible();
+ });
+ });
+
+ test.describe('header extras track the active tab', () => {
+ test('the execution flow shows only while Scripts is active', async ({ requestPage }) => {
+ const { executionContext } = requestPage;
+ await expect(executionContext.executionFlow).toBeHidden();
+
+ await executionContext.openTab('scripts');
+
+ await expect(executionContext.executionFlow).toHaveText('Sandwich execution flow');
+
+ await executionContext.openTab('variables');
+
+ await expect(executionContext.executionFlow).toBeHidden();
+ });
+
+ test('"View complete code" shows only while Tests is active and opens the code dialog', async ({ requestPage, page }) => {
+ const { executionContext } = requestPage;
+ await expect(executionContext.viewCompleteCodeButton).toBeHidden();
+
+ await executionContext.openTab('tests');
+
+ await expect(executionContext.viewCompleteCodeButton).toBeVisible();
+
+ await executionContext.viewCompleteCodeButton.click();
+
+ await expect(page.getByRole('dialog', { name: 'All tests' })).toBeVisible();
+ });
+ });
+
+ test('persists the collapsed state across a reload', async ({ requestPage, page }) => {
+ const toggle = () => requestPage.section('Execution Context').getByRole('button', { name: /Execution Context/i });
+ await expect(toggle()).toHaveAttribute('aria-expanded', 'true');
+
+ await toggle().click();
+
+ await expect(toggle()).toHaveAttribute('aria-expanded', 'false');
+
+ await page.reload();
+
+ await expect(toggle()).toHaveAttribute('aria-expanded', 'false');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/request/unsupported-request.spec.ts b/packages/oc-docs/e2e/tests/request/unsupported-request.spec.ts
new file mode 100644
index 00000000..3ee25718
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/request/unsupported-request.spec.ts
@@ -0,0 +1,37 @@
+import { test, expect } from '../../playwright';
+
+const UNSUPPORTED_REQUESTS = [
+ { paths: ['Realtime', 'Live Updates'], name: 'Live Updates', typeLabel: 'Websocket', shortName: 'WS', url: '/ws/updates' },
+ { paths: ['Realtime', 'GraphQL API'], name: 'GraphQL API', typeLabel: 'GraphQL', shortName: 'GQL', url: '/graphql' },
+ { paths: ['Realtime', 'Order Service'], name: 'Order Service', typeLabel: 'gRPC', shortName: 'GRPC', url: '/orders.OrderService' }
+];
+
+test.describe('Request page — unsupported request types', () => {
+ for (const { paths, name, typeLabel, shortName, url } of UNSUPPORTED_REQUESTS) {
+ test(`shows a "preview not available" notice for a ${typeLabel} request`, async ({ unsupportedRequestPage }) => {
+ await unsupportedRequestPage.open(paths);
+
+ await expect(unsupportedRequestPage.title).toHaveText(name);
+ await expect(unsupportedRequestPage.breadcrumb.segment('Realtime')).toBeVisible();
+ await expect(unsupportedRequestPage.breadcrumb.current).toHaveText(name);
+ await expect(unsupportedRequestPage.message).toContainText('Preview not available');
+ await expect(unsupportedRequestPage.message).toContainText(`${typeLabel} documentation`);
+ });
+
+ test(`renders the protocol method and url for a ${typeLabel} request`, async ({ unsupportedRequestPage }) => {
+ await unsupportedRequestPage.open(paths);
+
+ await expect(unsupportedRequestPage.urlBar.root).toBeVisible();
+ await expect(unsupportedRequestPage.urlBar.method).toHaveText(shortName);
+ await expect(unsupportedRequestPage.urlBar.url).toContainText(url);
+ });
+ }
+
+ test('renders request docs on the docs page when the request provides them', async ({ unsupportedRequestPage }) => {
+ // Only "Live Updates" carries a `docs` field in the sample collection.
+ await unsupportedRequestPage.open(['Realtime', 'Live Updates']);
+
+ await expect(unsupportedRequestPage.docs).toBeVisible();
+ await expect(unsupportedRequestPage.docs).toContainText('full-duplex communication channel');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/routing/routing.spec.ts b/packages/oc-docs/e2e/tests/routing/routing.spec.ts
new file mode 100644
index 00000000..d9a8291b
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/routing/routing.spec.ts
@@ -0,0 +1,93 @@
+import { test, expect } from '../../playwright';
+
+const FIXTURE = '/?fixture=folders';
+const page$ = (s: string) => `${FIXTURE}#/${s}`;
+
+test.describe('page-based navigation', () => {
+ test('deep-link to a nested request renders only that page on fresh load', async ({ page }) => {
+ await page.goto(page$('bookings/lifecycle/create-booking'));
+
+ const active = page.getByTestId('page');
+ await expect(active).toHaveAttribute('data-page-slug', 'bookings/lifecycle/create-booking');
+ await expect(active).toHaveAttribute('data-page-type', 'request');
+ await expect(page.getByRole('heading', { name: 'Create Booking', level: 1 })).toBeVisible();
+
+ await expect(page.getByRole('heading', { name: 'Login', level: 1 })).toHaveCount(0);
+ });
+
+ test('breadcrumb reflects the folder hierarchy', async ({ page }) => {
+ await page.goto(page$('bookings/lifecycle/create-booking'));
+ const bc = page.getByTestId('request-breadcrumb');
+ await expect(bc).toContainText('Hotel API');
+ await expect(bc).toContainText('Bookings');
+ await expect(bc).toContainText('Lifecycle');
+ await expect(page.getByRole('heading', { name: 'Create Booking', level: 1 })).toBeVisible();
+ });
+
+ test('auto-expands ancestor folders so the deep-linked item is visible in the sidebar', async ({ page }) => {
+ await page.goto(page$('bookings/lifecycle/create-booking'));
+ await expect(page.getByTestId('sidebar-item').filter({ hasText: 'Cancel Booking' })).toBeVisible();
+ });
+
+ test('prev/next walks the hierarchy in sequence order', async ({ page }) => {
+ await page.goto(page$('bookings/lifecycle/create-booking'));
+
+ const next = page.getByTestId('next-link');
+ await expect(next).toContainText('Confirm Booking');
+ await next.click();
+
+ await expect(page.getByTestId('page')).toHaveAttribute(
+ 'data-page-slug',
+ 'bookings/lifecycle/confirm-booking'
+ );
+ await expect(page.getByTestId('prev-link')).toContainText('Create Booking');
+ await expect(page.getByTestId('next-link')).toContainText('Cancel Booking');
+ });
+
+ test('slug URL is stable across reload', async ({ page }) => {
+ await page.goto(page$('authentication/login'));
+ await expect(page.getByRole('heading', { name: 'Login', level: 1 })).toBeVisible();
+
+ await page.reload();
+ await expect(page).toHaveURL(/#\/authentication\/login$/);
+ await expect(page.getByRole('heading', { name: 'Login', level: 1 })).toBeVisible();
+ });
+
+ test('a script item renders as its own script page', async ({ page }) => {
+ await page.goto(page$('setup-script'));
+ const active = page.getByTestId('page');
+ await expect(active).toHaveAttribute('data-page-slug', 'setup-script');
+ await expect(active).toHaveAttribute('data-page-type', 'script');
+ await expect(page.getByRole('heading', { name: 'Setup Script', level: 1 })).toBeVisible();
+ });
+
+ test('a folder whose name has special characters resolves via its encoded slug', async ({ page }) => {
+ // "Customers/%$" -> the slash/percent/dollar are percent-encoded, so the
+ // folder keeps its own page instead of colliding or collapsing.
+ await page.goto(page$('customers%2F%25%24'));
+ const active = page.getByTestId('page');
+ await expect(active).toHaveAttribute('data-page-slug', 'customers%2F%25%24');
+ await expect(active).toHaveAttribute('data-page-type', 'folder');
+ await expect(page.getByTestId('folder-title')).toHaveText('Customers/%$');
+ });
+
+ test('a request inside a special-character folder deep-links (encoded parent + separator)', async ({ page }) => {
+ await page.goto(page$('customers%2F%25%24/list-customers'));
+ const active = page.getByTestId('page');
+ await expect(active).toHaveAttribute('data-page-slug', 'customers%2F%25%24/list-customers');
+ await expect(active).toHaveAttribute('data-page-type', 'request');
+ await expect(page.getByTestId('request-title')).toHaveText('List customers');
+ });
+
+ test('unknown slug redirects to the overview', async ({ page }) => {
+ await page.goto(page$('does/not/exist'));
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'overview');
+ });
+
+ test('clicking a sidebar item navigates to its slug route', async ({ page }) => {
+ await page.goto(FIXTURE);
+ await page.locator('[data-testid="sidebar-item"][data-slug="authentication"]').click();
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-slug', 'authentication');
+ await expect(page).toHaveURL(/#\/authentication$/);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/script/script.spec.ts b/packages/oc-docs/e2e/tests/script/script.spec.ts
new file mode 100644
index 00000000..875d1acc
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/script/script.spec.ts
@@ -0,0 +1,29 @@
+import { test, expect } from '../../playwright';
+
+const BILLING_SCRIPT_PATH = ['billing', 'Script.js'];
+
+test.describe('Script page', () => {
+ test.beforeEach(async ({ scriptPage }) => {
+ await scriptPage.open(BILLING_SCRIPT_PATH);
+ });
+
+ test('shows the script name as the page title', async ({ scriptPage }) => {
+ await expect(scriptPage.title).toHaveText('Script');
+ });
+
+ test('shows the folder path to the script as a breadcrumb', async ({ scriptPage }) => {
+ await expect(scriptPage.breadcrumb.segment('billing')).toBeVisible();
+ await expect(scriptPage.breadcrumb.current).toHaveText('Script');
+ });
+
+ test('renders the script source as a read-only code block', async ({ scriptPage }) => {
+ const { content } = scriptPage;
+ await expect(content.root).toBeVisible();
+ await expect(content.code).toContainText('user@example.com');
+ await expect(content.code).toContainText('password123');
+ });
+
+ test('offers a button to copy the script', async ({ scriptPage }) => {
+ await expect(scriptPage.content.copyButton).toBeVisible();
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/scripts/code-editor-copy.spec.ts b/packages/oc-docs/e2e/tests/scripts/code-editor-copy.spec.ts
new file mode 100644
index 00000000..c3e7b251
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/scripts/code-editor-copy.spec.ts
@@ -0,0 +1,35 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Monaco editor copy button', () => {
+ test('reveals a copy button on hover and copies the editor content', async ({ page, playground, context }) => {
+ await context.grantPermissions(['clipboard-read', 'clipboard-write']);
+
+ await page.goto('/#/?pg=1&dock=bottom');
+ await playground.openSidebarItem('get users');
+ await playground.selectTab('scripts');
+
+ const editor = playground.preRequestScriptEditor;
+ await editor.focus();
+ await page.keyboard.type('const answer = 42;');
+ await page.keyboard.press('Escape');
+
+ const copyBtn = editor.copyButton;
+
+ await test.step('hidden until the editor is hovered', async () => {
+ await page.mouse.move(0, 0); // move off the editor (clicking it left the pointer over it)
+ await expect(copyBtn).toHaveCSS('opacity', '0');
+ });
+
+ await test.step('revealed on hover (top-right)', async () => {
+ await editor.root.hover();
+ await expect(copyBtn).toHaveCSS('opacity', '1');
+ });
+
+ await test.step('clicking it copies the editor content', async () => {
+ await copyBtn.click();
+ await expect
+ .poll(() => page.evaluate(() => navigator.clipboard.readText()))
+ .toContain('const answer = 42;');
+ });
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/scripts/scripts-autocomplete.spec.ts b/packages/oc-docs/e2e/tests/scripts/scripts-autocomplete.spec.ts
new file mode 100644
index 00000000..e64b98c1
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/scripts/scripts-autocomplete.spec.ts
@@ -0,0 +1,30 @@
+import { test, expect } from '../../playwright';
+
+test.describe('Scripts editor autocomplete', () => {
+ test.beforeEach(async ({ page, playground }) => {
+ await page.goto('/#/?pg=1&dock=bottom');
+ await playground.openSidebarItem('get users');
+ await expect(page).toHaveURL(/pgReq=/);
+ await playground.selectTab('scripts');
+ });
+
+ test('offers req/bru completions in the pre-request script editor', async ({ page, playground }) => {
+ const editor = playground.preRequestScriptEditor;
+ await editor.focus();
+ await page.keyboard.type('bru.getEnvVar');
+
+ await expect(editor.suggestions).toBeVisible();
+ await expect(editor.suggestions).toContainText('getEnvVar(key)');
+ });
+
+ test('offers res completions in the post-response script editor', async ({ page, playground }) => {
+ await playground.selectScriptTab('post-response');
+
+ const editor = playground.postResponseScriptEditor;
+ await editor.focus();
+ await page.keyboard.type('res.getBody');
+
+ await expect(editor.suggestions).toBeVisible();
+ await expect(editor.suggestions).toContainText('getBody()');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/search/search.spec.ts b/packages/oc-docs/e2e/tests/search/search.spec.ts
new file mode 100644
index 00000000..137dda67
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/search/search.spec.ts
@@ -0,0 +1,283 @@
+import { test, expect } from '../../playwright';
+
+/**
+ * The endpoint search palette: a header-anchored combobox whose listbox drops
+ * below the field. Inline on desktop; revealed by a Topbar icon below desktop.
+ */
+test.use({ colorScheme: 'light' });
+
+const DESKTOP = { width: 1280, height: 900 };
+const TABLET = { width: 900, height: 800 };
+const MOBILE = { width: 390, height: 800 };
+const FIXTURE = '/?fixture=folders';
+
+test.describe('Search palette', () => {
+ test('expands in place on focus (combobox, not a dialog)', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ await expect(search.field).toBeVisible();
+ await expect(search.openPanel).toHaveCount(0);
+ await expect(page.getByRole('dialog')).toHaveCount(0);
+
+ await search.field.click();
+ await expect(search.openPanel).toBeVisible();
+ await expect(search.filters).toBeVisible();
+
+ const box = await search.openPanel.boundingBox();
+ expect(box, 'panel has no bounding box').not.toBeNull();
+ expect(box?.y).toBeLessThan(80);
+ });
+
+ test('platform shortcut focuses and opens the field', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ const isMac = await page.evaluate(() => /Mac|iPhone|iPad|iPod/.test(navigator.platform));
+ await page.keyboard.press(isMac ? 'Meta+k' : 'Control+k');
+
+ await expect(search.openPanel).toBeVisible();
+ await expect(search.field).toBeFocused();
+ });
+
+ test('platform shortcut refocuses the field when the panel is already open', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+
+ const isMac = await page.evaluate(() => /Mac|iPhone|iPad|iPod/.test(navigator.platform));
+ const hotkey = isMac ? 'Meta+k' : 'Control+k';
+
+ await search.field.click();
+ await expect(search.field).toBeFocused();
+
+ await search.field.blur();
+ await expect(search.field).not.toBeFocused();
+
+ await page.keyboard.press(hotkey);
+ await expect(search.field).toBeFocused();
+ });
+
+ test('shows the initial empty state before typing', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+ await search.field.click();
+
+ await expect(search.panel).toContainText('Search the collection');
+ await expect(search.panel).toContainText('Find any request by name, endpoint, or folder.');
+ });
+
+ test('typing fuzzy-matches over request names', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('login');
+
+ await expect(search.results.first()).toBeVisible();
+ await expect(search.panel).toContainText('Login');
+ });
+
+ test('corrects a typo (adjacent letter swap) to the intended request', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('lgoin'); // "login" with the o/g swapped
+
+ await expect(search.results.first()).toBeVisible();
+ await expect(search.panel).toContainText('Login');
+ });
+
+ test('matches on the folder chain typed as text (not only the filter dropdown)', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('authentication'); // the folder Login lives under
+
+ await expect(search.results.first()).toBeVisible();
+ await expect(search.panel).toContainText('Login');
+ });
+
+ test('a single character keeps the initial prompt (below the match threshold)', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('l');
+
+ await expect(search.panel).toContainText('Search the collection');
+ await expect(search.resultsList).toHaveCount(0);
+ });
+
+ test('selecting a result navigates and closes the panel', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('login');
+ await search.result('Login').first().click();
+
+ await expect(search.openPanel).toHaveCount(0);
+ await expect(page.getByRole('heading', { name: 'Login', level: 1 })).toBeVisible();
+ // focus leaves the palette after selecting, so the caret doesn't linger
+ await expect(search.field).not.toBeFocused();
+ });
+
+ test('selecting a result clears the query (nothing lingers)', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('login');
+ await search.result('Login').first().click();
+
+ await expect(search.openPanel).toHaveCount(0);
+ await search.field.click();
+ await expect(search.field).toHaveValue('');
+ });
+
+ test('shows an empty state when nothing matches', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('zzzqqq-nomatch');
+
+ await expect(search.panel).toContainText('No matching requests');
+ await expect(search.resultsList).toHaveCount(0);
+ });
+
+ test('Escape clears and closes', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.field.fill('login');
+ await page.keyboard.press('Escape');
+
+ await expect(search.openPanel).toHaveCount(0);
+ // focus stays on the input after closing, so it's ready to type again
+ await expect(search.field).toBeFocused();
+
+ // and clicking the still-focused field reopens the panel
+ await search.field.click();
+ await expect(search.openPanel).toBeVisible();
+ });
+
+ test('clicking outside closes the panel', async ({ page, search, pageHeader }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto('/');
+ await search.field.click();
+ await expect(search.openPanel).toBeVisible();
+
+ await pageHeader.brandName.click();
+ await expect(search.openPanel).toHaveCount(0);
+ });
+
+ test('method chip filters results to that method', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.methodChip('GET').click();
+
+ await expect(search.results.first()).toBeVisible();
+ const count = await search.resultMethods.count();
+ expect(count).toBeGreaterThan(0);
+ for (let i = 0; i < count; i++) {
+ await expect(search.resultMethods.nth(i)).toHaveText('GET');
+ }
+ });
+
+ test('a non-primary method chip (PATCH) filters results to that method', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+
+ await search.methodChip('PATCH').click();
+
+ await expect(search.results.first()).toBeVisible();
+ const count = await search.resultMethods.count();
+ expect(count).toBeGreaterThan(0);
+ for (let i = 0; i < count; i++) {
+ await expect(search.resultMethods.nth(i)).toHaveText('PATCH');
+ }
+ });
+
+ test('arrow-key navigation keeps the highlighted option within the scroll area', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+ await search.methodChip('GET').click(); // enough GET results to overflow the list
+
+ await expect(search.results.first()).toBeVisible();
+ for (let i = 0; i < 12; i++) await page.keyboard.press('ArrowDown');
+
+ await expect(search.activeOption).toBeVisible();
+ const opt = await search.activeOption.boundingBox();
+ const box = await search.resultsScroll.boundingBox();
+ expect(opt, 'active option has no bounding box').not.toBeNull();
+ expect(box, 'results scroll has no bounding box').not.toBeNull();
+ // the highlighted option stays inside the visible scroll area
+ expect(opt?.y).toBeGreaterThanOrEqual((box?.y ?? 0) - 1);
+ expect((opt?.y ?? 0) + (opt?.height ?? 0)).toBeLessThanOrEqual((box?.y ?? 0) + (box?.height ?? 0) + 1);
+ });
+
+ test('folder dropdown closes on an outside click', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+
+ await search.folderButton.click();
+ await expect(search.folderMenu).toBeVisible();
+
+ await search.field.click(); // click outside the dropdown
+ await expect(search.folderMenu).toHaveCount(0);
+ });
+
+ test('folder filter scopes results to the chosen folder', async ({ page, search }) => {
+ await page.setViewportSize(DESKTOP);
+ await page.goto(FIXTURE);
+ await search.field.click();
+
+ await search.folderButton.click();
+ await search.folderOption('Authentication').click();
+
+ await expect(search.panel).toContainText('Login');
+ await expect(search.panel).not.toContainText('Create Booking');
+ });
+
+ test('tablet: the toggle reveals a panel that stays within the viewport', async ({ page, search }) => {
+ await page.setViewportSize(TABLET);
+ await page.goto('/');
+
+ await expect(search.toggleIcon).toBeVisible();
+ await search.toggleIcon.click();
+ await expect(search.openPanel).toBeVisible();
+
+ const box = await search.openPanel.boundingBox();
+ expect(box, 'panel has no bounding box').not.toBeNull();
+ expect(box?.x).toBeGreaterThanOrEqual(0);
+ expect((box?.x ?? 0) + (box?.width ?? 0)).toBeLessThanOrEqual(TABLET.width);
+ });
+
+ test('mobile: the toggle opens the panel without growing the header', async ({ page, search, pageHeader }) => {
+ await page.setViewportSize(MOBILE);
+ await page.goto('/');
+
+ const before = await pageHeader.root.boundingBox();
+ expect(before, 'header has no bounding box').not.toBeNull();
+
+ await search.toggleIcon.click();
+ await expect(search.openPanel).toBeVisible();
+ await expect(search.field).toBeVisible();
+
+ const after = await pageHeader.root.boundingBox();
+ expect(after, 'header has no bounding box').not.toBeNull();
+ expect(after?.height).toBe(before?.height);
+ });
+
+ test('mobile: closing returns to just the toggle icon', async ({ page, search }) => {
+ await page.setViewportSize(MOBILE);
+ await page.goto('/');
+
+ await search.toggleIcon.click();
+ await expect(search.field).toBeVisible();
+
+ await search.clearButton.click();
+ await expect(search.field).toHaveCount(0);
+ await expect(search.toggleIcon).toBeVisible();
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/sidebar/sidebar-examples.spec.ts b/packages/oc-docs/e2e/tests/sidebar/sidebar-examples.spec.ts
new file mode 100644
index 00000000..107981d8
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/sidebar/sidebar-examples.spec.ts
@@ -0,0 +1,94 @@
+import { test, expect } from '../../playwright';
+
+const GET_ALL_CUSTOMERS = ['billing', 'customers', 'Get All Customers'];
+const OK_EXAMPLE = '200 OK - first page';
+const BAD_REQUEST_EXAMPLE = '400 Bad Request - invalid per_page';
+const REQUEST_PATH = '#/billing/customers/get-all-customers';
+const OK_EXAMPLE_SLUG = '200-ok-first-page';
+const OK_EXAMPLE_URL = `/${REQUEST_PATH}/${OK_EXAMPLE_SLUG}`;
+
+test.describe('Sidebar - Examples (docs)', () => {
+ test.beforeEach(async ({ requestPage }) => {
+ await requestPage.open(GET_ALL_CUSTOMERS);
+ });
+
+ test('keeps a request with examples collapsed until its toggle is expanded', async ({ sidebar }) => {
+ await expect(sidebar.exampleToggle('Get All Customers')).toBeVisible();
+ await expect(sidebar.exampleRow(OK_EXAMPLE)).toHaveCount(0);
+
+ await sidebar.toggleExamples('Get All Customers');
+ await expect(sidebar.exampleRow(OK_EXAMPLE)).toBeVisible();
+ await expect(sidebar.exampleRow(BAD_REQUEST_EXAMPLE)).toBeVisible();
+ });
+
+ test('clicking an example navigates to the parent request page and highlights the matching example card', async ({
+ sidebar,
+ requestPage,
+ page
+ }) => {
+ await sidebar.toggleExamples('Get All Customers');
+ await sidebar.exampleRow(OK_EXAMPLE).click();
+
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'request');
+ await expect(page).toHaveURL(/#\/billing\/customers\/get-all-customers\/200-ok-first-page$/);
+
+ const activeCard = requestPage.examples.activeCard;
+ await expect(activeCard).toBeVisible();
+ await expect(activeCard).toContainText(OK_EXAMPLE);
+ await expect(sidebar.exampleRow(OK_EXAMPLE)).toHaveClass(/active/);
+ // Only the example row is active, not its parent request row.
+ await expect(sidebar.item('Get All Customers')).not.toHaveClass(/active/);
+ });
+
+ test('switching to a different example moves the highlight to it', async ({ sidebar, requestPage }) => {
+ await sidebar.toggleExamples('Get All Customers');
+ await sidebar.exampleRow(OK_EXAMPLE).click();
+ await expect(requestPage.examples.activeCard).toContainText(OK_EXAMPLE);
+
+ await sidebar.exampleRow(BAD_REQUEST_EXAMPLE).click();
+
+ const activeCard = requestPage.examples.activeCard;
+ await expect(activeCard).toContainText(BAD_REQUEST_EXAMPLE);
+ await expect(activeCard).not.toContainText(OK_EXAMPLE);
+ await expect(sidebar.exampleRow(BAD_REQUEST_EXAMPLE)).toHaveClass(/active/);
+ });
+
+ test('deep-links the example: opening its url (share) and reloading restore the highlight', async ({
+ page,
+ requestPage
+ }) => {
+ await page.goto(OK_EXAMPLE_URL);
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'request');
+ await expect(requestPage.examples.activeCard).toContainText(OK_EXAMPLE);
+
+ await page.reload();
+ await expect(requestPage.examples.activeCard).toContainText(OK_EXAMPLE);
+ });
+
+ test('browser back and forward move the highlight between examples', async ({ sidebar, requestPage, page }) => {
+ await sidebar.toggleExamples('Get All Customers');
+ await sidebar.exampleRow(OK_EXAMPLE).click();
+ await expect(requestPage.examples.activeCard).toContainText(OK_EXAMPLE);
+ await sidebar.exampleRow(BAD_REQUEST_EXAMPLE).click();
+ await expect(requestPage.examples.activeCard).toContainText(BAD_REQUEST_EXAMPLE);
+
+ await page.goBack();
+ await expect(requestPage.examples.activeCard).toContainText(OK_EXAMPLE);
+ await page.goForward();
+ await expect(requestPage.examples.activeCard).toContainText(BAD_REQUEST_EXAMPLE);
+ });
+
+ test('an unknown example slug falls back to the request page with no highlight', async ({ page, requestPage }) => {
+ await page.goto(`/${REQUEST_PATH}/does-not-exist`);
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'request');
+ await expect(requestPage.examples.activeCard).toHaveCount(0);
+ });
+
+ test('Try on an example opens the playground on that example, deep-linked', async ({ requestPage, playground, page }) => {
+ await requestPage.examples.try(OK_EXAMPLE);
+
+ await expect(playground.exampleView).toBeVisible();
+ await expect(page).toHaveURL(new RegExp(`[?&]pgEx=${OK_EXAMPLE_SLUG}(?:&|$)`));
+ await expect(playground.exampleViewControls).toHaveCount(0);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/sidebar/sidebar.spec.ts b/packages/oc-docs/e2e/tests/sidebar/sidebar.spec.ts
new file mode 100644
index 00000000..88c46cc8
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/sidebar/sidebar.spec.ts
@@ -0,0 +1,77 @@
+import { test, expect } from '../../playwright';
+
+const FOLDERS = '/?fixture=folders';
+const DESKTOP = { width: 1280, height: 900 };
+const MOBILE = { width: 390, height: 800 };
+
+test.describe('sidebar - desktop (inline, collapsible)', () => {
+ test.use({ viewport: DESKTOP });
+
+ test('renders inline with the overview link, no hamburger or drawer', async ({ page, sidebar }) => {
+ await page.goto(FOLDERS);
+ await expect(sidebar.inline).toBeVisible();
+ await expect(sidebar.overview).toBeVisible();
+ await expect(sidebar.hamburger).toHaveCount(0);
+ await expect(sidebar.drawer).toHaveCount(0);
+ });
+
+ test('collapses the whole panel and re-opens it', async ({ page, sidebar }) => {
+ await page.goto(FOLDERS);
+ await sidebar.collapse();
+ await expect(sidebar.inline).toHaveCount(0);
+ await expect(sidebar.expandButton).toBeVisible();
+ await sidebar.expand();
+ await expect(sidebar.inline).toBeVisible();
+ });
+
+ test('keeps folders expanded across navigation', async ({ page, sidebar }) => {
+ await page.goto(`${FOLDERS}#/bookings/lifecycle/create-booking`);
+ await expect(sidebar.item('Cancel Booking')).toBeVisible();
+ await sidebar.overview.click();
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'overview');
+ await expect(sidebar.item('Cancel Booking')).toBeVisible();
+ });
+
+ test('collapses a folder holding the active item without changing the view', async ({ page, sidebar }) => {
+ await page.goto(`${FOLDERS}#/bookings/lifecycle/create-booking`);
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'request');
+ await expect(sidebar.folderChevron('Lifecycle')).toHaveClass(/expanded/);
+ await expect(sidebar.item('Cancel Booking')).toBeVisible();
+
+ await sidebar.toggleFolder('Lifecycle');
+
+ await expect(sidebar.folderChevron('Lifecycle')).not.toHaveClass(/expanded/);
+ await expect(sidebar.item('Cancel Booking')).toHaveCount(0);
+ await expect(page.getByTestId('page')).toHaveAttribute('data-page-type', 'request');
+ await expect(page).toHaveURL(/#\/bookings\/lifecycle\/create-booking$/);
+ });
+});
+
+test.describe('sidebar - mobile (off-canvas drawer)', () => {
+ test.use({ viewport: MOBILE });
+
+ test('has no inline panel and opens the drawer from the hamburger', async ({ page, sidebar }) => {
+ await page.goto(FOLDERS);
+ await expect(sidebar.inline).toHaveCount(0);
+ await expect(sidebar.backdrop).toBeHidden();
+ await sidebar.openDrawer();
+ await expect(sidebar.backdrop).toBeVisible();
+ await expect(sidebar.drawer).toHaveAttribute('aria-hidden', 'false');
+ });
+
+ test('closes the drawer when a nav item is tapped', async ({ page, sidebar }) => {
+ await page.goto(FOLDERS);
+ await sidebar.openDrawer();
+ await expect(sidebar.backdrop).toBeVisible();
+ await sidebar.overview.click();
+ await expect(sidebar.backdrop).toBeHidden();
+ });
+
+ test('closes the drawer when the backdrop is tapped', async ({ page, sidebar }) => {
+ await page.goto(FOLDERS);
+ await sidebar.openDrawer();
+ await expect(sidebar.backdrop).toBeVisible();
+ await sidebar.closeDrawerViaBackdrop();
+ await expect(sidebar.backdrop).toBeHidden();
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/theming/theme-toggle.spec.ts b/packages/oc-docs/e2e/tests/theming/theme-toggle.spec.ts
new file mode 100644
index 00000000..0559d4c3
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/theming/theme-toggle.spec.ts
@@ -0,0 +1,39 @@
+import { test, expect } from '../../playwright';
+
+/**
+ * The header has one button that flips the whole app between light and dark.
+ */
+test.describe('Theme switcher', () => {
+ test.use({ colorScheme: 'light' });
+
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/');
+ });
+
+ test('starts in light mode, with the toggle offering "Switch to dark theme"', async ({ page, themeToggle }) => {
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'light');
+ await expect(themeToggle.button).toHaveAccessibleName('Switch to dark theme');
+ });
+
+ test('switches the whole app to dark mode when the toggle is clicked', async ({ page, themeToggle }) => {
+ await themeToggle.toggle();
+
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
+ // The toggle now offers the opposite action.
+ await expect(themeToggle.button).toHaveAccessibleName('Switch to light theme');
+ });
+
+ test('switches back to light mode when the toggle is clicked again', async ({ page, themeToggle }) => {
+ await themeToggle.toggle();
+ await themeToggle.toggle();
+
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'light');
+ });
+
+ test('remembers the chosen theme across a page reload', async ({ page, themeToggle }) => {
+ await themeToggle.toggle();
+ await page.reload();
+
+ await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/tooltip/truncation-tooltip.spec.ts b/packages/oc-docs/e2e/tests/tooltip/truncation-tooltip.spec.ts
new file mode 100644
index 00000000..a6ae99b7
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/tooltip/truncation-tooltip.spec.ts
@@ -0,0 +1,32 @@
+import { test, expect } from '../../playwright';
+
+const GET_ALL_CUSTOMERS = ['billing', 'customers', 'Get All Customers'];
+
+test.describe('Truncation tooltips', () => {
+ test('reveals the full text in a tooltip when a value is truncated (narrow viewport)', async ({
+ requestPage,
+ tooltip,
+ page
+ }) => {
+ await requestPage.open(GET_ALL_CUSTOMERS);
+ await page.setViewportSize({ width: 280, height: 800 });
+
+ const clippedCell = await tooltip.findFirstClippedCell();
+ expect(clippedCell, 'expected at least one truncated cell at 280px').not.toBeNull();
+
+ await tooltip.hoverCell(clippedCell!.index);
+ await expect(tooltip.popup).toBeVisible();
+ await expect(tooltip.popup).toHaveText(clippedCell!.fullText);
+ });
+
+ test('does not attach a tooltip to text that fits (wide viewport)', async ({ requestPage, tooltip, page }) => {
+ await requestPage.open(GET_ALL_CUSTOMERS);
+ await page.setViewportSize({ width: 1400, height: 900 });
+
+ const unclippedCellIndex = await tooltip.findFirstUnclippedCellIndex();
+ test.skip(unclippedCellIndex < 0, 'no non-truncated text found to check');
+
+ await tooltip.hoverCell(unclippedCellIndex);
+ await expect(tooltip.popup).toHaveCount(0);
+ });
+});
diff --git a/packages/oc-docs/e2e/tests/variableInfoPopup/variableInfoPopup.spec.ts b/packages/oc-docs/e2e/tests/variableInfoPopup/variableInfoPopup.spec.ts
new file mode 100644
index 00000000..6f660e5a
--- /dev/null
+++ b/packages/oc-docs/e2e/tests/variableInfoPopup/variableInfoPopup.spec.ts
@@ -0,0 +1,317 @@
+import { test, expect } from '../../playwright';
+
+const REQUEST = '/?fixture=vars#/customers/variables-demo';
+
+test.describe('Variable hover card', () => {
+ test.beforeEach(async ({ requestPage, envSwitcher }) => {
+ await requestPage.goto(REQUEST);
+ await envSwitcher.selectEnvironment('Dev');
+ });
+
+ test('resolves an environment variable with its scope badge and value', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('host');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.name).toHaveText('host');
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('https://api.dev.example.com');
+ });
+
+ test('badges collection, folder and request scopes correctly', async ({ page, requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('apiVersion');
+ await expect(variableCard.scopeBadge).toHaveText('Collection');
+ await expect(variableCard.value).toHaveText('2024-01');
+
+ await page.mouse.move(0, 0);
+ await expect(variableCard.card).toHaveCount(0);
+
+ await variableCard.hoverToken('folderScope');
+ await expect(variableCard.scopeBadge).toHaveText('Folder');
+ await expect(variableCard.value).toHaveText('from-folder');
+
+ await page.mouse.move(0, 0);
+ await expect(variableCard.card).toHaveCount(0);
+
+ await variableCard.hoverToken('userId');
+ await expect(variableCard.scopeBadge).toHaveText('Request');
+ await expect(variableCard.value).toHaveText('req-42');
+ });
+
+ test('resolves a value that references other variables', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('endpoint');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.value).toHaveText('https://api.dev.example.com/v1');
+ });
+
+ test('shows the card for a variable used in an example request URL', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('exampleOnly');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Collection');
+ await expect(variableCard.value).toHaveText('example-value');
+ });
+
+ test('shows the card for a variable used in the request body', async ({ requestPage }) => {
+ const { bodyVariableCard: variableCard } = requestPage;
+ await variableCard.hoverToken('host');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('https://api.dev.example.com');
+ });
+
+ test('shows a (Secret) placeholder for a secret referenced in the request body', async ({ requestPage }) => {
+ const { bodyVariableCard: variableCard } = requestPage;
+ await variableCard.hoverToken('bearer_token');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('(Secret)');
+ await expect(variableCard.copyButton).toHaveCount(0);
+ });
+
+ test('shows an (empty) placeholder with no copy for a defined variable that has no value', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('emptyValue');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('(empty)');
+ await expect(variableCard.copyButton).toHaveCount(0);
+ });
+
+ test('pretty-prints an object-typed value', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('profile');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.value).toContainText('NYC');
+ await expect(variableCard.value).toContainText('zip');
+ });
+
+ test('marks process.env and dynamic references read-only, without a value', async ({ page, requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('process.env.HOME');
+
+ await expect(variableCard.scopeBadge).toHaveText('Process Env');
+ await expect(variableCard.note).toHaveText('read-only');
+
+ await page.mouse.move(0, 0);
+ await expect(variableCard.card).toHaveCount(0);
+
+ await variableCard.hoverToken('$randomInt');
+
+ await expect(variableCard.scopeBadge).toHaveText('Dynamic');
+ await expect(variableCard.note).toContainText('random value');
+ });
+
+ test('shows a (Secret) placeholder with no reveal or copy, never exposing the value', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.pinToken('bearer_token');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('(Secret)');
+ await expect(variableCard.card).not.toContainText('super-secret-token');
+ await expect(variableCard.revealToggle).toHaveCount(0);
+ await expect(variableCard.copyButton).toHaveCount(0);
+ });
+
+ test('copies the resolved value from the copy button', async ({ page, requestPage }) => {
+ const { variableCard } = requestPage;
+ await page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
+
+ await variableCard.pinToken('apiVersion');
+ await expect(variableCard.card).toBeVisible();
+
+ await variableCard.copyButton.click();
+ await expect.poll(() => page.evaluate(() => navigator.clipboard.readText())).toBe('2024-01');
+ });
+
+ test('is read-only — no editor inside the card', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.pinToken('host');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.editors).toHaveCount(0);
+ });
+
+ test('stays open while hovering the card, then closes after the pointer leaves', async ({ page, requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('host');
+ await expect(variableCard.card).toBeVisible();
+
+ await variableCard.card.hover();
+ await expect(variableCard.card).toBeVisible();
+
+ await page.mouse.move(0, 0);
+ await expect(variableCard.card).toBeHidden();
+ });
+
+ test('pins on click; Escape and outside click dismiss it', async ({ page, requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.pinToken('host');
+ await expect(variableCard.card).toBeVisible();
+
+ // Pinned: leaving does not close it.
+ await page.mouse.move(0, 0);
+ await expect(variableCard.card).toBeVisible();
+
+ await page.keyboard.press('Escape');
+ await expect(variableCard.card).toBeHidden();
+
+ await variableCard.pinToken('host');
+ await expect(variableCard.card).toBeVisible();
+
+ await page.mouse.click(2, 2);
+ await expect(variableCard.card).toBeHidden();
+ });
+
+ test.describe('touch', () => {
+ test.use({ hasTouch: true });
+
+ test('opens on tap', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.token('host').tap();
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ });
+ });
+
+ test.describe('narrow (mobile) viewport', () => {
+ test.use({ viewport: { width: 280, height: 700 } });
+
+ test('keeps the hover card within a narrow viewport instead of overflowing off-screen', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await variableCard.hoverToken('endpoint');
+ await expect(variableCard.card).toBeVisible();
+
+ const box = await variableCard.card.boundingBox();
+ if (!box) throw new Error('hover card has no bounding box');
+
+ expect(box.x).toBeGreaterThanOrEqual(0);
+ expect(box.x + box.width).toBeLessThanOrEqual(280);
+ });
+ });
+});
+
+// The card also works on the Overview and Folder pages (the collection/folder
+// config sections render header values through VariableText), degrading to the
+// scopes those pages can see (no request scope on Overview/Folder).
+test.describe('Variable hover card — Overview page', () => {
+ test.beforeEach(async ({ overviewPage, envSwitcher }) => {
+ await overviewPage.goto('/?fixture=vars');
+ await envSwitcher.selectEnvironment('Dev');
+ });
+
+ test('shows the card for a variable used in a collection header (Collection scope)', async ({ overviewPage }) => {
+ const { variableCard } = overviewPage;
+ await variableCard.hoverToken('apiVersion');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Collection');
+ await expect(variableCard.value).toHaveText('2024-01');
+ });
+
+ test('shows a (Secret) placeholder for a secret referenced in a collection header', async ({ overviewPage }) => {
+ const { variableCard } = overviewPage;
+ await variableCard.hoverToken('bearer_token');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('(Secret)');
+ });
+});
+
+test.describe('Variable hover card — Folder page', () => {
+ test.beforeEach(async ({ folderPage, envSwitcher }) => {
+ await folderPage.goto('/?fixture=vars#/customers');
+ await envSwitcher.selectEnvironment('Dev');
+ });
+
+ test('shows the card for a variable used in a folder header (Folder scope)', async ({ folderPage }) => {
+ const { variableCard } = folderPage;
+ await variableCard.hoverToken('folderScope');
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Folder');
+ await expect(variableCard.value).toHaveText('from-folder');
+ });
+});
+
+test.describe('Variable hover card — Code snippet', () => {
+ test.beforeEach(async ({ requestPage, envSwitcher }) => {
+ await requestPage.goto(REQUEST);
+ await envSwitcher.selectEnvironment('Dev');
+ });
+
+ test('shows the hover card for a variable inside the generated code', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await requestPage.codeSnippet.variableToken('host').hover();
+
+ await expect(variableCard.card).toBeVisible();
+ await expect(variableCard.scopeBadge).toHaveText('Environment');
+ await expect(variableCard.value).toHaveText('https://api.dev.example.com');
+ });
+
+ test('replaces a variable with its resolved value when show variables is on', async ({ requestPage, envSwitcher }) => {
+ const host = requestPage.codeSnippet.variableToken('host');
+ await expect(host).toHaveText('{{host}}');
+
+ await envSwitcher.toggle();
+ await expect(host).toHaveText('https://api.dev.example.com');
+ });
+
+ test('never resolves a secret into the code, even when show variables is on', async ({ requestPage, envSwitcher }) => {
+ await envSwitcher.toggle();
+ await expect(requestPage.codeSnippet.variableToken('bearer_token')).toHaveText('{{bearer_token}}');
+ });
+
+ test('copy writes the revealed snippet to the clipboard when show variables is on', async ({ page, requestPage, envSwitcher }) => {
+ await page.context().grantPermissions(['clipboard-read', 'clipboard-write']);
+ await envSwitcher.toggle();
+ await requestPage.codeSnippet.copyButton.click();
+
+ await expect
+ .poll(() => page.evaluate(() => navigator.clipboard.readText()))
+ .toContain('https://api.dev.example.com/customers/req-42?v=2024-01');
+
+ const copied = await page.evaluate(() => navigator.clipboard.readText());
+ expect(copied).not.toContain('{{host}}/customers');
+ expect(copied).toContain('{{bearer_token}}');
+ });
+
+ test('toggling show variables while a card is open does not crash the page', async ({ page, requestPage, envSwitcher }) => {
+ const { variableCard } = requestPage;
+ const errors: string[] = [];
+ page.on('pageerror', (error) => errors.push(error.message));
+
+ await requestPage.codeSnippet.variableToken('host').hover();
+ await expect(variableCard.card).toBeVisible();
+
+ await envSwitcher.toggle();
+ await expect(requestPage.codeSnippet.variableToken('host')).toHaveText('https://api.dev.example.com');
+ await expect(variableCard.card).toHaveCount(0);
+ expect(errors).toEqual([]);
+ });
+
+ test('hover card renders above the expanded code-snippet modal', async ({ requestPage }) => {
+ const { variableCard } = requestPage;
+ await requestPage.codeSnippet.openExpandedView();
+ await requestPage.codeSnippet.modalVariableToken('host').hover();
+ await expect(variableCard.card).toBeVisible();
+
+ const onTop = await variableCard.card.evaluate((el) => {
+ const rect = el.getBoundingClientRect();
+ const hit = document.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
+ return el.contains(hit);
+ });
+ expect(onTop).toBe(true);
+ });
+});
diff --git a/packages/oc-docs/e2e/tsconfig.json b/packages/oc-docs/e2e/tsconfig.json
new file mode 100644
index 00000000..6238ba7c
--- /dev/null
+++ b/packages/oc-docs/e2e/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "noEmit": true
+ },
+ "include": ["**/*.ts"]
+}
diff --git a/packages/oc-docs/eslint.config.js b/packages/oc-docs/eslint.config.js
new file mode 100644
index 00000000..1f5adec3
--- /dev/null
+++ b/packages/oc-docs/eslint.config.js
@@ -0,0 +1,39 @@
+import js from '@eslint/js';
+import globals from 'globals';
+import reactHooks from 'eslint-plugin-react-hooks';
+import reactRefresh from 'eslint-plugin-react-refresh';
+import tseslint from 'typescript-eslint';
+
+export default tseslint.config(
+ { ignores: ['dist', 'dist-standalone', 'dist-server'] },
+ {
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
+ files: ['**/*.{ts,tsx}'],
+ languageOptions: {
+ ecmaVersion: 2020,
+ globals: globals.browser,
+ },
+ plugins: {
+ 'react-hooks': reactHooks,
+ 'react-refresh': reactRefresh,
+ },
+ rules: {
+ ...reactHooks.configs.recommended.rules,
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ '@typescript-eslint/no-explicit-any': 'warn',
+ },
+ },
+ {
+ // Playwright e2e tests are not React: the fixture `use` argument is not a hook,
+ // and the files export page-object/component classes, not React components.
+ files: ['e2e/**/*.ts'],
+ rules: {
+ 'react-hooks/rules-of-hooks': 'off',
+ 'react-refresh/only-export-components': 'off',
+ },
+ },
+);
\ No newline at end of file
diff --git a/packages/oc-docs/index.html b/packages/oc-docs/index.html
new file mode 100644
index 00000000..fc817fb1
--- /dev/null
+++ b/packages/oc-docs/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ OpenCollection Docs - Development
+
+
+
+
+
+
diff --git a/packages/oc-docs/package.json b/packages/oc-docs/package.json
new file mode 100644
index 00000000..3d01b305
--- /dev/null
+++ b/packages/oc-docs/package.json
@@ -0,0 +1,136 @@
+{
+ "name": "@opencollection/docs",
+ "version": "0.0.1",
+ "description": "Interactive API documentation component for OpenCollection - supports both React components and standalone JavaScript",
+ "type": "module",
+ "main": "dist/oc-playground.umd.js",
+ "module": "dist/oc-playground.es.js",
+ "types": "dist/index.d.ts",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "import": "./dist/oc-playground.es.js",
+ "require": "./dist/oc-playground.umd.js"
+ },
+ "./standalone": {
+ "types": "./standalone.d.ts",
+ "import": "./dist-standalone/playground.es.js",
+ "require": "./dist-standalone/playground.umd.js"
+ },
+ "./express": {
+ "types": "./dist/express.d.ts",
+ "import": "./dist/express.js",
+ "require": "./dist/express.js"
+ },
+ "./server": {
+ "types": "./dist/server.d.ts",
+ "import": "./dist/server.js",
+ "require": "./dist/server.js"
+ }
+ },
+ "files": [
+ "dist",
+ "dist-standalone",
+ "standalone.d.ts"
+ ],
+ "scripts": {
+ "gen:theme": "vite-node scripts/generate-theme-css.ts",
+ "predev": "npm run gen:theme && npm run build:lib-bundle",
+ "dev": "vite",
+ "server": "node server.js",
+ "dev:all": "concurrently \"npm run dev\" \"npm run server\"",
+ "build:lib-bundle": "vite build --config vite.config.libraries-bundle.ts",
+ "prebuild": "npm run gen:theme && npm run build:lib-bundle",
+ "build": "npm run clean && tsc -p tsconfig.build.json --emitDeclarationOnly && vite build",
+ "build:standalone": "npm run clean:standalone && vite build --config vite.config.standalone.ts",
+ "build:all": "npm run build && npm run build:standalone",
+ "prepublishOnly": "npm run build:all",
+ "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview",
+ "test": "vitest",
+ "test:run": "vitest run",
+ "test:e2e": "playwright test",
+ "test:e2e:ui": "playwright test --ui",
+ "clean": "rimraf dist",
+ "clean:standalone": "rimraf dist-standalone"
+ },
+ "dependencies": {
+ "@emotion/css": "^11.13.5",
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@faker-js/faker": "^9.7.0",
+ "@mintlify/httpsnippet": "^1.0.10",
+ "@monaco-editor/react": "^4.7.0",
+ "@opencollection/types": "0.11.0",
+ "@prantlf/jsonlint": "^16.0.0",
+ "@reduxjs/toolkit": "^2.10.1",
+ "@tabler/icons": "^1.46.0",
+ "@tailwindcss/vite": "^4.0.9",
+ "@tippyjs/react": "^4.2.6",
+ "@types/js-yaml": "^4.0.9",
+ "@types/markdown-it": "^14.1.2",
+ "@types/prismjs": "^1.26.5",
+ "ajv": "^8.12.0",
+ "codemirror": "^6.0.2",
+ "fuse.js": "^7.5.0",
+ "js-yaml": "^4.1.0",
+ "jshint": "^2.13.6",
+ "markdown-it": "^14.1.0",
+ "monaco-editor": "^0.53.0",
+ "nanoid": "~3.3.11",
+ "prismjs": "^1.29.0",
+ "quickjs-emscripten": "~0.31.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-markdown": "^10.0.0",
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.3.0",
+ "remark-gfm": "^4.0.1",
+ "strip-json-comments": "^3.1.1"
+ },
+ "devDependencies": {
+ "@emotion/babel-plugin": "~11.13.5",
+ "@eslint/js": "^9.21.0",
+ "@playwright/test": "^1.52.0",
+ "@tailwindcss/postcss": "^4.1.13",
+ "@tailwindcss/typography": "^0.5.10",
+ "@types/express": "^4.17.21",
+ "@types/lodash-es": "~4.17.12",
+ "@types/prismjs": "^1.26.3",
+ "@types/react": "^19.0.10",
+ "@types/react-dom": "^19.0.4",
+ "@types/uuid": "^10.0.0",
+ "@vitejs/plugin-react": "^4.3.4",
+ "autoprefixer": "^10.4.20",
+ "chai": "~5.3.3",
+ "concurrently": "^9.1.2",
+ "eslint": "^9.21.0",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "eslint-plugin-react-refresh": "^0.4.19",
+ "globals": "^15.15.0",
+ "lodash-es": "~4.17.21",
+ "node-html-parser": "^8.0.4",
+ "postcss": "^8.5.3",
+ "rimraf": "^6.0.1",
+ "rollup": "^4.50.2",
+ "tailwindcss": "^4.0.9",
+ "terser": "^5.44.0",
+ "typescript": "~5.7.2",
+ "typescript-eslint": "^8.24.1",
+ "vite": "^6.2.0",
+ "vitest": "^2.1.8"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "keywords": [
+ "opencollection",
+ "api",
+ "documentation",
+ "playground",
+ "interactive"
+ ],
+ "author": "OpenCollection",
+ "license": "MIT"
+}
diff --git a/packages/oc-docs/playwright.config.ts b/packages/oc-docs/playwright.config.ts
new file mode 100644
index 00000000..02942c61
--- /dev/null
+++ b/packages/oc-docs/playwright.config.ts
@@ -0,0 +1,31 @@
+import { defineConfig, devices } from '@playwright/test';
+import { appConfig } from './e2e/config/app.config';
+
+export default defineConfig({
+ testDir: './e2e',
+ tsconfig: './e2e/tsconfig.json',
+ fullyParallel: true,
+ forbidOnly: !!process.env.CI,
+ retries: process.env.CI ? 2 : 0,
+ workers: process.env.CI ? 1 : undefined,
+ reporter: [
+ ['list'],
+ ['html'],
+ ['json', { outputFile: 'playwright-report/results.json' }],
+ ],
+ use: {
+ baseURL: appConfig.baseURL,
+ trace: 'on-first-retry',
+ },
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ ],
+ webServer: {
+ command: appConfig.webServerCommand,
+ url: appConfig.baseURL,
+ reuseExistingServer: !process.env.CI,
+ },
+});
diff --git a/packages/oc-docs/postcss.config.cjs b/packages/oc-docs/postcss.config.cjs
new file mode 100644
index 00000000..90c78136
--- /dev/null
+++ b/packages/oc-docs/postcss.config.cjs
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ '@tailwindcss/postcss': {},
+ autoprefixer: {},
+ },
+}
\ No newline at end of file
diff --git a/packages/oc-docs/scripts/generate-theme-css.ts b/packages/oc-docs/scripts/generate-theme-css.ts
new file mode 100644
index 00000000..611b2f98
--- /dev/null
+++ b/packages/oc-docs/scripts/generate-theme-css.ts
@@ -0,0 +1,35 @@
+import { writeFileSync } from 'node:fs';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { flattenTheme } from '../src/theme/flatten';
+import { breakpoints } from '../src/theme/tokens/breakpoints';
+import { light } from '../src/theme/tokens/light';
+import { dark } from '../src/theme/tokens/dark';
+
+const block = (selector: string, vars: Record) =>
+ `${selector} {\n${Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join('\n')}\n}\n`;
+
+const bpVars = Object.fromEntries(Object.entries(breakpoints).map(([k, v]) => [`--oc-breakpoint-${k}`, v]));
+
+const css = [
+ '/* AUTO-GENERATED by scripts/generate-theme-css.ts. Do not edit by hand. */',
+ '/* Run: npm run gen:theme */',
+ '/*',
+ ' * Tokens are ported 1:1 from the Bruno app themes (src/theme/tokens/light.ts,',
+ ' * dark.ts). The full Bruno set is emitted for fidelity and future component',
+ ' * reuse, so some variables are not consumed by the docs UI yet — e.g.',
+ ' * --oc-notifications-*, --oc-grpc-*, --oc-console-*, --oc-deprecation-warning-*.',
+ ' * These are intentional and safe to keep; prune/refine them later if needed.',
+ ' */',
+ block(':root', bpVars),
+ // Light is also the :root default, so colours resolve even if the root has no
+ // data-theme attribute (e.g. applyTheme() never ran) — degrades to light
+ // instead of unstyled.
+ block(':root,\n[data-theme="light"]', flattenTheme(light as unknown as Record)),
+ block('[data-theme="dark"]', flattenTheme(dark as unknown as Record)),
+].join('\n');
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+writeFileSync(resolve(__dirname, '../src/styles/theme.generated.css'), css);
+console.log('theme.generated.css written');
diff --git a/packages/oc-docs/src/assets/icons/BookIcon.tsx b/packages/oc-docs/src/assets/icons/BookIcon.tsx
new file mode 100644
index 00000000..819d0fb9
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/BookIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const BookIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/BrunoGlyph.tsx b/packages/oc-docs/src/assets/icons/BrunoGlyph.tsx
new file mode 100644
index 00000000..2f3eabac
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/BrunoGlyph.tsx
@@ -0,0 +1,107 @@
+import React from 'react';
+
+/** Bruno mascot — fixed brand colours (a brand mark, not a themeable surface).
+ * Used inside the Open-in-Bruno CTA. */
+export const BrunoGlyph: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/CaretIcon.tsx b/packages/oc-docs/src/assets/icons/CaretIcon.tsx
new file mode 100644
index 00000000..d6111236
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/CaretIcon.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+
+/** Small downward caret; fills its container (e.g. the variable data-type select). */
+export const CaretIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/ChevronDownIcon.tsx b/packages/oc-docs/src/assets/icons/ChevronDownIcon.tsx
new file mode 100644
index 00000000..108b99af
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ChevronDownIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+/** Chevron down, the search palette's folder filter dropdown. */
+export const ChevronDownIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/ChevronLeftIcon.tsx b/packages/oc-docs/src/assets/icons/ChevronLeftIcon.tsx
new file mode 100644
index 00000000..c2eb543a
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ChevronLeftIcon.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const ChevronLeftIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/ChevronRightIcon.tsx b/packages/oc-docs/src/assets/icons/ChevronRightIcon.tsx
new file mode 100644
index 00000000..b1ea8a28
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ChevronRightIcon.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const ChevronRightIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/CloseIcon.tsx b/packages/oc-docs/src/assets/icons/CloseIcon.tsx
new file mode 100644
index 00000000..0f46475b
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/CloseIcon.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const CloseIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/CubeIcon.tsx b/packages/oc-docs/src/assets/icons/CubeIcon.tsx
new file mode 100644
index 00000000..451d0963
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/CubeIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const CubeIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/DockBottomIcon.tsx b/packages/oc-docs/src/assets/icons/DockBottomIcon.tsx
new file mode 100644
index 00000000..6ba98693
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/DockBottomIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const DockBottomIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/DockInlineIcon.tsx b/packages/oc-docs/src/assets/icons/DockInlineIcon.tsx
new file mode 100644
index 00000000..5537be71
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/DockInlineIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const DockInlineIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/DockModalIcon.tsx b/packages/oc-docs/src/assets/icons/DockModalIcon.tsx
new file mode 100644
index 00000000..bff13e97
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/DockModalIcon.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const DockModalIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/ExampleIcon.spec.tsx b/packages/oc-docs/src/assets/icons/ExampleIcon.spec.tsx
new file mode 100644
index 00000000..9989b40e
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ExampleIcon.spec.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { describe, it, expect } from 'vitest';
+import { ExampleIcon } from './ExampleIcon';
+import { useRenderToDom } from '../../hooks/useRenderToDom';
+import { query } from '../../test-utils/dom';
+
+describe('ExampleIcon', () => {
+ it('renders a decorative svg glyph', () => {
+ const root = useRenderToDom();
+ expect(query(root, 'svg').getAttribute('aria-hidden')).toBe('true');
+ });
+});
diff --git a/packages/oc-docs/src/assets/icons/ExampleIcon.tsx b/packages/oc-docs/src/assets/icons/ExampleIcon.tsx
new file mode 100644
index 00000000..5ef6cf71
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ExampleIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+
+export const ExampleIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/ExpandIcon.tsx b/packages/oc-docs/src/assets/icons/ExpandIcon.tsx
new file mode 100644
index 00000000..05c4b9a5
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/ExpandIcon.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const ExpandIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/EyeIcon.tsx b/packages/oc-docs/src/assets/icons/EyeIcon.tsx
new file mode 100644
index 00000000..e6912c55
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/EyeIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const EyeIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/EyeOffIcon.tsx b/packages/oc-docs/src/assets/icons/EyeOffIcon.tsx
new file mode 100644
index 00000000..4f071e98
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/EyeOffIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const EyeOffIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/FileIcon.tsx b/packages/oc-docs/src/assets/icons/FileIcon.tsx
new file mode 100644
index 00000000..6df3b18f
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/FileIcon.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const FileIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/FileNotFoundIcon.tsx b/packages/oc-docs/src/assets/icons/FileNotFoundIcon.tsx
new file mode 100644
index 00000000..25e0aa73
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/FileNotFoundIcon.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const FileNotFoundIcon: React.FC = () => (
+
+);
+
+export default FileNotFoundIcon;
diff --git a/packages/oc-docs/src/assets/icons/FolderIcon.tsx b/packages/oc-docs/src/assets/icons/FolderIcon.tsx
new file mode 100644
index 00000000..ad3d48dd
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/FolderIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+/** Folder outline, the search palette's folder filter options. */
+export const FolderIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/GlobeIcon.tsx b/packages/oc-docs/src/assets/icons/GlobeIcon.tsx
new file mode 100644
index 00000000..e0d76292
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/GlobeIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const GlobeIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/HamburgerIcon.tsx b/packages/oc-docs/src/assets/icons/HamburgerIcon.tsx
new file mode 100644
index 00000000..7765242c
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/HamburgerIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+/** Three bars — Topbar sidebar (hamburger) toggle. */
+export const HamburgerIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/OverflowIcon.tsx b/packages/oc-docs/src/assets/icons/OverflowIcon.tsx
new file mode 100644
index 00000000..d105d0a0
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/OverflowIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+
+/** Vertical ellipsis — Topbar mobile overflow trigger. */
+export const OverflowIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/PlayIcon.tsx b/packages/oc-docs/src/assets/icons/PlayIcon.tsx
new file mode 100644
index 00000000..5f589492
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/PlayIcon.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+
+export const PlayIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/RefreshIcon.tsx b/packages/oc-docs/src/assets/icons/RefreshIcon.tsx
new file mode 100644
index 00000000..d76b8093
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/RefreshIcon.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const RefreshIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/SearchIcon.tsx b/packages/oc-docs/src/assets/icons/SearchIcon.tsx
new file mode 100644
index 00000000..4a31c171
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/SearchIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+/** Magnifying glass — Topbar search toggle. */
+export const SearchIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/SendIcon.tsx b/packages/oc-docs/src/assets/icons/SendIcon.tsx
new file mode 100644
index 00000000..19a6b4dd
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/SendIcon.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+/** Paper-plane "send" icon used by the Try action. */
+export const SendIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/SettingsIcon.tsx b/packages/oc-docs/src/assets/icons/SettingsIcon.tsx
new file mode 100644
index 00000000..7e482279
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/SettingsIcon.tsx
@@ -0,0 +1,9 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const SettingsIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/SidebarToggleIcon.tsx b/packages/oc-docs/src/assets/icons/SidebarToggleIcon.tsx
new file mode 100644
index 00000000..40329bf9
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/SidebarToggleIcon.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+interface SidebarToggleIconProps {
+ /** Fills the sidebar column when the playground sidebar is open. */
+ active?: boolean;
+}
+
+export const SidebarToggleIcon: React.FC = ({ active = false }) => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/TrashIcon.tsx b/packages/oc-docs/src/assets/icons/TrashIcon.tsx
new file mode 100644
index 00000000..59df4350
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/TrashIcon.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import { baseIconProps } from './baseIconProps';
+
+export const TrashIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/WarningIcon.tsx b/packages/oc-docs/src/assets/icons/WarningIcon.tsx
new file mode 100644
index 00000000..6f705314
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/WarningIcon.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+/** Warning circle with an exclamation mark; sized by its container. */
+export const WarningIcon: React.FC = () => (
+
+);
diff --git a/packages/oc-docs/src/assets/icons/baseIconProps.ts b/packages/oc-docs/src/assets/icons/baseIconProps.ts
new file mode 100644
index 00000000..4e96f1c7
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/baseIconProps.ts
@@ -0,0 +1,15 @@
+import type { SVGProps } from 'react';
+
+/** Shared stroke styling. `currentColor` lets the icon inherit the surrounding
+ * theme colour, so it adapts when the theme changes. */
+export const baseIconProps: SVGProps = {
+ width: 20,
+ height: 20,
+ viewBox: '0 0 24 24',
+ fill: 'none',
+ stroke: 'currentColor',
+ strokeWidth: 2,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round',
+ 'aria-hidden': true
+};
diff --git a/packages/oc-docs/src/assets/icons/index.ts b/packages/oc-docs/src/assets/icons/index.ts
new file mode 100644
index 00000000..a54d4b20
--- /dev/null
+++ b/packages/oc-docs/src/assets/icons/index.ts
@@ -0,0 +1,29 @@
+export * from './SearchIcon';
+export * from './WarningIcon';
+export * from './CaretIcon';
+export * from './CloseIcon';
+export * from './FolderIcon';
+export * from './ChevronDownIcon';
+export * from './HamburgerIcon';
+export * from './OverflowIcon';
+export * from './BrunoGlyph';
+export * from './GlobeIcon';
+export * from './CubeIcon';
+export * from './ChevronLeftIcon';
+export * from './ChevronRightIcon';
+export * from './BookIcon';
+export * from './ExpandIcon';
+export * from './PlayIcon';
+export * from './SendIcon';
+export * from './EyeIcon';
+export * from './EyeOffIcon';
+export * from './FileIcon';
+export * from './FileNotFoundIcon';
+export * from './RefreshIcon';
+export * from './DockInlineIcon';
+export * from './DockBottomIcon';
+export * from './DockModalIcon';
+export * from './SidebarToggleIcon';
+export * from './SettingsIcon';
+export * from './TrashIcon';
+export * from './ExampleIcon';
diff --git a/packages/oc-docs/src/assets/opencollection-logo.svg b/packages/oc-docs/src/assets/opencollection-logo.svg
new file mode 100644
index 00000000..62f1dc76
--- /dev/null
+++ b/packages/oc-docs/src/assets/opencollection-logo.svg
@@ -0,0 +1,7 @@
+
diff --git a/packages/oc-docs/src/assets/react.svg b/packages/oc-docs/src/assets/react.svg
new file mode 100644
index 00000000..6c87de9b
--- /dev/null
+++ b/packages/oc-docs/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/oc-docs/src/components/AppShell/AppShell.tsx b/packages/oc-docs/src/components/AppShell/AppShell.tsx
new file mode 100644
index 00000000..aec675fd
--- /dev/null
+++ b/packages/oc-docs/src/components/AppShell/AppShell.tsx
@@ -0,0 +1,181 @@
+import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
+import { useLocation } from 'react-router-dom';
+import Topbar from '../Topbar/Topbar';
+import EnvSwitcher from '../EnvSwitcher/EnvSwitcher';
+import ShowVarsToggle from '../ShowVarsToggle/ShowVarsToggle';
+import ThemeToggle from '../ThemeToggle/ThemeToggle';
+import Sidebar from '../Docs/Sidebar/Sidebar';
+import SidebarDrawer from '../SidebarDrawer/SidebarDrawer';
+import IconButton from '../../ui/IconButton/IconButton';
+import { ChevronLeftIcon, ChevronRightIcon } from '../../assets/icons';
+import PageRouter from '../PageRouter/PageRouter';
+import Playground from '../Playground/Playground';
+import SearchBar from '../Search/SearchBar/SearchBar';
+import { useSearchHotkey, usePlaygroundUrlState, useElementWidth } from '../../hooks';
+import { useAppSelector } from '../../store/hooks';
+import { selectDocsCollection } from '../../store/slices/docs';
+import { selectGitCollectionUrl } from '../../store/slices/app';
+import { useActiveResolution } from '../../routing/hooks';
+import { exampleSlugForIndex } from '../../routing/slug';
+import type { HttpRequest } from '@opencollection/types/requests/http';
+import { layoutModeForWidth } from '../../hooks/useTopbarLayout';
+import { buildFetchInBrunoUrl } from '../../utils/buildFetchInBrunoUrl';
+import { StyledWrapper } from './StyledWrapper';
+
+interface AppShellProps {
+ logo?: React.ReactNode;
+ testId?: string;
+}
+
+const AppShell: React.FC = ({ logo, testId = 'app-shell' }) => {
+ const collection = useAppSelector(selectDocsCollection);
+ const gitCollectionUrl = useAppSelector(selectGitCollectionUrl);
+ const resolution = useActiveResolution();
+
+ // Single source of truth for search-open, shared by the Topbar (icon + row)
+ // and the SearchBar panel so they never disagree. ⌘K / Ctrl+K is mounted here
+ // so it works regardless of the Topbar's responsive layout.
+ const [searchOpen, setSearchOpen] = useState(false);
+ // Bumped on every hotkey press so the field refocuses even when the panel is
+ // already open (open state alone wouldn't change, so it can't drive focus).
+ const [searchFocusNonce, setSearchFocusNonce] = useState(0);
+ const openSearch = useCallback(() => {
+ setSearchOpen(true);
+ setSearchFocusNonce((n) => n + 1);
+ }, []);
+ useSearchHotkey(openSearch);
+
+ // Responsive mode follows the docs area width, not the window: when the inline
+ // playground takes part of the row, the docs column (`.appshell-body`) shrinks
+ // and the docs chrome (topbar + sidebar) should go tablet/mobile accordingly.
+ // In the other docks the shell is a column, so this equals the window width.
+ const bodyRef = useRef(null);
+ const contentRef = useRef(null);
+ const bodyWidth = useElementWidth(bodyRef);
+ const mode = layoutModeForWidth(bodyWidth || (typeof window !== 'undefined' ? window.innerWidth : 1024));
+ const isDesktop = mode === 'desktop';
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
+ const [drawerOpen, setDrawerOpen] = useState(false);
+ const { pathname } = useLocation();
+
+ const { open: playgroundOpen, dock: playgroundDock, openPlayground, setRequestExample } = usePlaygroundUrlState();
+ // Bumped on every Try click so the bottom sheet re-expands from collapsed even
+ // when the requested slug is unchanged (a slug change alone wouldn't signal it).
+ const [playgroundOpenNonce, setPlaygroundOpenNonce] = useState(0);
+
+ useEffect(() => {
+ setDrawerOpen(false);
+ }, [pathname]);
+
+ useLayoutEffect(() => {
+ const content = contentRef.current;
+ if (content) content.scrollTop = 0;
+ }, [pathname]);
+
+ // Close the mobile drawer when moving to desktop, so it doesn't reappear on
+ // its own if the viewport shrinks back to mobile.
+ useEffect(() => {
+ if (isDesktop) setDrawerOpen(false);
+ }, [isDesktop]);
+
+ const closeDrawer = useCallback(() => setDrawerOpen(false), []);
+ const toggleSidebar = useCallback(() => {
+ if (mode === 'desktop') setSidebarCollapsed((collapsed) => !collapsed);
+ else setDrawerOpen((open) => !open);
+ }, [mode]);
+
+ const handleOpenPlayground = useCallback(() => {
+ openPlayground(resolution?.entry.slug);
+ setPlaygroundOpenNonce((nonce) => nonce + 1);
+ }, [openPlayground, resolution]);
+
+ // Open the playground on a specific example of the current request (its Try
+ // action): pgReq keeps the request, pgEx the example, so a share/reload lands
+ // on the same read-only example view.
+ const handleTryExample = (index: number) => {
+ const entry = resolution?.entry;
+ if (!entry) return;
+ setRequestExample(entry.slug, exampleSlugForIndex(entry.item as HttpRequest | null, index));
+ };
+
+ return (
+
+
+
+ }
+ searchOpen={searchOpen}
+ onSearchOpenChange={setSearchOpen}
+ onToggleSidebar={toggleSidebar}
+ envSwitcherSlot={
+ <>
+
+
+ >
+ }
+ openInBrunoHref={buildFetchInBrunoUrl(gitCollectionUrl)}
+ themeToggleSlot={
}
+ />
+
+
+
+ {isDesktop && !sidebarCollapsed && (
+ <>
+
+
setSidebarCollapsed(true)}
+ >
+
+
+ >
+ )}
+ {isDesktop && sidebarCollapsed && (
+
setSidebarCollapsed(false)}
+ >
+
+
+ )}
+
+
+
+
+
+
+
+ {playgroundOpen && }
+
+ {!isDesktop && (
+
+
+
+ )}
+
+ );
+};
+
+export default AppShell;
diff --git a/packages/oc-docs/src/components/AppShell/StyledWrapper.ts b/packages/oc-docs/src/components/AppShell/StyledWrapper.ts
new file mode 100644
index 00000000..a7c7d333
--- /dev/null
+++ b/packages/oc-docs/src/components/AppShell/StyledWrapper.ts
@@ -0,0 +1,116 @@
+import styled from '@emotion/styled';
+
+export const StyledWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ height: 100vh;
+ box-sizing: border-box;
+
+ &[data-dock='inline'] {
+ flex-direction: row;
+ }
+
+ .appshell-body {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-width: 0;
+ min-height: 0;
+ overflow: hidden;
+ container-type: inline-size;
+ container-name: docs;
+ }
+
+ .appshell-main {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ min-height: 0;
+ }
+
+ .appshell-row {
+ display: flex;
+ flex: 1;
+ min-height: 0;
+ position: relative;
+ }
+
+ .appshell-sidebar {
+ width: var(--sidebar-width);
+ flex-shrink: 0;
+ height: 100%;
+ overflow: hidden;
+ border-right: 1px solid var(--oc-border-border0);
+ background-color: var(--oc-background-base);
+ }
+
+ .appshell-content {
+ flex: 1;
+ min-width: 0;
+ height: 100%;
+ overflow-y: auto;
+ overscroll-behavior-y: contain;
+ scrollbar-width: thin;
+ scrollbar-color: var(--oc-scrollbar-color) transparent;
+ }
+
+ .appshell-content::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ .appshell-content::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ .appshell-content::-webkit-scrollbar-thumb {
+ background-color: var(--oc-scrollbar-color);
+ border-radius: 20px;
+ }
+
+ .appshell-content::-webkit-scrollbar-thumb:hover {
+ background-color: color-mix(in srgb, var(--oc-text) 20%, transparent);
+ }
+
+ .appshell-collapse,
+ .appshell-reopen {
+ position: absolute;
+ z-index: calc(var(--z-sidebar, 5) + 1);
+ width: 22px;
+ height: 22px;
+ border: 1px solid var(--oc-border-border0);
+ border-radius: var(--oc-radius);
+ background-color: var(--oc-background-base);
+ color: var(--oc-colors-text-subtext0);
+ }
+
+ .appshell-collapse svg,
+ .appshell-reopen svg {
+ width: 14px;
+ height: 14px;
+ }
+
+ .appshell-collapse:hover,
+ .appshell-reopen:hover {
+ background-color: var(--oc-background-surface0);
+ color: var(--text-secondary);
+ }
+
+ .appshell-collapse {
+ top: 14px;
+ left: calc(var(--sidebar-width) - 12px);
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.15s ease;
+ }
+
+ .appshell-sidebar:hover ~ .appshell-collapse,
+ .appshell-collapse:hover {
+ opacity: 1;
+ pointer-events: auto;
+ }
+
+ .appshell-reopen {
+ top: 14px;
+ left: 12px;
+ }
+`;
diff --git a/packages/oc-docs/src/components/AuthDetails/AuthDetails.spec.tsx b/packages/oc-docs/src/components/AuthDetails/AuthDetails.spec.tsx
new file mode 100644
index 00000000..04e605dc
--- /dev/null
+++ b/packages/oc-docs/src/components/AuthDetails/AuthDetails.spec.tsx
@@ -0,0 +1,220 @@
+import React from 'react';
+import { renderToStaticMarkup } from 'react-dom/server';
+import { parse } from 'node-html-parser';
+import { describe, it, expect } from 'vitest';
+import { AuthDetails } from './AuthDetails';
+import { AUTH_MODE_LABELS } from '../../constants';
+import { SECRET_MASK } from '../../constants';
+
+const renderAuth = (ui: React.ReactElement) => {
+ const html = renderToStaticMarkup(ui);
+ const root = parse(html);
+ // Strip emotion's inline