diff --git a/.github/skills/prepare-release/SKILL.md b/.github/skills/prepare-release/SKILL.md new file mode 100644 index 00000000..5a2a7ffa --- /dev/null +++ b/.github/skills/prepare-release/SKILL.md @@ -0,0 +1,133 @@ +--- +name: prepare-release +description: Prepare a release for the Azure App Configuration JavaScript Provider. Use when user mentions release preparation, version bump, creating merge PRs, preview release, or stable release for this project. +--- + +# Prepare Release + +This skill automates the release preparation workflow for the [Azure App Configuration JavaScript Provider](https://github.com/Azure/AppConfiguration-JavaScriptProvider) project. + +## When to Use This Skill + +Use this skill when you need to: +- Bump the package version for a new stable or preview release +- Create merge PRs to sync branches (main → preview, main → release/stable, preview → release) +- Prepare all the PRs needed before publishing a new release +- Resolve merge conflicts between main and preview branches + +## Background + +### Repository Information +- **GitHub Repo**: https://github.com/Azure/AppConfiguration-JavaScriptProvider +- **Package Name**: `@azure/app-configuration-provider` + +### Branch Structure +- `main` – primary development branch for stable releases +- `preview` – development branch for preview releases +- `release/stable/v{major}` – release branch for stable versions (e.g., `release/stable/v2`) +- `release/v{major}` – release branch for preview versions (e.g., `release/v2`) + +### Version Files +The version must be updated in **all four locations** simultaneously: +1. `src/version.ts` – line 4: `export const VERSION = "";` +2. `package.json` – line 3: `"version": "",` +3. `package-lock.json` – line 3: `"version": "",` +4. `package-lock.json` – line 9: `"version": "",` + +### Version Format +- **Stable**: `{major}.{minor}.{patch}` (e.g., `2.4.0`) +- **Preview**: `{major}.{minor}.{patch}-preview` (e.g., `2.4.2-preview`) + +## Quick Start + +Ask the user whether this is a **stable** or **preview** release, and what the **new version number** should be. Then follow the appropriate workflow below. + +--- + +### Workflow A: Stable Release + +#### Step 1: Version Bump PR + +Create a version bump PR targeting `main` by running the version bump script: + +```bash +./scripts/version-bump.sh +``` + +For example: `./scripts/version-bump.sh 2.5.0` + +The script will automatically: +1. Read the current version from `src/version.ts`. +2. Create a new branch from `main` named `/version-` (e.g., `linglingye/version-2.5.0`). +3. Update the version in all four files (`src/version.ts`, `package.json`, `package-lock.json` lines 3 and 9). +4. Commit, push, and create a PR to `main` with title: `Version bump `. + +When the script prompts `Proceed? [y/N]`, confirm by entering `y`. + +#### Step 2: Merge Main to Release Branch + +After the version bump PR is merged, create a PR to merge `main` into the stable release branch by running: + +```bash +./scripts/merge-to-release.sh +``` + +For example: `./scripts/merge-to-release.sh 2.5.0` + +When the script prompts `Proceed? [y/N]`, confirm by entering `y`. + +> **Important**: Use "Merge commit" (not squash) when merging this PR to preserve commit history. + +--- + +### Workflow B: Preview Release + +#### Step 1: Merge Main to Preview (Conflict Resolution) + +Create a PR to merge `main` into `preview`. This will likely have conflicts. + +1. Fetch the latest `main` and `preview` branches. +2. Create a new branch from `preview` named `/resolve-conflict` (or similar). +3. Merge `main` into this branch. If there are conflicts, inform the user and let them resolve manually. +4. Push the branch and create a PR targeting `preview` with title: `Merge main to preview`. + +> **Important**: Use "Merge commit" (not squash) when merging this PR. + +**Sample PR**: https://github.com/Azure/AppConfiguration-JavaScriptProvider/pull/272 + +#### Step 2: Version Bump PR + +After the merge-to-preview PR is merged, create a version bump PR targeting `preview` by running the version bump script with the `--preview` flag: + +```bash +./scripts/version-bump.sh --preview +``` + +For example: `./scripts/version-bump.sh 2.5.1-preview --preview` + +When the script prompts `Proceed? [y/N]`, confirm by entering `y`. + +#### Step 3: Merge Preview to Release Branch + +After the version bump PR is merged, create a PR to merge `preview` into the preview release branch by running: + +```bash +./scripts/merge-to-release.sh --preview +``` + +For example: `./scripts/merge-to-release.sh 2.5.1-preview --preview` + +When the script prompts `Proceed? [y/N]`, confirm by entering `y`. + +> **Important**: Use "Merge commit" (not squash) when merging this PR. + +--- + +## Review Checklist + +Each PR should be reviewed with the following checks: +- [ ] Version is updated consistently across all 3 files +- [ ] No unintended file changes are included +- [ ] Merge PRs use **merge commit** strategy (not squash) +- [ ] Branch names follow the naming conventions +- [ ] All CI checks pass diff --git a/.gitignore b/.gitignore index 1ccd7b97..70fc8a60 100644 --- a/.gitignore +++ b/.gitignore @@ -410,4 +410,4 @@ types/ *.tgz # examples -examples/package-lock.json +examples/*/package-lock.json diff --git a/examples/console-app/README.md b/examples/console-app/README.md index ccee57bb..3de15e98 100644 --- a/examples/console-app/README.md +++ b/examples/console-app/README.md @@ -31,6 +31,8 @@ To run the examples using the published version of the package: npm install ``` + This will install all required packages listed in `package.json` with their latest compatible versions. + 2. There are two ways to run the examples using correct credentials: - Edit the file `.env.template`, adding the access keys to your App Configuration store. and rename the file from `.env.template` to just `.env`. The examples will read this file automatically. diff --git a/examples/console-app/package-lock.json b/examples/console-app/package-lock.json deleted file mode 100644 index fb1b22be..00000000 --- a/examples/console-app/package-lock.json +++ /dev/null @@ -1,1417 +0,0 @@ -{ - "name": "examples", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@azure/app-configuration-provider": "*", - "@azure/identity": "^4.1.0", - "dotenv": "^16.3.1", - "express": "^4.21.2" - } - }, - "..": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "@azure/app-configuration": "^1.6.1", - "@azure/identity": "^4.2.1", - "@azure/keyvault-secrets": "^4.7.0" - }, - "devDependencies": { - "@rollup/plugin-typescript": "^11.1.2", - "@types/mocha": "^10.0.4", - "@types/node": "^22.7.7", - "@types/sinon": "^17.0.1", - "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^6.6.0", - "@typescript-eslint/parser": "^6.6.0", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "dotenv": "^16.3.1", - "eslint": "^8.48.0", - "mocha": "^10.2.0", - "nock": "^13.3.3", - "rimraf": "^5.0.1", - "rollup": "^3.29.5", - "rollup-plugin-dts": "^5.3.0", - "sinon": "^15.2.0", - "tslib": "^2.6.0", - "typescript": "^5.6.3", - "uuid": "^9.0.1" - } - }, - "node_modules/@azure/abort-controller": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", - "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/app-configuration-provider": { - "resolved": "..", - "link": true - }, - "node_modules/@azure/core-auth": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", - "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-client": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", - "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-rest-pipeline": "^1.9.1", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.6.1", - "@azure/logger": "^1.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-rest-pipeline": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz", - "integrity": "sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.8.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.9.0", - "@azure/logger": "^1.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-tracing": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", - "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-util": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", - "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/identity": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.5.0.tgz", - "integrity": "sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.9.0", - "@azure/core-client": "^1.9.2", - "@azure/core-rest-pipeline": "^1.17.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^3.26.1", - "@azure/msal-node": "^2.15.0", - "events": "^3.0.0", - "jws": "^4.0.0", - "open": "^8.0.0", - "stoppable": "^1.1.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/logger": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", - "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/msal-browser": { - "version": "3.26.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.26.1.tgz", - "integrity": "sha512-y78sr9g61aCAH9fcLO1um+oHFXc1/5Ap88RIsUSuzkm0BHzFnN+PXGaQeuM1h5Qf5dTnWNOd6JqkskkMPAhh7Q==", - "dependencies": { - "@azure/msal-common": "14.15.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-common": { - "version": "14.15.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.15.0.tgz", - "integrity": "sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-node": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.15.0.tgz", - "integrity": "sha512-gVPW8YLz92ZeCibQH2QUw96odJoiM3k/ZPH3f2HxptozmH6+OnyyvKXo/Egg39HAM230akarQKHf0W74UHlh0Q==", - "dependencies": { - "@azure/msal-common": "14.15.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=16" - } - }, - "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/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/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/body-parser/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/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/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.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "engines": { - "node": ">=8" - } - }, - "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/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/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/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/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/express/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/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/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/finalhandler/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/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.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "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/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", - "license": "MIT", - "dependencies": { - "jwa": "^1.4.2", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "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.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "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/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "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.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/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" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz", - "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.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/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/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/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/send/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/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/serve-static/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/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/serve-static/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/serve-static/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/serve-static/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/serve-static/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/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.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", - "engines": { - "node": ">=4", - "npm": ">=6" - } - }, - "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/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==" - }, - "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/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/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - } - } -} diff --git a/examples/web-app/README.md b/examples/web-app/README.md index a6e6b40c..c6f764b3 100644 --- a/examples/web-app/README.md +++ b/examples/web-app/README.md @@ -31,6 +31,8 @@ To run the examples using the published version of the package: npm install ``` + This will install all required packages listed in `package.json` with their latest compatible versions. + 2. There are two ways to run the examples using correct credentials: - Edit the file `.env.template`, adding the access keys to your App Configuration store. and rename the file from `.env.template` to just `.env`. The examples will read this file automatically. diff --git a/examples/web-app/package-lock.json b/examples/web-app/package-lock.json deleted file mode 100644 index 9e249f98..00000000 --- a/examples/web-app/package-lock.json +++ /dev/null @@ -1,1570 +0,0 @@ -{ - "name": "web-example", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@azure/app-configuration-provider": "*", - "@azure/identity": "^4.1.0", - "dotenv": "^16.3.1", - "express": "^4.22.1" - } - }, - "node_modules/@azure/abort-controller": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", - "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/app-configuration": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@azure/app-configuration/-/app-configuration-1.8.0.tgz", - "integrity": "sha512-RO4IGZMa3hI1yVhvb5rPr+r+UDxe4VDxbntFZIc5fsUPGqZbKzmGR2wABEtlrC2SU5YX6tL+NS3xWb4vf1M9lQ==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.5.0", - "@azure/core-http-compat": "^2.0.0", - "@azure/core-lro": "^2.5.1", - "@azure/core-paging": "^1.4.0", - "@azure/core-rest-pipeline": "^1.6.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.6.1", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/app-configuration-provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/app-configuration-provider/-/app-configuration-provider-2.0.0.tgz", - "integrity": "sha512-N3gQ9m5Iu9fApLkWUOqUGgtUsNuUSIJe2j1gUBv1/u5FQE9JfsMetw6fVlxjVgh+qrd8c4kkdK1f6hvLn/K4Lg==", - "dependencies": { - "@azure/app-configuration": "^1.6.1", - "@azure/identity": "^4.2.1", - "@azure/keyvault-secrets": "^4.7.0" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/@azure/identity": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.7.0.tgz", - "integrity": "sha512-6z/S2KorkbKaZ0DgZFVRdu7RCuATmMSTjKpuhj7YpjxkJ0vnJ7kTM3cpNgzFgk9OPYfZ31wrBEtC/iwAS4jQDA==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.9.0", - "@azure/core-client": "^1.9.2", - "@azure/core-rest-pipeline": "^1.17.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^4.2.0", - "@azure/msal-node": "^3.2.1", - "events": "^3.0.0", - "jws": "^4.0.0", - "open": "^10.1.0", - "stoppable": "^1.1.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/@azure/msal-browser": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.5.0.tgz", - "integrity": "sha512-H7mWmu8yI0n0XxhJobrgncXI6IU5h8DKMiWDHL5y+Dc58cdg26GbmaMUehbUkdKAQV2OTiFa4FUa6Fdu/wIxBg==", - "dependencies": { - "@azure/msal-common": "15.2.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/@azure/msal-common": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.2.0.tgz", - "integrity": "sha512-HiYfGAKthisUYqHG1nImCf/uzcyS31wng3o+CycWLIM9chnYJ9Lk6jZ30Y6YiYYpTQ9+z/FGUpiKKekd3Arc0A==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/@azure/msal-node": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.2.3.tgz", - "integrity": "sha512-0eaPqBIWEAizeYiXdeHb09Iq0tvHJ17ztvNEaLdr/KcJJhJxbpkkEQf09DB+vKlFE0tzYi7j4rYLTXtES/InEQ==", - "dependencies": { - "@azure/msal-common": "15.2.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@azure/app-configuration-provider/node_modules/open": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", - "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", - "dependencies": { - "default-browser": "^5.2.1", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^3.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@azure/core-auth": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", - "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-client": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", - "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-rest-pipeline": "^1.9.1", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.6.1", - "@azure/logger": "^1.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-http-compat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.2.0.tgz", - "integrity": "sha512-1kW8ZhN0CfbNOG6C688z5uh2yrzALE7dDXHiR9dY4vt+EbhGZQSbjDa5bQd2rf3X2pdWMsXbqbArxUyeNdvtmg==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-client": "^1.3.0", - "@azure/core-rest-pipeline": "^1.19.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-lro": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", - "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.2.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-paging": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", - "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-rest-pipeline": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.19.0.tgz", - "integrity": "sha512-bM3308LRyg5g7r3Twprtqww0R/r7+GyVxj4BafcmVPo4WQoGt5JXuaqxHEFjw2o3rvFZcUPiqJMg6WuvEEeVUA==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.8.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-tracing": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", - "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-util": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", - "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/identity": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.1.0.tgz", - "integrity": "sha512-BhYkF8Xr2gXjyDxocm0pc9RI5J5a1jw8iW0dw6Bx95OGdYbuMyFZrrwNw4eYSqQ2BB6FZOqpJP3vjsAqRcvDhw==", - "dependencies": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.5.0", - "@azure/core-client": "^1.4.0", - "@azure/core-rest-pipeline": "^1.1.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.3.0", - "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^3.11.1", - "@azure/msal-node": "^2.6.6", - "events": "^3.0.0", - "jws": "^4.0.0", - "open": "^8.0.0", - "stoppable": "^1.1.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/identity/node_modules/@azure/abort-controller": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", - "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", - "dependencies": { - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@azure/keyvault-common": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/keyvault-common/-/keyvault-common-2.0.0.tgz", - "integrity": "sha512-wRLVaroQtOqfg60cxkzUkGKrKMsCP6uYXAOomOIysSMyt1/YM0eUn9LqieAWM8DLcU4+07Fio2YGpPeqUbpP9w==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.5.0", - "@azure/core-rest-pipeline": "^1.8.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.10.0", - "@azure/logger": "^1.1.4", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/keyvault-secrets": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@azure/keyvault-secrets/-/keyvault-secrets-4.9.0.tgz", - "integrity": "sha512-XkLsuzxFdhVIOVcELhso8OhQgY2lSWZcZn6fqjE848FwP9lJemJhu7nxYy8Q1nns6XqPB0WsTPmEkR8eu852vA==", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.5.0", - "@azure/core-http-compat": "^2.0.1", - "@azure/core-lro": "^2.2.0", - "@azure/core-paging": "^1.1.1", - "@azure/core-rest-pipeline": "^1.8.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", - "@azure/keyvault-common": "^2.0.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/logger": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", - "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/msal-browser": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.28.1.tgz", - "integrity": "sha512-OHHEWMB5+Zrix8yKvLVzU3rKDFvh7SOzAzXfICD7YgUXLxfHpTPX2pzOotrri1kskwhHqIj4a5LvhZlIqE7C7g==", - "dependencies": { - "@azure/msal-common": "14.16.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-common": { - "version": "14.16.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.16.0.tgz", - "integrity": "sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-node": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.2.tgz", - "integrity": "sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==", - "dependencies": { - "@azure/msal-common": "14.16.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=16" - } - }, - "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==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "engines": { - "node": ">= 14" - } - }, - "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==" - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/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==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "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==", - "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==", - "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==", - "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==" - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/default-browser": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "engines": { - "node": ">=8" - } - }, - "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==", - "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==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "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==", - "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==", - "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==", - "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==" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/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==" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/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==" - }, - "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==" - }, - "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==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-inside-container/node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", - "license": "MIT", - "dependencies": { - "jwa": "^1.4.2", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/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==" - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==", - "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==" - }, - "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==", - "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==", - "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==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "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==" - }, - "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==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "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==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/raw-body/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/run-applescript": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "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==", - "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==" - }, - "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==", - "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==" - }, - "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==", - "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==", - "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==", - "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==", - "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==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", - "engines": { - "node": ">=4", - "npm": ">=6" - } - }, - "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==", - "engines": { - "node": ">=0.6" - } - }, - "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==" - }, - "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==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "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==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - } - } -} diff --git a/package-lock.json b/package-lock.json index 1ade5776..f6799a77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@azure/app-configuration-provider", - "version": "2.5.0-preview", + "version": "2.7.0-preview", "lockfileVersion": 3, "requires": true, "packages": { @@ -9,7 +9,8 @@ "version": "2.5.0-preview", "license": "MIT", "dependencies": { - "@azure/app-configuration": "^1.11.0", + "@azure-rest/core-client": "^2.6.0", + "@azure/app-configuration": "1.13.0-beta.1", "@azure/core-rest-pipeline": "^1.6.0", "@azure/identity": "^4.2.1", "@azure/keyvault-secrets": "^4.7.0", @@ -21,39 +22,40 @@ "@types/chai-as-promised": "8.0.2", "@types/mocha": "^10.0.10", "@types/node": "^22.18.0", - "@types/sinon": "^17.0.4", + "@types/sinon": "^21.0.1", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^8.41.0", "@typescript-eslint/parser": "^8.41.0", - "@vitest/browser": "^3.2.4", + "@vitest/browser": "^4.1.8", + "@vitest/browser-playwright": "^4.1.8", "chai": "^4.5.0", "chai-as-promised": "^7.1.2", "cpy-cli": "^6.0.0", "dotenv": "^17.2.1", "eslint": "^9.34.0", - "mocha": "^11.7.1", + "mocha": "^11.7.6", "nock": "^14.0.10", - "playwright": "^1.55.0", + "playwright": "^1.60.0", "rimraf": "^6.0.1", - "rollup": "^4.50.0", + "rollup": "^4.59.0", "rollup-plugin-dts": "^6.2.3", - "sinon": "^21.0.0", + "sinon": "^21.1.2", "tslib": "^2.8.1", "typescript": "^5.9.2", - "uuid": "^11.1.0", - "vitest": "^3.2.4" + "uuid": "^14.0.0", + "vitest": "^4.1.8" } }, "node_modules/@azure-rest/core-client": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.5.0.tgz", - "integrity": "sha512-KMVIPxG6ygcQ1M2hKHahF7eddKejYsWTjoLIfTWiqnaj42dBkYzj4+S8rK9xxmlOaEHKZHcMrRbm0NfN4kgwHw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@azure-rest/core-client/-/core-client-2.6.1.tgz", + "integrity": "sha512-KzI10qnkWTsVS2yRBUdc8NLUJ1rOm+292mYs7Pe9wqAj/jv4bRskVm1l8XkKeVTN0OCQtrU5RG0Yhjbz1Wmg7g==", "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.9.0", - "@azure/core-rest-pipeline": "^1.5.0", - "@azure/core-tracing": "^1.0.1", + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" }, @@ -74,16 +76,17 @@ } }, "node_modules/@azure/app-configuration": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@azure/app-configuration/-/app-configuration-1.11.0.tgz", - "integrity": "sha512-ehfTNvVyr4lFKz1Nfynubqg/kEWMFMjCQs8lADDa+U1HG96QIoelMYFbfWIixw4KhOqoCAIOWEp4bAXIZ0/V/w==", + "version": "1.13.0-beta.1", + "resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@azure/app-configuration/-/app-configuration-1.13.0-beta.1.tgz", + "integrity": "sha1-Ki9uFulaC34U0jPNU2Eo2u1myL8=", "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.0.0", + "@azure-rest/core-client": "^2.6.0", + "@azure/abort-controller": "^2.1.2", "@azure/core-auth": "^1.3.0", - "@azure/core-client": "^1.5.0", + "@azure/core-client": "^1.9.2", "@azure/core-http-compat": "^2.0.0", - "@azure/core-lro": "^2.5.1", + "@azure/core-lro": "^3.1.0", "@azure/core-paging": "^1.4.0", "@azure/core-rest-pipeline": "^1.6.0", "@azure/core-tracing": "^1.0.0", @@ -92,7 +95,22 @@ "tslib": "^2.2.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.0.0" + } + }, + "node_modules/@azure/app-configuration/node_modules/@azure/core-lro": { + "version": "3.4.0", + "resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@azure/core-lro/-/core-lro-3.4.0.tgz", + "integrity": "sha1-c0Zb0X3lxduw8noJH29mGnBHC78=", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" } }, "node_modules/@azure/core-auth": { @@ -128,17 +146,19 @@ } }, "node_modules/@azure/core-http-compat": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.3.0.tgz", - "integrity": "sha512-qLQujmUypBBG0gxHd0j6/Jdmul6ttl24c8WGiLXIk7IHXdBlfoBqW27hyz3Xn6xbfdyVSarl1Ttbk0AwnZBYCw==", + "version": "2.5.0", + "resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@azure/core-http-compat/-/core-http-compat-2.5.0.tgz", + "integrity": "sha1-14BmGln4pDL+yyt8b6LVgi3KHeo=", "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-client": "^1.3.0", - "@azure/core-rest-pipeline": "^1.20.0" + "@azure/abort-controller": "^2.1.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" + }, + "peerDependencies": { + "@azure/core-client": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0" } }, "node_modules/@azure/core-lro": { @@ -213,9 +233,9 @@ } }, "node_modules/@azure/identity": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.11.1.tgz", - "integrity": "sha512-0ZdsLRaOyLxtCYgyuqyWqGU5XQ9gGnjxgfoNTt1pvELGkkUFrMATABZFIq8gusM7N1qbqpVtwLOhk0d/3kacLg==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", + "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", "license": "MIT", "dependencies": { "@azure/abort-controller": "^2.0.0", @@ -225,8 +245,8 @@ "@azure/core-tracing": "^1.0.0", "@azure/core-util": "^1.11.0", "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^4.2.0", - "@azure/msal-node": "^3.5.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.0", "open": "^10.1.0", "tslib": "^2.2.0" }, @@ -290,47 +310,37 @@ } }, "node_modules/@azure/msal-browser": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.21.1.tgz", - "integrity": "sha512-qGtzX3HJfJsOVeDcVrFZAYZoxLRjrW2lXzXqijgiBA5EtM9ud7F/EYgKKQ9TJU/WtE46szuZtQZx5vD4pEiknA==", + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.11.0.tgz", + "integrity": "sha512-zkGNYS3TwY8lUpPIafAmsFCYZbgFixY9y/LZB9GUg0IILoHTqpN26j5OrkL1AQThh/YdZsawe4iWXfp85lFVxg==", "license": "MIT", "dependencies": { - "@azure/msal-common": "15.12.0" + "@azure/msal-common": "16.6.2" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.12.0.tgz", - "integrity": "sha512-4ucXbjVw8KJ5QBgnGJUeA07c8iznwlk5ioHIhI4ASXcXgcf2yRFhWzYOyWg/cI49LC9ekpFJeQtO3zjDTbl6TQ==", + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.6.2.tgz", + "integrity": "sha512-hQjjsekAjB00cM1EmatWJlzhEoK2Qhz7Rj5gvM6tYf8iL7RM3tkxlpU9fG0+ofkulzg9AEEA6dIEnSmDr5ZqUA==", "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.7.3.tgz", - "integrity": "sha512-MoJxkKM/YpChfq4g2o36tElyzNUMG8mfD6u8NbuaPAsqfGpaw249khAcJYNoIOigUzRw45OjXCOrexE6ImdUxg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.2.2.tgz", + "integrity": "sha512-toS+2AePxqyzb0YOKttDOOiSl3jrkK9aiqIvpurpis0O34QcIS5gToqrgT39p04Dpxw3YoUU0lxJKTpSFFfA6Q==", "license": "MIT", "dependencies": { - "@azure/msal-common": "15.12.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" + "@azure/msal-common": "16.6.2", + "jsonwebtoken": "^9.0.0" }, "engines": { - "node": ">=16" - } - }, - "node_modules/@azure/msal-node/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "node": ">=20" } }, "node_modules/@babel/code-frame": { @@ -339,6 +349,7 @@ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", @@ -354,858 +365,718 @@ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", + "optional": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", - "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "node_modules/@blazediff/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz", + "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } + "license": "MIT" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", - "cpu": [ - "ppc64" - ], + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", - "cpu": [ - "arm" - ], + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", - "cpu": [ - "arm64" - ], + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", - "cpu": [ - "x64" - ], + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", - "cpu": [ - "arm" - ], + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", - "cpu": [ - "ia32" - ], + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", - "cpu": [ - "loong64" - ], + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", - "cpu": [ - "mips64el" - ], + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">= 4" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", - "cpu": [ - "ppc64" - ], + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", - "cpu": [ - "s390x" - ], + "node_modules/@eslint/js": { + "version": "9.34.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.34.0.tgz", + "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", - "cpu": [ - "x64" - ], + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", - "cpu": [ - "arm64" - ], + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", - "cpu": [ - "x64" - ], + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", - "cpu": [ - "arm64" - ], + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, "engines": { - "node": ">=18" + "node": ">=18.18.0" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", - "cpu": [ - "x64" - ], + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", - "cpu": [ - "arm64" - ], + "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": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", - "cpu": [ - "x64" - ], + "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": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": ">=18" + "node": ">=12" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", - "cpu": [ - "ia32" - ], + "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", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", - "cpu": [ - "x64" - ], + "node_modules/@mswjs/interceptors": { + "version": "0.39.6", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.6.tgz", + "integrity": "sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@open-draft/deferred-promise": "^2.2.0", + "@open-draft/logger": "^0.3.0", + "@open-draft/until": "^2.0.0", + "is-node-process": "^1.2.0", + "outvariant": "^1.4.3", + "strict-event-emitter": "^0.5.1" + }, "engines": { "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", - "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "@tybys/wasm-util": "^0.10.1" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", - "dev": true, - "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 8" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", - "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 8" } }, - "node_modules/@eslint/core": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", - "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.15" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 8" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "node_modules/@open-draft/deferred-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", + "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } + "license": "MIT" }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@open-draft/logger": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", + "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "is-node-process": "^1.2.0", + "outvariant": "^1.4.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/@open-draft/until": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", + "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } + "license": "MIT" }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@eslint/js": { - "version": "9.34.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.34.0.tgz", - "integrity": "sha512-EoyvqQnBNsV1CWaEJ559rxXL4c8V92gxirbawSmVUOWXlsRxxQXl6LmCpdUblgxgSkDIqKnhzba2SjRTI/A5Rw==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", + "optional": true, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": ">=14" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } + "license": "MIT" }, - "node_modules/@eslint/plugin-kit": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", - "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.15.2", - "levn": "^0.4.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18.18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18.18.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.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==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.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/@mswjs/interceptors": { - "version": "0.39.6", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.39.6.tgz", - "integrity": "sha512-bndDP83naYYkfayr/qhBHMhk0YGwS1iv6vaEGcr0SQbO0IZtbOPqjKjds/WcG+bJA+1T5vCx6kprKOzn5Bg+Vw==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.3", - "strict-event-emitter": "^0.5.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=18" + "node": "^20.19.0 || >=22.12.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==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "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==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "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==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">= 8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=14" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, @@ -1260,9 +1131,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", - "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -1274,9 +1145,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", - "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -1288,9 +1159,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", - "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -1302,9 +1173,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", - "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -1316,9 +1187,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", - "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -1330,9 +1201,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", - "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -1344,9 +1215,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", - "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -1358,9 +1229,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", - "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -1372,9 +1243,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", - "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -1386,9 +1257,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", - "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -1399,10 +1270,24 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", - "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -1414,9 +1299,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", - "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -1428,9 +1327,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", - "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -1442,9 +1341,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", - "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -1456,9 +1355,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", - "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -1470,9 +1369,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", - "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -1484,9 +1383,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", - "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -1497,10 +1396,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", - "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -1512,9 +1425,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", - "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -1526,9 +1439,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", - "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -1539,10 +1452,24 @@ "win32" ] }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", - "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -1587,9 +1514,9 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1597,9 +1524,9 @@ } }, "node_modules/@sinonjs/samsam": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", - "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-10.0.2.tgz", + "integrity": "sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1607,47 +1534,24 @@ "type-detect": "^4.1.0" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/chai": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", @@ -1707,9 +1611,9 @@ } }, "node_modules/@types/sinon": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", - "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-21.0.1.tgz", + "integrity": "sha512-5yoJSqLbjH8T9V2bksgRayuhpZy+723/z6wBOR+Soe4ZlXC0eW8Na71TeaZPUWDQvM7LYKa9UGFc6LRqxiR5fQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1966,9 +1870,9 @@ } }, "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.0.tgz", - "integrity": "sha512-sOx1PKSuFwnIl7z4RN0Ls7N9AQawmR9r66eI5rFCzLDIs8HTIYrIpH9QjYWoX0lkgGrkLxXhi4QnK7MizPRrIg==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.6.tgz", + "integrity": "sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og==", "license": "MIT", "dependencies": { "http-proxy-agent": "^7.0.0", @@ -1980,139 +1884,97 @@ } }, "node_modules/@vitest/browser": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-3.2.4.tgz", - "integrity": "sha512-tJxiPrWmzH8a+w9nLKlQMzAKX/7VjFs50MWgcAj7p9XQ7AQ9/35fByFYptgPELyLw+0aixTnC4pUWV+APcZ/kw==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", + "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@blazediff/core": "1.9.1", + "@vitest/mocker": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.1.0", + "ws": "^8.19.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.10" + } + }, + "node_modules/@vitest/browser-playwright": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.10.tgz", + "integrity": "sha512-nMoXGEiRpT7m3W7NsbvrM2aKNwiNHZf+zEpUCvMteGjZFvfT96Q9fh7QyB98dvDWXiKvrLxA7bJ1mCOOv+JQPw==", "dev": true, "license": "MIT", "dependencies": { - "@testing-library/dom": "^10.4.0", - "@testing-library/user-event": "^14.6.1", - "@vitest/mocker": "3.2.4", - "@vitest/utils": "3.2.4", - "magic-string": "^0.30.17", - "sirv": "^3.0.1", - "tinyrainbow": "^2.0.0", - "ws": "^8.18.2" + "@vitest/browser": "4.1.10", + "@vitest/mocker": "4.1.10", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "playwright": "*", - "vitest": "3.2.4", - "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0" + "vitest": "4.1.10" }, "peerDependenciesMeta": { "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true + "optional": false } } }, "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", "dev": true, "license": "MIT", "dependencies": { + "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/expect/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/@vitest/expect/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/@vitest/expect/node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, - "node_modules/@vitest/expect/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/@vitest/expect/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/@vitest/expect/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==", + "node_modules/@vitest/expect/node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14.16" + "node": ">=18" } }, "node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.2.4", + "@vitest/spy": "4.1.10", "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" + "magic-string": "^0.30.21" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "msw": { @@ -2134,42 +1996,42 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^2.0.0" + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.2.4", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "magic-string": "^0.30.17", + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", "pathe": "^2.0.3" }, "funding": { @@ -2177,40 +2039,30 @@ } }, "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", "dev": true, "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" - }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/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/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2244,9 +2096,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -2296,16 +2148,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -2324,9 +2166,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -2374,16 +2216,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -2590,6 +2422,13 @@ "dev": true, "license": "MIT" }, + "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/copy-file": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/copy-file/-/copy-file-11.1.0.tgz", @@ -2753,14 +2592,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/diff": { @@ -2773,13 +2612,6 @@ "node": ">=0.3.1" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT" - }, "node_modules/dotenv": { "version": "17.2.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", @@ -2817,54 +2649,12 @@ "license": "MIT" }, "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==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, - "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2980,9 +2770,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -3014,9 +2804,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3111,9 +2901,9 @@ } }, "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -3267,9 +3057,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -3339,6 +3129,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -3369,6 +3160,30 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -3612,6 +3427,16 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3678,13 +3503,24 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -3728,12 +3564,12 @@ "license": "MIT" }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -3763,9 +3599,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -3774,37 +3610,298 @@ } }, "node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.2", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "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==", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/locate-path": { @@ -3900,26 +3997,19 @@ } }, "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "license": "MIT", - "bin": { - "lz-string": "bin/bin.js" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, "node_modules/magic-string": { - "version": "0.30.18", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3964,9 +4054,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -3977,13 +4067,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -3993,19 +4083,19 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mocha": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.1.tgz", - "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", + "version": "11.7.6", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.6.tgz", + "integrity": "sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==", "dev": true, "license": "MIT", "dependencies": { @@ -4017,6 +4107,7 @@ "find-up": "^5.0.0", "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^9.0.5", @@ -4071,9 +4162,9 @@ "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==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ { @@ -4111,6 +4202,17 @@ "node": ">=18.20.0 <20 || >=20.12.1" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/open": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", @@ -4292,17 +4394,17 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "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": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4346,9 +4448,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -4359,13 +4461,13 @@ } }, "node_modules/playwright": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", - "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.56.1" + "playwright-core": "1.60.0" }, "bin": { "playwright": "cli.js" @@ -4378,9 +4480,9 @@ } }, "node_modules/playwright-core": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", - "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4405,10 +4507,20 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "dev": true, "funding": [ { @@ -4426,7 +4538,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -4444,44 +4556,6 @@ "node": ">= 0.8.0" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/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/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/propagate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", @@ -4533,13 +4607,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT" - }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -4626,6 +4693,29 @@ "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.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/rimraf/node_modules/glob": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", @@ -4666,53 +4756,60 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/rimraf/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" }, "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || >=22.12.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/rollup": { - "version": "4.50.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", - "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -4726,27 +4823,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.50.0", - "@rollup/rollup-android-arm64": "4.50.0", - "@rollup/rollup-darwin-arm64": "4.50.0", - "@rollup/rollup-darwin-x64": "4.50.0", - "@rollup/rollup-freebsd-arm64": "4.50.0", - "@rollup/rollup-freebsd-x64": "4.50.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", - "@rollup/rollup-linux-arm-musleabihf": "4.50.0", - "@rollup/rollup-linux-arm64-gnu": "4.50.0", - "@rollup/rollup-linux-arm64-musl": "4.50.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", - "@rollup/rollup-linux-ppc64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-gnu": "4.50.0", - "@rollup/rollup-linux-riscv64-musl": "4.50.0", - "@rollup/rollup-linux-s390x-gnu": "4.50.0", - "@rollup/rollup-linux-x64-gnu": "4.50.0", - "@rollup/rollup-linux-x64-musl": "4.50.0", - "@rollup/rollup-openharmony-arm64": "4.50.0", - "@rollup/rollup-win32-arm64-msvc": "4.50.0", - "@rollup/rollup-win32-ia32-msvc": "4.50.0", - "@rollup/rollup-win32-x64-msvc": "4.50.0", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, @@ -4895,27 +4996,36 @@ } }, "node_modules/sinon": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", - "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "version": "21.1.2", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.1.2.tgz", + "integrity": "sha512-FS6mN+/bx7e2ajpXkEmOcWB6xBzWiuNoAQT18/+a20SS4U7FSYl8Ms7N6VTUxN/1JAjkx7aXp+THMC8xdpp0gA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", - "supports-color": "^7.2.0" + "@sinonjs/fake-timers": "^15.3.2", + "@sinonjs/samsam": "^10.0.2", + "diff": "^8.0.4" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/sinon" } }, + "node_modules/sinon/node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/sirv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "dev": true, "license": "MIT", "dependencies": { @@ -4958,9 +5068,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", - "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, @@ -5088,26 +5198,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", - "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5142,21 +5232,24 @@ "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==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -5165,30 +5258,10 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", - "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { @@ -5305,9 +5378,9 @@ } }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", "dev": true, "funding": [ "https://github.com/sponsors/broofa", @@ -5315,22 +5388,21 @@ ], "license": "MIT", "bin": { - "uuid": "dist/esm/bin/uuid" + "uuid": "dist-node/bin/uuid" } }, "node_modules/vite": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.0.tgz", - "integrity": "sha512-C/Naxf8H0pBx1PA4BdpT+c/5wdqI9ILMdwjSMILw7tVIh3JsxzZqdeTLmmdaoh5MYUEOyBnM9K3o0DzoZ/fe+w==", + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -5346,9 +5418,10 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", @@ -5361,13 +5434,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -5393,89 +5469,80 @@ } } }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", "happy-dom": "*", - "jsdom": "*" + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, - "@types/debug": { + "@opentelemetry/api": { "optional": true }, "@types/node": { "optional": true }, - "@vitest/browser": { + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { "optional": true }, "@vitest/ui": { @@ -5486,73 +5553,12 @@ }, "jsdom": { "optional": true + }, + "vite": { + "optional": false } } }, - "node_modules/vitest/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/vitest/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/vitest/node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, - "node_modules/vitest/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/vitest/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/vitest/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/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5597,9 +5603,9 @@ } }, "node_modules/workerpool": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.3.tgz", - "integrity": "sha512-slxCaKbYjEdFT/o2rH9xS1hf4uRDch1w7Uo+apxhZ+sf/1d9e0ZVkn42kPNGP2dgjIx6YFvSevj0zHvbWe2jdw==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, @@ -5699,9 +5705,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 788f8223..97c6c7b7 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,14 @@ { "name": "@azure/app-configuration-provider", - "version": "2.5.0-preview", + "version": "2.7.0-preview", "description": "The JavaScript configuration provider for Azure App Configuration", "files": [ "dist/", "LICENSE", "README.md" ], + "main": "./dist/commonjs/index.js", + "type": "module", "exports": { "./package.json": "./package.json", ".": { @@ -21,7 +23,7 @@ } }, "scripts": { - "build": "npm run clean && rollup --config && npm run build-test", + "build": "npm run clean && rollup --config && cpy cjs-package.json dist/commonjs --rename=package.json && npm run build-test", "build-test": "npm run build-test-esm && npm run build-test-cjs", "build-test-esm": "tsc -p ./tsconfig.test.esm.json && cpy esm-package.json out/esm --rename=package.json", "build-test-cjs": "tsc -p ./tsconfig.test.cjs.json && cpy cjs-package.json out/commonjs --rename=package.json", @@ -43,30 +45,32 @@ "@types/chai-as-promised": "8.0.2", "@types/mocha": "^10.0.10", "@types/node": "^22.18.0", - "@types/sinon": "^17.0.4", + "@types/sinon": "^21.0.1", "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^8.41.0", "@typescript-eslint/parser": "^8.41.0", + "@vitest/browser": "^4.1.8", + "@vitest/browser-playwright": "^4.1.8", "chai": "^4.5.0", "chai-as-promised": "^7.1.2", "cpy-cli": "^6.0.0", "dotenv": "^17.2.1", "eslint": "^9.34.0", - "mocha": "^11.7.1", + "mocha": "^11.7.6", "nock": "^14.0.10", + "playwright": "^1.60.0", "rimraf": "^6.0.1", - "rollup": "^4.50.0", + "rollup": "^4.59.0", "rollup-plugin-dts": "^6.2.3", - "sinon": "^21.0.0", + "sinon": "^21.1.2", "tslib": "^2.8.1", "typescript": "^5.9.2", - "uuid": "^11.1.0", - "vitest": "^3.2.4", - "@vitest/browser": "^3.2.4", - "playwright": "^1.55.0" + "uuid": "^14.0.0", + "vitest": "^4.1.8" }, "dependencies": { - "@azure/app-configuration": "^1.11.0", + "@azure-rest/core-client": "^2.6.0", + "@azure/app-configuration": "1.13.0-beta.1", "@azure/core-rest-pipeline": "^1.6.0", "@azure/identity": "^4.2.1", "@azure/keyvault-secrets": "^4.7.0", diff --git a/scripts/merge-to-release.sh b/scripts/merge-to-release.sh new file mode 100644 index 00000000..3d254028 --- /dev/null +++ b/scripts/merge-to-release.sh @@ -0,0 +1,140 @@ +#!/bin/bash + +# ============================================================================ +# merge-to-release.sh +# +# Creates a PR to merge a development branch into its corresponding release +# branch. Used after a version bump PR has been merged. +# +# Usage: +# ./scripts/merge-to-release.sh [--preview] +# +# Examples: +# ./scripts/merge-to-release.sh 2.5.0 # main → release/stable/v2 +# ./scripts/merge-to-release.sh 2.5.1-preview --preview # preview → release/v2 +# +# Prerequisites: +# - git and gh (GitHub CLI) must be installed and authenticated +# ============================================================================ + +set -euo pipefail + +# ── Helpers ────────────────────────────────────────────────────────────────── + +usage() { + cat < [--preview] + +Arguments: + version The version that was just bumped (used to determine major version) + --preview Merge preview → release/v{major} instead of + main → release/stable/v{major} + +Examples: + $(basename "$0") 2.5.0 # main → release/stable/v2 + $(basename "$0") 2.5.1-preview --preview # preview → release/v2 +EOF + exit 1 +} + +error() { + echo "ERROR: $1" >&2 + exit 1 +} + +info() { + echo "── $1" +} + +# ── Parse arguments ────────────────────────────────────────────────────────── + +VERSION="" +IS_PREVIEW=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --preview) + IS_PREVIEW=true + shift + ;; + -h|--help) + usage + ;; + *) + if [[ -z "$VERSION" ]]; then + VERSION="$1" + else + error "Unexpected argument: $1" + fi + shift + ;; + esac +done + +[[ -z "$VERSION" ]] && usage + +# Validate version format +if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-preview)?$'; then + error "Invalid version format '$VERSION'. Expected: X.Y.Z or X.Y.Z-preview" +fi + +# ── Determine branches ────────────────────────────────────────────────────── + +# Extract major version (e.g. "2" from "2.5.0" or "2.5.1-preview") +MAJOR_VERSION=$(echo "$VERSION" | cut -d. -f1) + +if [[ "$IS_PREVIEW" == true ]]; then + SOURCE_BRANCH="preview" + TARGET_BRANCH="release/v${MAJOR_VERSION}" + PR_TITLE="Merge preview to release/v${MAJOR_VERSION}" +else + SOURCE_BRANCH="main" + TARGET_BRANCH="release/stable/v${MAJOR_VERSION}" + PR_TITLE="Merge main to release/stable/v${MAJOR_VERSION}" +fi + +info "Source branch : $SOURCE_BRANCH" +info "Target branch : $TARGET_BRANCH" +info "PR title : $PR_TITLE" +echo "" + +# ── Confirm with user ──────────────────────────────────────────────────────── + +read -rp "Proceed? [y/N] " confirm +if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Aborted." + exit 0 +fi + +echo "" + +# ── Resolve project directory ──────────────────────────────────────────────── + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +cd "$PROJECT_DIR" + +# ── Fetch latest branches ─────────────────────────────────────────────────── + +info "Fetching latest branches..." +git fetch origin "$SOURCE_BRANCH" +git fetch origin "$TARGET_BRANCH" + +# ── Create PR ──────────────────────────────────────────────────────────────── + +info "Creating pull request..." +PR_URL=$(gh pr create \ + --base "$TARGET_BRANCH" \ + --head "$SOURCE_BRANCH" \ + --title "$PR_TITLE" \ + --body "Merge \`$SOURCE_BRANCH\` into \`$TARGET_BRANCH\` after version bump \`$VERSION\`. + +> **Important**: Use **Merge commit** (not squash) when merging this PR to preserve commit history. + +--- +*This PR was created automatically by \`scripts/merge-to-release.sh\`.*") + +echo "" +info "Done! PR created: $PR_URL" +echo "" +echo "⚠️ Remember: Use \"Merge commit\" (not squash) when merging this PR." diff --git a/scripts/version-bump.sh b/scripts/version-bump.sh new file mode 100644 index 00000000..005caa56 --- /dev/null +++ b/scripts/version-bump.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +# ============================================================================ +# version-bump.sh +# +# Automates the version bump workflow for @azure/app-configuration-provider. +# Updates version in all required files, creates a branch, commits, pushes, +# and opens a PR via the GitHub CLI (gh). +# +# Usage: +# ./scripts/version-bump.sh [--preview] +# +# Examples: +# ./scripts/version-bump.sh 2.5.0 # stable release → PR to main +# ./scripts/version-bump.sh 2.5.1-preview --preview # preview release → PR to preview +# +# Prerequisites: +# - git, sed, and gh (GitHub CLI) must be installed and authenticated +# ============================================================================ + +set -euo pipefail + +# ── Helpers ────────────────────────────────────────────────────────────────── + +usage() { + cat < [--preview] + +Arguments: + new_version The version to bump to (e.g. 2.5.0 or 2.5.1-preview) + --preview Target the preview branch instead of main + +Examples: + $(basename "$0") 2.5.0 # stable → PR to main + $(basename "$0") 2.5.1-preview --preview # preview → PR to preview +EOF + exit 1 +} + +error() { + echo "ERROR: $1" >&2 + exit 1 +} + +info() { + echo "── $1" +} + +# ── Parse arguments ────────────────────────────────────────────────────────── + +NEW_VERSION="" +IS_PREVIEW=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --preview) + IS_PREVIEW=true + shift + ;; + -h|--help) + usage + ;; + *) + if [[ -z "$NEW_VERSION" ]]; then + NEW_VERSION="$1" + else + error "Unexpected argument: $1" + fi + shift + ;; + esac +done + +[[ -z "$NEW_VERSION" ]] && usage + +# Validate version format: major.minor.patch or major.minor.patch-preview +if ! echo "$NEW_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-preview)?$'; then + error "Invalid version format '$NEW_VERSION'. Expected: X.Y.Z or X.Y.Z-preview" +fi + +# If version ends with -preview, ensure --preview flag is set +if echo "$NEW_VERSION" | grep -qE '\-preview$'; then + if [[ "$IS_PREVIEW" == false ]]; then + error "Version '$NEW_VERSION' looks like a preview version. Did you forget --preview?" + fi +fi + +# ── Resolve paths & context ───────────────────────────────────────────────── + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" + +VERSION_TS="$PROJECT_DIR/src/version.ts" +PACKAGE_JSON="$PROJECT_DIR/package.json" +PACKAGE_LOCK="$PROJECT_DIR/package-lock.json" + +# Determine target branch and branch prefix +if [[ "$IS_PREVIEW" == true ]]; then + TARGET_BRANCH="preview" +else + TARGET_BRANCH="main" +fi + +# Get git username for branch naming (e.g. "linglingye" from "linglingye/version-2.4.0") +GIT_USERNAME=$(git config user.name 2>/dev/null || echo "") +if [[ -z "$GIT_USERNAME" ]]; then + error "Could not determine git user.name. Please set it with: git config user.name " +fi +# Use the first token (lowercase, no spaces) as the branch prefix +BRANCH_PREFIX=$(echo "$GIT_USERNAME" | awk '{print $1}' | tr '[:upper:]' '[:lower:]') + +BRANCH_NAME="${BRANCH_PREFIX}/version-${NEW_VERSION}" + +# ── Show plan ───────────────────────────────────────────────────────────────── + +info "New version : $NEW_VERSION" +info "Target branch : $TARGET_BRANCH" +info "New branch : $BRANCH_NAME" +echo "" + +# ── Confirm with user ──────────────────────────────────────────────────────── + +read -rp "Proceed? [y/N] " confirm +if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo "Aborted." + exit 0 +fi + +echo "" + +# ── Create branch from target ──────────────────────────────────────────────── + +cd "$PROJECT_DIR" + +info "Fetching latest $TARGET_BRANCH..." +git fetch origin "$TARGET_BRANCH" + +info "Creating branch '$BRANCH_NAME' from origin/$TARGET_BRANCH..." +git checkout -b "$BRANCH_NAME" "origin/$TARGET_BRANCH" + +# ── Read current version (after checkout so we read from the target branch) ── + +CURRENT_VERSION=$(grep -oP 'VERSION = "\K[^"]+' "$VERSION_TS") +info "Current version : $CURRENT_VERSION" + +if [[ "$CURRENT_VERSION" == "$NEW_VERSION" ]]; then + error "Current version is already $NEW_VERSION. Nothing to do." +fi + +# ── Update version in all files ────────────────────────────────────────────── + +info "Updating src/version.ts..." +sed -i "s/export const VERSION = \"$CURRENT_VERSION\"/export const VERSION = \"$NEW_VERSION\"/" "$VERSION_TS" + +info "Updating package.json..." +sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_JSON" + +info "Updating package-lock.json (line 3)..." +# package-lock.json has the version on line 3 and line 9 — update both +sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_LOCK" + +info "Updating package-lock.json (line 9)..." +sed -i "0,/\"version\": \"$CURRENT_VERSION\"/s//\"version\": \"$NEW_VERSION\"/" "$PACKAGE_LOCK" + +# ── Verify changes ────────────────────────────────────────────────────────── + +info "Verifying updates..." + +verify_version() { + local file="$1" + local expected="$2" + if ! grep -q "\"$expected\"" "$file" 2>/dev/null && ! grep -q "\"$expected\"" "$file" 2>/dev/null; then + error "Version not found in $file after update. Please check manually." + fi +} + +# Check src/version.ts specifically +if ! grep -q "export const VERSION = \"$NEW_VERSION\"" "$VERSION_TS"; then + error "Version not updated in src/version.ts" +fi +verify_version "$PACKAGE_JSON" "$NEW_VERSION" +verify_version "$PACKAGE_LOCK" "$NEW_VERSION" + +info "All version files updated ✓" +echo "" + +# ── Commit, push, and create PR ───────────────────────────────────────────── + +COMMIT_MSG="version bump $NEW_VERSION" + +info "Committing changes..." +git add "$VERSION_TS" "$PACKAGE_JSON" "$PACKAGE_LOCK" +git commit -m "$COMMIT_MSG" + +info "Pushing branch '$BRANCH_NAME'..." +git push origin "$BRANCH_NAME" + +info "Creating pull request..." +PR_URL=$(gh pr create \ + --base "$TARGET_BRANCH" \ + --head "$BRANCH_NAME" \ + --title "Version bump $NEW_VERSION" \ + --body "Bump version from \`$CURRENT_VERSION\` to \`$NEW_VERSION\`. + +### Changes +- \`src/version.ts\` – updated VERSION constant +- \`package.json\` – updated version field +- \`package-lock.json\` – updated version fields (lines 3 and 9) + +--- +*This PR was created automatically by \`scripts/version-bump.sh\`.*") + +echo "" +info "Done! PR created: $PR_URL" diff --git a/src/appConfigurationClient.ts b/src/appConfigurationClient.ts new file mode 100644 index 00000000..307361d9 --- /dev/null +++ b/src/appConfigurationClient.ts @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + AppConfigurationClient as ConfigurationClient, + AppConfigurationClientOptions as ConfigurationClientOptions, + CheckConfigurationSettingsOptions, + ConfigurationSettingId, + FeatureFlagClient, + FeatureFlagClientOptions, + GetConfigurationSettingOptions, + GetSnapshotOptions, + KnownAppConfigurationApiVersion, + ListConfigurationSettingsForSnapshotOptions, + ListConfigurationSettingsOptions, + ListFeatureFlagsOptions +} from "@azure/app-configuration"; +import { TokenCredential } from "@azure/identity"; +import { instanceOfTokenCredential } from "./common/utils.js"; +import { ArgumentError } from "./common/errors.js"; +import { ErrorMessages } from "./common/errorMessages.js"; +import { RequestTracingOptions, applyRequestTracing } from "./requestTracing/utils.js"; + +/** + * A client for the operations the provider needs from both the @see ConfigurationClient and + * @see FeatureFlagClient SDK clients. Request tracing is applied before delegating each operation. + */ +export class AppConfigurationClient { + #configurationClient: ConfigurationClient; + #featureFlagClient: FeatureFlagClient; + + constructor(connectionString: string, options?: ConfigurationClientOptions); + constructor(endpoint: string, credential: TokenCredential, options?: ConfigurationClientOptions); + constructor( + connectionStringOrEndpoint: string, + credentialOrOptions?: TokenCredential | ConfigurationClientOptions, + options?: ConfigurationClientOptions + ) { + const credentialPassed = instanceOfTokenCredential(credentialOrOptions); + const configurationClientOptions = credentialPassed + ? options + : credentialOrOptions as ConfigurationClientOptions | undefined; + const featureFlagClientOptions = getFeatureFlagClientOptions(configurationClientOptions); + + if (credentialPassed) { + const credential = credentialOrOptions as TokenCredential; + this.#configurationClient = new ConfigurationClient(connectionStringOrEndpoint, credential, configurationClientOptions); + this.#featureFlagClient = new FeatureFlagClient(connectionStringOrEndpoint, credential, featureFlagClientOptions); + } else { + this.#configurationClient = new ConfigurationClient(connectionStringOrEndpoint, configurationClientOptions); + this.#featureFlagClient = new FeatureFlagClient(connectionStringOrEndpoint, featureFlagClientOptions); + } + } + + listConfigurationSettings(listOptions: ListConfigurationSettingsOptions, tracingOptions: RequestTracingOptions) { + return this.#configurationClient.listConfigurationSettings(applyRequestTracing(tracingOptions, listOptions)); + } + + checkConfigurationSettings(checkOptions: CheckConfigurationSettingsOptions, tracingOptions: RequestTracingOptions) { + return this.#configurationClient.checkConfigurationSettings(applyRequestTracing(tracingOptions, checkOptions)); + } + + getConfigurationSetting(configurationSettingId: ConfigurationSettingId, getOptions: GetConfigurationSettingOptions | undefined, tracingOptions: RequestTracingOptions) { + return this.#configurationClient.getConfigurationSetting(configurationSettingId, applyRequestTracing(tracingOptions, getOptions)); + } + + getSnapshot(snapshotName: string, getOptions: GetSnapshotOptions | undefined, tracingOptions: RequestTracingOptions) { + return this.#configurationClient.getSnapshot(snapshotName, applyRequestTracing(tracingOptions, getOptions)); + } + + listConfigurationSettingsForSnapshot(snapshotName: string, listOptions: ListConfigurationSettingsForSnapshotOptions | undefined, tracingOptions: RequestTracingOptions) { + return this.#configurationClient.listConfigurationSettingsForSnapshot(snapshotName, applyRequestTracing(tracingOptions, listOptions)); + } + + listFeatureFlags(listOptions: ListFeatureFlagsOptions, tracingOptions: RequestTracingOptions) { + return this.#featureFlagClient.listFeatureFlags(applyRequestTracing(tracingOptions, listOptions)); + } +} + +export function getFeatureFlagClientOptions(options?: ConfigurationClientOptions): FeatureFlagClientOptions | undefined { + if (options === undefined) { + return undefined; + } + if (options.apiVersion !== undefined && !isSupportedApiVersion(options.apiVersion)) { + throw new ArgumentError(ErrorMessages.API_VERSION_NOT_SUPPORTED); + } + + return { + ...options, + ...(options.retryOptions && { retryOptions: { ...options.retryOptions } }), + ...(options.proxyOptions && { proxyOptions: { ...options.proxyOptions } }), + ...(options.tlsOptions && { tlsOptions: { ...options.tlsOptions } }), + ...(options.userAgentOptions && { userAgentOptions: { ...options.userAgentOptions } }), + ...(options.telemetryOptions && { telemetryOptions: { ...options.telemetryOptions } }), + ...(options.additionalPolicies && { additionalPolicies: [...options.additionalPolicies] }) + }; +} + +function isSupportedApiVersion(apiVersion: string): boolean { + const apiVersionDate = parseApiVersionDate(apiVersion); + const minimumApiVersionDate = parseApiVersionDate(KnownAppConfigurationApiVersion.V20260501Preview)!; + return apiVersionDate !== undefined && apiVersionDate >= minimumApiVersionDate; +} + +function parseApiVersionDate(apiVersion: string): number | undefined { + const match = /^(\d{4}-\d{2}-\d{2})(?:-[0-9A-Za-z.-]+)?$/.exec(apiVersion); + if (match === null) { + return undefined; + } + + const date = new Date(`${match[1]}T00:00:00Z`); + if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== match[1]) { + return undefined; + } + + return date.getTime(); +} diff --git a/src/configurationClientManager.ts b/src/appConfigurationClientManager.ts similarity index 91% rename from src/configurationClientManager.ts rename to src/appConfigurationClientManager.ts index 7249eda7..11dfbab2 100644 --- a/src/configurationClientManager.ts +++ b/src/appConfigurationClientManager.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { AppConfigurationClient, AppConfigurationClientOptions } from "@azure/app-configuration"; -import { ConfigurationClientWrapper } from "./configurationClientWrapper.js"; +import { AppConfigurationClientOptions as ConfigurationClientOptions } from "@azure/app-configuration"; +import { AppConfigurationClient } from "./appConfigurationClient.js"; +import { AppConfigurationClientWrapper } from "./appConfigurationClientWrapper.js"; import { TokenCredential } from "@azure/identity"; import { AzureAppConfigurationOptions } from "./appConfigurationOptions.js"; import { isBrowser, isWebWorker } from "./requestTracing/utils.js"; @@ -28,18 +29,18 @@ const DNS_RESOLVER_TIMEOUT_IN_MS = 3_000; const DNS_RESOLVER_TRIES = 2; const MAX_ALTNATIVE_SRV_COUNT = 10; -export class ConfigurationClientManager { +export class AppConfigurationClientManager { readonly endpoint: URL; // primary endpoint, which is the one specified in the connection string or passed in as a parameter #isFailoverable: boolean; #dns: any; #secret : string; #id : string; #credential: TokenCredential; - #clientOptions: AppConfigurationClientOptions | undefined; + #clientOptions: ConfigurationClientOptions | undefined; #appConfigOptions: AzureAppConfigurationOptions | undefined; #validDomain: string; // valid domain for the primary endpoint, which is used to discover replicas - #staticClients: ConfigurationClientWrapper[]; // there should always be only one static client - #dynamicClients: ConfigurationClientWrapper[]; + #staticClients: AppConfigurationClientWrapper[]; // there should always be only one static client + #dynamicClients: AppConfigurationClientWrapper[]; #replicaCount: number = 0; #lastFallbackClientUpdateTime: number = 0; // enforce to discover fallback client when it is expired #lastFallbackClientRefreshAttempt: number = 0; // avoid refreshing clients before the minimal refresh interval @@ -84,7 +85,7 @@ export class ConfigurationClientManager { throw new ArgumentError(ErrorMessages.CONNECTION_STRING_OR_ENDPOINT_MISSED); } - this.#staticClients = [new ConfigurationClientWrapper(this.endpoint.origin, staticClient)]; + this.#staticClients = [new AppConfigurationClientWrapper(this.endpoint.origin, staticClient)]; this.#validDomain = getValidDomain(this.endpoint.hostname.toLowerCase()); } @@ -113,7 +114,7 @@ export class ConfigurationClientManager { return this.#replicaCount; } - async getClients(): Promise { + async getClients(): Promise { if (!this.#isFailoverable) { return this.#staticClients; } @@ -159,17 +160,17 @@ export class ConfigurationClientManager { } const srvTargetHosts = shuffleList(result); - const newDynamicClients: ConfigurationClientWrapper[] = []; + const newDynamicClients: AppConfigurationClientWrapper[] = []; for (const host of srvTargetHosts) { if (isValidEndpoint(host, this.#validDomain)) { const targetEndpoint = `https://${host}`; if (host.toLowerCase() === this.endpoint.hostname.toLowerCase()) { continue; } - const client = this.#credential ? + const appConfigurationClient = this.#credential ? new AppConfigurationClient(targetEndpoint, this.#credential, this.#clientOptions) : new AppConfigurationClient(buildConnectionString(targetEndpoint, this.#secret, this.#id), this.#clientOptions); - newDynamicClients.push(new ConfigurationClientWrapper(targetEndpoint, client)); + newDynamicClients.push(new AppConfigurationClientWrapper(targetEndpoint, appConfigurationClient)); } } @@ -256,7 +257,7 @@ export function isValidEndpoint(host: string, validDomain: string): boolean { return host.toLowerCase().endsWith(validDomain.toLowerCase()); } -function getClientOptions(options?: AzureAppConfigurationOptions): AppConfigurationClientOptions | undefined { +export function getClientOptions(options?: AzureAppConfigurationOptions): ConfigurationClientOptions { // user-agent let userAgentPrefix = RequestTracing.USER_AGENT_PREFIX; // Default UA for JavaScript Provider const userAgentOptions = options?.clientOptions?.userAgentOptions; diff --git a/src/configurationClientWrapper.ts b/src/appConfigurationClientWrapper.ts similarity index 86% rename from src/configurationClientWrapper.ts rename to src/appConfigurationClientWrapper.ts index 137d1c38..30f4abcf 100644 --- a/src/configurationClientWrapper.ts +++ b/src/appConfigurationClientWrapper.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { AppConfigurationClient } from "@azure/app-configuration"; +import { AppConfigurationClient } from "./appConfigurationClient.js"; import { getExponentialBackoffDuration } from "./common/backoffUtils.js"; -export class ConfigurationClientWrapper { +export class AppConfigurationClientWrapper { endpoint: string; client: AppConfigurationClient; backoffEndTime: number = 0; // Timestamp diff --git a/src/appConfigurationImpl.ts b/src/appConfigurationImpl.ts index 4b642e6e..8759c849 100644 --- a/src/appConfigurationImpl.ts +++ b/src/appConfigurationImpl.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import { - AppConfigurationClient, ConfigurationSetting, ConfigurationSettingId, GetConfigurationSettingOptions, @@ -18,7 +17,10 @@ import { ListConfigurationSettingsForSnapshotOptions, GetSnapshotResponse, KnownSnapshotComposition, - ListConfigurationSettingPage + ListConfigurationSettingPage, + ListFeatureFlagPage, + FeatureFlag, + ListFeatureFlagsOptions } from "@azure/app-configuration"; import { isRestError, RestError } from "@azure/core-rest-pipeline"; import { AzureAppConfiguration, ConfigurationObjectConstructionOptions } from "./appConfiguration.js"; @@ -58,18 +60,16 @@ import { AzureKeyVaultKeyValueAdapter } from "./keyvault/keyVaultKeyValueAdapter import { RefreshTimer } from "./refresh/refreshTimer.js"; import { RequestTracingOptions, - checkConfigurationSettingsWithTrace, - getConfigurationSettingWithTrace, - listConfigurationSettingsWithTrace, - getSnapshotWithTrace, - listConfigurationSettingsForSnapshotWithTrace, requestTracingEnabled } from "./requestTracing/utils.js"; import { FeatureFlagTracingOptions } from "./requestTracing/featureFlagTracingOptions.js"; import { AIConfigurationTracingOptions } from "./requestTracing/aiConfigurationTracingOptions.js"; import { KeyFilter, LabelFilter, SettingWatcher, SettingSelector, PagedSettingsWatcher, WatchedSetting } from "./types.js"; -import { ConfigurationClientManager } from "./configurationClientManager.js"; +import { AppConfigurationClientManager } from "./appConfigurationClientManager.js"; +import { AppConfigurationClient } from "./appConfigurationClient.js"; +import { convert } from "./featureManagement/featureFlagConverter.js"; import { getFixedBackoffDuration, getExponentialBackoffDuration } from "./common/backoffUtils.js"; +import { getStatusCode } from "./common/utils.js"; import { InvalidOperationError, ArgumentError, isFailoverableError, isInputError, SnapshotReferenceError } from "./common/errors.js"; import { ErrorMessages } from "./common/errorMessages.js"; import { X_MS_DATE_HEADER } from "./afd/constants.js"; @@ -89,7 +89,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { */ #sortedTrimKeyPrefixes: string[] | undefined; readonly #requestTracingEnabled: boolean; - #clientManager: ConfigurationClientManager; + #clientManager: AppConfigurationClientManager; #options: AzureAppConfigurationOptions | undefined; #isInitialLoadCompleted: boolean = false; #isFailoverRequest: boolean = false; @@ -97,6 +97,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { #fmVersion: string | undefined; #aiConfigurationTracing: AIConfigurationTracingOptions | undefined; #useSnapshotReference: boolean = false; + #useEnhancedFeatureFlag: boolean = false; // Refresh #refreshInProgress: boolean = false; @@ -109,28 +110,33 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { #sentinels: Map = new Map(); #watchAll: boolean = false; #kvRefreshInterval: number = DEFAULT_REFRESH_INTERVAL_IN_MS; - #kvRefreshTimer: RefreshTimer; + #kvRefreshTimer: RefreshTimer | undefined = undefined; // Feature flags #featureFlagEnabled: boolean = false; #featureFlagRefreshEnabled: boolean = false; #ffRefreshInterval: number = DEFAULT_REFRESH_INTERVAL_IN_MS; - #ffRefreshTimer: RefreshTimer; + #ffRefreshTimer: RefreshTimer | undefined = undefined; // Key Vault references #secretRefreshEnabled: boolean = false; #secretReferences: ConfigurationSetting[] = []; // cached key vault references - #secretRefreshTimer: RefreshTimer; - #resolveSecretsInParallel: boolean = false; + #secretRefreshTimer: RefreshTimer | undefined = undefined; /** - * Selectors of key-values obtained from @see AzureAppConfigurationOptions.selectors + * Page watchers for key-values, derived from @see AzureAppConfigurationOptions.selectors. */ - #kvSelectors: PagedSettingsWatcher[] = []; + #kvPageWatchers: PagedSettingsWatcher[] = []; /** - * Selectors of feature flags obtained from @see AzureAppConfigurationOptions.featureFlagOptions.selectors + * Page watchers for feature flags, derived from + * @see AzureAppConfigurationOptions.featureFlagOptions.selectors with each key filter prefixed by `.appconfig.featureflag/`. */ - #ffSelectors: PagedSettingsWatcher[] = []; + #ffPageWatchers: PagedSettingsWatcher[] = []; + /** + * Page watchers for enhanced feature flags loaded from the dedicated feature flag endpoint, derived from + * @see AzureAppConfigurationOptions.featureFlagOptions.selectors. + */ + #enhancedFfPageWatchers: PagedSettingsWatcher[] = []; // Load balancing #lastSuccessfulEndpoint: string = ""; @@ -139,7 +145,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { #isAfdUsed: boolean = false; constructor( - clientManager: ConfigurationClientManager, + clientManager: AppConfigurationClientManager, options: AzureAppConfigurationOptions | undefined, isAfdUsed: boolean ) { @@ -159,7 +165,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } // if no selector is specified, always load key values using the default selector: key="*" and label="\0" - this.#kvSelectors = getValidKeyValueSelectors(options?.selectors); + this.#kvPageWatchers = getPageWatchers(options?.selectors); if (options?.refreshOptions?.enabled === true) { this.#refreshEnabled = true; @@ -192,7 +198,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { if (options?.featureFlagOptions?.enabled === true) { this.#featureFlagEnabled = true; // validate feature flag selectors, only load feature flags when enabled - this.#ffSelectors = getValidFeatureFlagSelectors(options.featureFlagOptions.selectors); + this.#ffPageWatchers = getFeatureFlagPageWatchers(options.featureFlagOptions.selectors); + this.#enhancedFfPageWatchers = getPageWatchers(options.featureFlagOptions.selectors); if (options.featureFlagOptions.refresh?.enabled === true) { this.#featureFlagRefreshEnabled = true; @@ -218,7 +225,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { this.#secretRefreshEnabled = true; this.#secretRefreshTimer = new RefreshTimer(secretRefreshIntervalInMs); } - this.#resolveSecretsInParallel = options.keyVaultOptions.parallelSecretResolutionEnabled ?? false; } this.#adapters.push(new AzureKeyVaultKeyValueAdapter(options?.keyVaultOptions, this.#secretRefreshTimer)); this.#adapters.push(new JsonKeyValueAdapter()); @@ -235,7 +241,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { fmVersion: this.#fmVersion, aiConfigurationTracing: this.#aiConfigurationTracing, isAfdUsed: this.#isAfdUsed, - useSnapshotReference: this.#useSnapshotReference + useSnapshotReference: this.#useSnapshotReference, + useEnhancedFeatureFlag: this.#useEnhancedFeatureFlag }; } @@ -350,8 +357,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { if (current[lastSegment] !== undefined) { throw new InvalidOperationError(`Ambiguity occurs when constructing configuration object from key '${key}', value '${value}'. The key should not be part of another key.`); } - // set value to the last segment - current[lastSegment] = value; + // Deep copy object values to avoid mutating the original objects in #configMap via shared references. + current[lastSegment] = typeof value === "object" && value !== null ? structuredClone(value) : value; } return data; } @@ -412,7 +419,9 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { await this.#loadSelectedKeyValues(); if (this.#featureFlagEnabled) { - await this.#loadFeatureFlags(); + const featureFlags: ConfigurationSetting[] = await this.#loadFeatureFlags(); + const enhancedFeatureFlags: FeatureFlag[] = await this.#loadEnhancedFeatureFlags(); + await this.#setFeatureFlags(featureFlags, enhancedFeatureFlags); } this.#isInitialLoadCompleted = true; break; @@ -432,7 +441,8 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { postAttempts += 1; backoffDuration = getExponentialBackoffDuration(postAttempts); } - console.warn(`Failed to load. Error message: ${error.message}. Retrying in ${backoffDuration} ms.`); + const errorMessage = error instanceof Error ? error.message : String(error); + console.warn(`Failed to load. Error message: ${errorMessage}. Retrying in ${backoffDuration} ms.`); await new Promise(resolve => setTimeout(resolve, backoffDuration)); } } while (!abortSignal.aborted); @@ -495,26 +505,14 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } } - /** - * Loads configuration settings from App Configuration, either key-value settings or feature flag settings. - * Additionally, updates the `pageEtags` property of the corresponding @see PagedSettingSelector after loading. - * - * @param loadFeatureFlag - Determines which type of configurationsettings to load: - * If true, loads feature flag using the feature flag selectors; - * If false, loads key-value using the key-value selectors. Defaults to false. - */ - async #loadConfigurationSettings(loadFeatureFlag: boolean = false): Promise { - const selectors: PagedSettingsWatcher[] = loadFeatureFlag ? this.#ffSelectors : this.#kvSelectors; - - // Use a Map to deduplicate configuration settings by key. When multiple selectors return settings with the same key, - // the configuration setting loaded by the later selector in the iteration order will override the one from the earlier selector. - const loadedSettings: Map = new Map(); - // deep copy selectors to avoid modification if current client fails - const selectorsToUpdate: PagedSettingsWatcher[] = JSON.parse( - JSON.stringify(selectors) - ); + async #loadSelectedKeyValues() { + this.#secretReferences = []; // clear all cached key vault reference configuration settings + const keyValues: [key: string, value: unknown][] = []; + const configSettings: Map = new Map(); + // Deep copy selectors to avoid modification if current client fails. + const watchersToUpdate: PagedSettingsWatcher[] = structuredClone(this.#kvPageWatchers); - for (const selector of selectorsToUpdate) { + for (const selector of watchersToUpdate) { let settings: ConfigurationSetting[] = []; if (selector.snapshotName === undefined) { const listOptions: ListConfigurationSettingsOptions = { @@ -531,7 +529,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } for (const setting of settings) { - if (isSnapshotReference(setting) && !loadFeatureFlag) { + if (isSnapshotReference(setting)) { this.#useSnapshotReference = true; const snapshotRef: ConfigurationSetting = parseSnapshotReference(setting); @@ -544,55 +542,38 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { for (const snapshotSetting of settingsFromSnapshot) { if (!isFeatureFlag(snapshotSetting)) { // Feature flags inside snapshot are ignored. This is consistent the behavior that key value selectors ignore feature flags. - loadedSettings.set(snapshotSetting.key, snapshotSetting); + configSettings.set(snapshotSetting.key, snapshotSetting); } } continue; } - if (loadFeatureFlag === isFeatureFlag(setting)) { - loadedSettings.set(setting.key, setting); + if (!isFeatureFlag(setting)) { + configSettings.set(setting.key, setting); } } } - if (loadFeatureFlag) { - this.#ffSelectors = selectorsToUpdate; - } else { - this.#kvSelectors = selectorsToUpdate; - } - return Array.from(loadedSettings.values()); - } - - /** - * Loads selected key-values from App Configuration to the local configuration. - */ - async #loadSelectedKeyValues() { - this.#secretReferences = []; // clear all cached key vault reference configuration settings - const keyValues: [key: string, value: unknown][] = []; - const loadedSettings: ConfigurationSetting[] = await this.#loadConfigurationSettings(); - + this.#kvPageWatchers = watchersToUpdate; if (this.#requestTracingEnabled && this.#aiConfigurationTracing !== undefined) { // reset old AI configuration tracing in order to track the information present in the current response from server this.#aiConfigurationTracing.reset(); } + const loadedSettings: ConfigurationSetting[] = Array.from(configSettings.values()); + for (const adapter of this.#adapters) { + await adapter.preload?.(loadedSettings.filter(s => adapter.canProcess(s))); // dedup and warm the secret cache + } + for (const setting of loadedSettings) { if (isSecretReference(setting)) { this.#secretReferences.push(setting); // cache secret references for resolve/refresh secret separately - continue; } // adapt configuration settings to key-values const [key, value] = await this.#processKeyValue(setting); keyValues.push([key, value]); } - if (this.#secretReferences.length > 0) { - await this.#resolveSecretReferences(this.#secretReferences, (key, value) => { - keyValues.push([key, value]); - }); - } - this.#clearLoadedKeyValues(); // clear existing key-values in case of configuration setting deletion for (const [k, v] of keyValues) { this.#configMap.set(k, v); // reset the configuration @@ -633,25 +614,85 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } } - /** - * Loads feature flags from App Configuration to the local configuration. - */ - async #loadFeatureFlags() { - const loadFeatureFlag = true; - const featureFlagSettings: ConfigurationSetting[] = await this.#loadConfigurationSettings(loadFeatureFlag); + async #loadFeatureFlags(): Promise { + const featureFlags: Map = new Map(); + // Deep copy selectors to avoid modification if current client fails. + const watchersToUpdate: PagedSettingsWatcher[] = structuredClone(this.#ffPageWatchers); + + for (const selector of watchersToUpdate) { + let settings: ConfigurationSetting[] = []; + if (selector.snapshotName === undefined) { + const listOptions: ListConfigurationSettingsOptions = { + keyFilter: selector.keyFilter, + labelFilter: selector.labelFilter, + tagsFilter: selector.tagFilters + }; + const { items, pageWatchers } = await this.#listConfigurationSettings(listOptions); + selector.pageWatchers = pageWatchers; + settings = items; + } else { // snapshot selector + settings = await this.#loadConfigurationSettingsFromSnapshot(selector.snapshotName); + } + + for (const setting of settings) { + if (isFeatureFlag(setting)) { + featureFlags.set(setting.key, setting); + } + } + } + + this.#ffPageWatchers = watchersToUpdate; + return Array.from(featureFlags.values()); + } + + async #loadEnhancedFeatureFlags(): Promise { + const loadedFeatureFlags: Map = new Map(); + // Deep copy selectors to avoid modification if current client fails. + const watchersToUpdate: PagedSettingsWatcher[] = structuredClone(this.#enhancedFfPageWatchers); + + for (const selector of watchersToUpdate) { + if (selector.snapshotName) { + continue; + } + const listOptions: ListFeatureFlagsOptions = { + nameFilter: selector.keyFilter, + labelFilter: selector.labelFilter, + tagsFilter: selector.tagFilters + }; + const { items, pageWatchers } = await this.#listEnhancedFeatureFlags(listOptions); + selector.pageWatchers = pageWatchers; + for (const featureFlag of items) { + loadedFeatureFlags.set(featureFlag.name, featureFlag); + } + } + + this.#enhancedFfPageWatchers = watchersToUpdate; + return Array.from(loadedFeatureFlags.values()); + } + + async #setFeatureFlags(featureFlags: ConfigurationSetting[], enhancedFeatureFlags: FeatureFlag[]): Promise { if (this.#requestTracingEnabled && this.#featureFlagTracing !== undefined) { // Reset old feature flag tracing in order to track the information present in the current response from server. this.#featureFlagTracing.reset(); } - // parse feature flags - const featureFlags = await Promise.all( - featureFlagSettings.map(setting => this.#parseFeatureFlag(setting)) + // Track whether enhanced feature flags were loaded. + this.#useEnhancedFeatureFlag = enhancedFeatureFlags.length > 0; + + // Exclude any feature flags that are superseded by an enhanced feature flag with the same name. + const ineligibleFeatureFlagKeys = new Set(enhancedFeatureFlags.map(ff => featureFlagPrefix + ff.name)); + const eligibleFeatureFlags = await Promise.all( + featureFlags + .filter(setting => !ineligibleFeatureFlagKeys.has(setting.key)) + .map(setting => this.#parseFeatureFlag(setting)) + ); + const parsedEnhancedFeatureFlags = await Promise.all( + enhancedFeatureFlags.map(ff => this.#parseEnhancedFeatureFlag(ff)) ); // feature_management is a reserved key, and feature_flags is an array of feature flags - this.#configMap.set(FEATURE_MANAGEMENT_KEY_NAME, { [FEATURE_FLAGS_KEY_NAME]: featureFlags }); + this.#configMap.set(FEATURE_MANAGEMENT_KEY_NAME, { [FEATURE_FLAGS_KEY_NAME]: [...eligibleFeatureFlags, ...parsedEnhancedFeatureFlags] }); } /** @@ -669,7 +710,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { let changedSentinel: WatchedSetting | undefined; let changedSentinelWatcher: SettingWatcher | undefined; if (this.#watchAll) { - needRefresh = await this.#checkConfigurationSettingsChange(this.#kvSelectors); + needRefresh = await this.#checkConfigurationSettingsChange(this.#kvPageWatchers); } else { for (const watchedSetting of this.#sentinels.keys()) { const configurationSettingId: ConfigurationSettingId = { key: watchedSetting.key, label: watchedSetting.label, etag: this.#sentinels.get(watchedSetting)?.etag }; @@ -678,7 +719,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { const watcher: SettingWatcher = this.#sentinels.get(watchedSetting)!; // watcher should always exist for sentinels const isDeleted = response === undefined && watcher.etag !== undefined; // previously existed, now deleted - const isChanged = response && response.statusCode === 200 && watcher.etag !== response.etag; // etag changed + const isChanged = response && getStatusCode(response.statusCode) === 200 && watcher.etag !== response.etag; // etag changed if (isDeleted || isChanged) { changedSentinel = watchedSetting; changedSentinelWatcher = { etag: isChanged ? response.etag : undefined }; @@ -690,7 +731,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { if (needRefresh) { for (const adapter of this.#adapters) { - await adapter.onChangeDetected(); + await adapter.onChangeDetected?.(); } await this.#loadSelectedKeyValues(); @@ -710,18 +751,20 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { */ async #refreshFeatureFlags(): Promise { // if still within refresh interval/backoff, return - if (this.#ffRefreshInterval === undefined || !this.#ffRefreshTimer.canRefresh()) { + if (this.#ffRefreshInterval === undefined || !this.#ffRefreshTimer!.canRefresh()) { return Promise.resolve(false); } - let needRefresh = false; - needRefresh = await this.#checkConfigurationSettingsChange(this.#ffSelectors); + const needRefresh = await this.#checkConfigurationSettingsChange(this.#ffPageWatchers) || + await this.#checkEnhancedFeatureFlagsChange(this.#enhancedFfPageWatchers); if (needRefresh) { - await this.#loadFeatureFlags(); + const featureFlags: ConfigurationSetting[] = await this.#loadFeatureFlags(); + const enhancedFeatureFlags: FeatureFlag[] = await this.#loadEnhancedFeatureFlags(); + await this.#setFeatureFlags(featureFlags, enhancedFeatureFlags); } - this.#ffRefreshTimer.reset(); + this.#ffRefreshTimer!.reset(); return Promise.resolve(needRefresh); } @@ -736,9 +779,16 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { return Promise.resolve(false); } - await this.#resolveSecretReferences(this.#secretReferences, (key, value) => { + const keyVaultRefAdapter = this.#adapters.find(adapter => adapter instanceof AzureKeyVaultKeyValueAdapter) as AzureKeyVaultKeyValueAdapter | undefined; + if (keyVaultRefAdapter) { + // dedup and warm the secret cache + await keyVaultRefAdapter.preload(this.#secretReferences); + } + + for (const setting of this.#secretReferences) { + const [key, value] = await this.#processKeyValue(setting); this.#configMap.set(key, value); - }); + } this.#secretRefreshTimer.reset(); return Promise.resolve(true); @@ -750,7 +800,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { * @returns true if key-value collection has changed, false otherwise. */ async #checkConfigurationSettingsChange(selectors: PagedSettingsWatcher[]): Promise { - const funcToExecute = async (client) => { + const funcToExecute = async (client: AppConfigurationClient) => { for (const selector of selectors) { if (selector.snapshotName) { // skip snapshot selector continue; @@ -767,10 +817,9 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { listOptions.pageEtags = pageWatchers.map(w => w.etag ?? "") ; } - const pageIterator = checkConfigurationSettingsWithTrace( - this.#requestTraceOptions, - client, - listOptions + const pageIterator = client.checkConfigurationSettings( + listOptions, + this.#requestTraceOptions ).byPage(); let i = 0; @@ -786,12 +835,75 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { isResponseFresh = serverResponseTime > lastServerResponseTime; } if (isResponseFresh && - page._response.status === 200 && // conditional request returns 304 if not changed + getStatusCode(page._response.status) === 200 && // conditional request returns 304 if not changed page.etag !== pageWatchers[i].etag) { return true; } i++; } + + if (i < pageWatchers.length) { + return true; + } + } + return false; + }; + + const isChanged = await this.#executeWithFailoverPolicy(funcToExecute); + return isChanged; + } + + /** + * Checks whether the enhanced feature flag collection from the dedicated feature flag endpoint has changed. + * @param selectors - The @see PagedSettingsWatcher of the enhanced feature flag collection. + * @returns true if the enhanced feature flag collection has changed, false otherwise. + */ + async #checkEnhancedFeatureFlagsChange(selectors: PagedSettingsWatcher[]): Promise { + const funcToExecute = async (client: AppConfigurationClient) => { + for (const selector of selectors) { + if (selector.snapshotName) { + continue; + } + const pageWatchers: SettingWatcher[] = selector.pageWatchers ?? []; + const listOptions: ListFeatureFlagsOptions = { + nameFilter: selector.keyFilter, + labelFilter: selector.labelFilter, + tagsFilter: selector.tagFilters + }; + + if (!this.#isAfdUsed) { + // if AFD is not used, add page etags to the listOptions to send conditional request + listOptions.pageEtags = pageWatchers.map(w => w.etag ?? ""); + } + + const pageIterator = client.listFeatureFlags( + listOptions, + this.#requestTraceOptions + ).byPage(); + + let i = 0; + for await (const page of pageIterator) { + const serverResponseTime: Date = this.#getMsDateHeader(page); + if (i >= pageWatchers.length) { + return true; + } + + const lastServerResponseTime = pageWatchers[i].lastServerResponseTime; + let isResponseFresh = false; + if (lastServerResponseTime !== undefined) { + isResponseFresh = serverResponseTime >= lastServerResponseTime; + } + if (isResponseFresh && + getStatusCode(page._response.status) === 200 && // conditional request returns 304 if not changed + page.etag !== pageWatchers[i].etag) { + return true; + } + i++; + } + + if (i < pageWatchers.length) { + return true; + } } return false; }; @@ -804,12 +916,11 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { * Gets a configuration setting by key and label. If the setting is not found, return undefined instead of throwing an error. */ async #getConfigurationSetting(configurationSettingId: ConfigurationSettingId, getOptions?: GetConfigurationSettingOptions): Promise { - const funcToExecute = async (client) => { - return getConfigurationSettingWithTrace( - this.#requestTraceOptions, - client, + const funcToExecute = async (client: AppConfigurationClient) => { + return client.getConfigurationSetting( configurationSettingId, - getOptions + getOptions, + this.#requestTraceOptions ); }; @@ -817,7 +928,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { try { response = await this.#executeWithFailoverPolicy(funcToExecute); } catch (error) { - if (isRestError(error) && error.statusCode === 404) { + if (isRestError(error) && getStatusCode(error.statusCode) === 404) { response = undefined; } else { throw error; @@ -827,12 +938,11 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } async #listConfigurationSettings(listOptions: ListConfigurationSettingsOptions): Promise<{ items: ConfigurationSetting[]; pageWatchers: SettingWatcher[] }> { - const funcToExecute = async (client) => { + const funcToExecute = async (client: AppConfigurationClient) => { const pageWatchers: SettingWatcher[] = []; - const pageIterator = listConfigurationSettingsWithTrace( - this.#requestTraceOptions, - client, - listOptions + const pageIterator = client.listConfigurationSettings( + listOptions, + this.#requestTraceOptions ).byPage(); const items: ConfigurationSetting[] = []; @@ -846,13 +956,31 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { return await this.#executeWithFailoverPolicy(funcToExecute); } + async #listEnhancedFeatureFlags(listOptions: ListFeatureFlagsOptions): Promise<{ items: FeatureFlag[]; pageWatchers: SettingWatcher[] }> { + const funcToExecute = async (client: AppConfigurationClient) => { + const pageWatchers: SettingWatcher[] = []; + const pageIterator = client.listFeatureFlags( + listOptions, + this.#requestTraceOptions + ).byPage(); + + const items: FeatureFlag[] = []; + for await (const page of pageIterator) { + pageWatchers.push({ etag: page.etag, lastServerResponseTime: this.#getMsDateHeader(page) }); + items.push(...page.items); + } + return { items, pageWatchers }; + }; + + return await this.#executeWithFailoverPolicy(funcToExecute); + } + async #getSnapshot(snapshotName: string, getOptions?: GetSnapshotOptions): Promise { - const funcToExecute = async (client) => { - return getSnapshotWithTrace( - this.#requestTraceOptions, - client, + const funcToExecute = async (client: AppConfigurationClient) => { + return client.getSnapshot( snapshotName, - getOptions + getOptions, + this.#requestTraceOptions ); }; @@ -860,7 +988,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { try { response = await this.#executeWithFailoverPolicy(funcToExecute); } catch (error) { - if (isRestError(error) && error.statusCode === 404) { + if (isRestError(error) && getStatusCode(error.statusCode) === 404) { response = undefined; } else { throw error; @@ -870,12 +998,11 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { } async #listConfigurationSettingsForSnapshot(snapshotName: string, listOptions?: ListConfigurationSettingsForSnapshotOptions): Promise { - const funcToExecute = async (client) => { - const pageIterator = listConfigurationSettingsForSnapshotWithTrace( - this.#requestTraceOptions, - client, + const funcToExecute = async (client: AppConfigurationClient) => { + const pageIterator = client.listConfigurationSettingsForSnapshot( snapshotName, - listOptions + listOptions, + this.#requestTraceOptions ).byPage(); const items: ConfigurationSetting[] = []; @@ -931,27 +1058,6 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { throw new Error(ErrorMessages.ALL_FALLBACK_CLIENTS_FAILED); } - async #resolveSecretReferences(secretReferences: ConfigurationSetting[], resultHandler: (key: string, value: unknown) => void): Promise { - if (this.#resolveSecretsInParallel) { - const secretResolutionPromises: Promise[] = []; - for (const setting of secretReferences) { - const secretResolutionPromise = this.#processKeyValue(setting) - .then(([key, value]) => { - resultHandler(key, value); - }); - secretResolutionPromises.push(secretResolutionPromise); - } - - // Wait for all secret resolution promises to be resolved - await Promise.all(secretResolutionPromises); - } else { - for (const setting of secretReferences) { - const [key, value] = await this.#processKeyValue(setting); - resultHandler(key, value); - } - } - } - async #processKeyValue(setting: ConfigurationSetting): Promise<[string, unknown]> { this.#setAIConfigurationTracing(setting); @@ -1006,8 +1112,37 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { if (rawFlag === undefined) { throw new ArgumentError(ErrorMessages.CONFIGURATION_SETTING_VALUE_UNDEFINED); } - const featureFlag = JSON.parse(rawFlag); + const parsedFeatureFlag = JSON.parse(rawFlag); + + let featureFlagReference = `${this.#clientManager.endpoint.origin}/kv/${setting.key}`; + if (setting.label && setting.label.trim().length !== 0) { + featureFlagReference += `?label=${setting.label}`; + } + + await this.#injectFeatureFlagTelemetry(parsedFeatureFlag, setting.etag, featureFlagReference); + this.#setFeatureFlagTracing(parsedFeatureFlag); + + return parsedFeatureFlag; + } + + async #parseEnhancedFeatureFlag(featureFlag: FeatureFlag): Promise { + const parsedFeatureFlag = convert(featureFlag); + let featureFlagReference = `${this.#clientManager.endpoint.origin}/ff/${featureFlag.name}`; + if (featureFlag.label && featureFlag.label.trim().length !== 0) { + featureFlagReference += `?label=${featureFlag.label}`; + } + + await this.#injectFeatureFlagTelemetry(parsedFeatureFlag, featureFlag.etag, featureFlagReference); + this.#setFeatureFlagTracing(parsedFeatureFlag); + + return parsedFeatureFlag; + } + + /** + * Populates the telemetry metadata (ETag, FeatureFlagReference and AllocationId) of a feature management schema object when telemetry is enabled. + */ + async #injectFeatureFlagTelemetry(featureFlag: any, etag: string | undefined, featureFlagReference: string): Promise { if (featureFlag[TELEMETRY_KEY_NAME] && featureFlag[TELEMETRY_KEY_NAME][ENABLED_KEY_NAME] === true) { const metadata = featureFlag[TELEMETRY_KEY_NAME][METADATA_KEY_NAME]; let allocationId = ""; @@ -1015,24 +1150,12 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { allocationId = await this.#generateAllocationId(featureFlag); } featureFlag[TELEMETRY_KEY_NAME][METADATA_KEY_NAME] = { - [ETAG_KEY_NAME]: setting.etag, - [FEATURE_FLAG_REFERENCE_KEY_NAME]: this.#createFeatureFlagReference(setting), + [ETAG_KEY_NAME]: etag, + [FEATURE_FLAG_REFERENCE_KEY_NAME]: featureFlagReference, ...(allocationId !== "" && { [ALLOCATION_ID_KEY_NAME]: allocationId }), ...(metadata || {}) }; } - - this.#setFeatureFlagTracing(featureFlag); - - return featureFlag; - } - - #createFeatureFlagReference(setting: ConfigurationSetting): string { - let featureFlagReference = `${this.#clientManager.endpoint.origin}/kv/${setting.key}`; - if (setting.label && setting.label.trim().length !== 0) { - featureFlagReference += `?label=${setting.label}`; - } - return featureFlagReference; } #setFeatureFlagTracing(featureFlag: any): void { @@ -1169,7 +1292,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration { /** * Extracts the response timestamp (x-ms-date) from the response headers. If not found, returns the current time. */ - #getMsDateHeader(response: GetConfigurationSettingResponse | ListConfigurationSettingPage | RestError): Date { + #getMsDateHeader(response: GetConfigurationSettingResponse | ListConfigurationSettingPage | ListFeatureFlagPage | RestError): Date { let header: string | undefined; if (isRestError(response)) { header = response.response?.headers?.get(X_MS_DATE_HEADER); @@ -1242,7 +1365,7 @@ function areTagFiltersEqual(tagsA?: string[], tagsB?: string[]): boolean { return sortedStringA === sortedStringB; } -function getValidKeyValueSelectors(selectors?: SettingSelector[]): SettingSelector[] { +function getPageWatchers(selectors?: SettingSelector[]): PagedSettingsWatcher[] { if (selectors === undefined || selectors.length === 0) { // Default selector: key: *, label: \0 return [{ keyFilter: KeyFilter.Any, labelFilter: LabelFilter.Null }]; @@ -1250,17 +1373,19 @@ function getValidKeyValueSelectors(selectors?: SettingSelector[]): SettingSelect return getValidSettingSelectors(selectors); } -function getValidFeatureFlagSelectors(selectors?: SettingSelector[]): SettingSelector[] { +function getFeatureFlagPageWatchers(selectors?: SettingSelector[]): PagedSettingsWatcher[] { if (selectors === undefined || selectors.length === 0) { - // Default selector: key: *, label: \0 + // Default selector: key/name: *, label: \0 return [{ keyFilter: `${featureFlagPrefix}${KeyFilter.Any}`, labelFilter: LabelFilter.Null }]; } - selectors.forEach(selector => { - if (selector.keyFilter) { - selector.keyFilter = `${featureFlagPrefix}${selector.keyFilter}`; - } - }); - return getValidSettingSelectors(selectors); + // Create prefixed copies because the original selectors are also used as unprefixed selectors for enhanced feature flags. + const prefixedSelectors = selectors.map(selector => ({ + ...selector, + keyFilter: selector.keyFilter + ? `${featureFlagPrefix}${selector.keyFilter}` + : selector.keyFilter + })); + return getValidSettingSelectors(prefixedSelectors); } function validateTagFilters(tagFilters: string[]): void { diff --git a/src/common/contentType.ts b/src/common/contentType.ts index 4891f425..829cc45a 100644 --- a/src/common/contentType.ts +++ b/src/common/contentType.ts @@ -8,7 +8,7 @@ export type ContentType = { parameters: Record; } -export function parseContentType(contentTypeValue: string | undefined): ContentType | undefined { +export function parseContentType(contentTypeValue?: string): ContentType | undefined { if (!contentTypeValue) { return undefined; } @@ -27,7 +27,7 @@ export function parseContentType(contentTypeValue: string | undefined): ContentT // Determine whether a content type string is a valid JSON content type. // https://docs.microsoft.com/en-us/azure/azure-app-configuration/howto-leverage-json-content-type -export function isJsonContentType(contentType: ContentType | undefined): boolean { +export function isJsonContentType(contentType?: ContentType): boolean { const mediaType = contentType?.mediaType; if (!mediaType) { return false; @@ -45,7 +45,7 @@ export function isJsonContentType(contentType: ContentType | undefined): boolean return typeParts[1].split("+").includes("json"); } -export function isFeatureFlagContentType(contentType: ContentType | undefined): boolean { +export function isFeatureFlagContentType(contentType?: ContentType): boolean { const mediaType = contentType?.mediaType; if (!mediaType) { return false; @@ -53,7 +53,7 @@ export function isFeatureFlagContentType(contentType: ContentType | undefined): return mediaType === featureFlagContentType; } -export function isSecretReferenceContentType(contentType: ContentType | undefined): boolean { +export function isSecretReferenceContentType(contentType?: ContentType): boolean { const mediaType = contentType?.mediaType; if (!mediaType) { return false; diff --git a/src/common/errorMessages.ts b/src/common/errorMessages.ts index 29332174..29fd6ec4 100644 --- a/src/common/errorMessages.ts +++ b/src/common/errorMessages.ts @@ -3,6 +3,7 @@ import { MIN_REFRESH_INTERVAL_IN_MS } from "../refresh/refreshOptions.js"; import { MIN_SECRET_REFRESH_INTERVAL_IN_MS } from "../keyvault/keyVaultOptions.js"; +import { ConfigurationSetting } from "@azure/app-configuration"; export const enum ErrorMessages { INVALID_WATCHED_SETTINGS_KEY = "The characters '*' and ',' are not supported in key of watched settings.", @@ -19,6 +20,7 @@ export const enum ErrorMessages { INVALID_KEY_FILTER = "Key filter cannot be null or empty.", INVALID_LABEL_FILTER = "The characters '*' and ',' are not supported in label filters.", INVALID_TAG_FILTER = "Tag filter must follow the format 'tagName=tagValue'", + API_VERSION_NOT_SUPPORTED = "The App Configuration provider requires API version '2026-05-01-preview' or later.", CONNECTION_STRING_OR_ENDPOINT_MISSED = "A connection string or an endpoint with credential must be specified to create a client.", REPLICA_DISCOVERY_NOT_SUPPORTED = "Replica discovery is not supported when loading from Azure Front Door. For guidance on how to take advantage of geo-replication when Azure Front Door is used, visit https://aka.ms/appconfig/geo-replication-with-afd", LOAD_BALANCING_NOT_SUPPORTED = "Load balancing is not supported when loading from Azure Front Door. For guidance on how to take advantage of geo-replication when Azure Front Door is used, visit https://aka.ms/appconfig/geo-replication-with-afd", @@ -29,3 +31,14 @@ export const enum KeyVaultReferenceErrorMessages { KEY_VAULT_OPTIONS_UNDEFINED = "Failed to process the Key Vault reference because Key Vault options are not configured.", KEY_VAULT_REFERENCE_UNRESOLVABLE = "Failed to resolve the key vault reference. No key vault secret client, credential or secret resolver callback is available to resolve the secret." } + +export function buildKeyVaultReferenceErrorMessage(message: string, secretIdentifier?: string, setting?: ConfigurationSetting): string { + let errorMessage = message; + if (secretIdentifier) { + errorMessage += ` SecretIdentifier: '${secretIdentifier}'`; + } + if (setting) { + errorMessage += ` Key: '${setting.key}' Label: '${setting.label ?? ""}' ETag: '${setting.etag ?? ""}'`; + } + return errorMessage; +} diff --git a/src/common/utils.ts b/src/common/utils.ts index 0264a72e..cfe5756b 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -34,3 +34,15 @@ export function shuffleList(array: T[]): T[] { export function instanceOfTokenCredential(obj: unknown) { return obj && typeof obj === "object" && "getToken" in obj && typeof obj.getToken === "function"; } + +/** + * Normalizes an HTTP status code to a number. + * + * The underlying App Configuration client may surface the status code either as a number + * or as a string (e.g. "200", "304", "404") depending on the runtime/transport. This helper + * coerces the value to a number so that status code comparisons behave consistently and + * refresh logic is not broken when the status is a string. + */ +export function getStatusCode(statusCode: number | string | undefined): number { + return Number(statusCode); +} diff --git a/src/featureManagement/featureFlagConverter.ts b/src/featureManagement/featureFlagConverter.ts new file mode 100644 index 00000000..c5f9c1a7 --- /dev/null +++ b/src/featureManagement/featureFlagConverter.ts @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import type { FeatureFlag as AzAppConfigFeatureFlag } from "@azure/app-configuration"; +import type { + FeatureFilter, + FeatureFlag, + FeatureFlagAllocation, + FeatureFlagTelemetry, + FeatureFlagVariant +} from "./featureFlags.js"; +import { isJsonContentType, parseContentType } from "../common/contentType.js"; + +/** + * Converts @see FeatureFlag into the + * Microsoft Feature Flag schema object used within the `feature_management.feature_flags` + * array. This mirrors the shape produced by parsing a classic feature flag key-value, so that downstream + * feature management parsing and the provider's telemetry/tracing logic are unchanged. + */ +export function convert(featureFlag: AzAppConfigFeatureFlag): FeatureFlag { + const result: FeatureFlag = { + id: featureFlag.name, + enabled: featureFlag.enabled, + conditions: { + client_filters: (featureFlag.conditions?.filters ?? []).map(filter => { + const clientFilter: FeatureFilter = { name: filter.name }; + if (filter.parameters != null) { + clientFilter.parameters = Object.fromEntries( + Object.entries(filter.parameters).map(([name, value]) => [name, parseParameterValue(value)])); + } + return clientFilter; + }) + } + }; + + if (featureFlag.description != null) { + result.description = featureFlag.description; + } + + if (featureFlag.conditions?.requirementType != null) { + result.conditions.requirement_type = featureFlag.conditions.requirementType; + } + + // variants: value -> configuration_value, statusOverride -> status_override + if (featureFlag.variants != null) { + result.variants = featureFlag.variants.map(variant => { + const resultVariant: FeatureFlagVariant = { name: variant.name }; + if (variant.value !== undefined) { + resultVariant.configuration_value = isJsonContentType(parseContentType(variant.contentType)) + ? parseJsonValue(variant.value, featureFlag.name) + : variant.value; + } + if (variant.statusOverride != null) { + resultVariant.status_override = variant.statusOverride; + } + return resultVariant; + }); + } + + // allocation: camelCase -> snake_case + if (featureFlag.allocation != null) { + const allocation: FeatureFlagAllocation = {}; + const sourceAllocation = featureFlag.allocation; + if (sourceAllocation.defaultWhenDisabled != null) { + allocation.default_when_disabled = sourceAllocation.defaultWhenDisabled; + } + if (sourceAllocation.defaultWhenEnabled != null) { + allocation.default_when_enabled = sourceAllocation.defaultWhenEnabled; + } + if (sourceAllocation.percentile != null) { + allocation.percentile = sourceAllocation.percentile.map(p => ({ variant: p.variant, from: p.from, to: p.to })); + } + if (sourceAllocation.user != null) { + allocation.user = sourceAllocation.user.map(u => ({ variant: u.variant, users: u.users })); + } + if (sourceAllocation.group != null) { + allocation.group = sourceAllocation.group.map(g => ({ variant: g.variant, groups: g.groups })); + } + if (sourceAllocation.seed != null) { + allocation.seed = sourceAllocation.seed; + } + result.allocation = allocation; + } + + // telemetry: metadata is (re)populated later by the provider with ETag/FeatureFlagReference/AllocationId + if (featureFlag.telemetry != null) { + const telemetry: FeatureFlagTelemetry = { enabled: featureFlag.telemetry.enabled }; + if (featureFlag.telemetry.metadata != null) { + telemetry.metadata = featureFlag.telemetry.metadata; + } + result.telemetry = telemetry; + } + + return result; +} + +function parseParameterValue(value: unknown): unknown { + if (value === undefined || value === null) { + return value; + } + if (typeof value !== "string") { + return value; + } + + const trimmedValue = value.trim(); + if (trimmedValue.length > 0 && (trimmedValue[0] === "{" || trimmedValue[0] === "[")) { + try { + return JSON.parse(value) as unknown; + } catch { + // The value may intentionally be a string that resembles JSON. + } + } + + return value; +} + +function parseJsonValue(value: string, featureFlagName: string): unknown { + try { + return JSON.parse(value) as unknown; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new SyntaxError(`Enhanced feature flag '${featureFlagName}': ${errorMessage}`, { cause: error }); + } +} diff --git a/src/featureManagement/featureFlags.ts b/src/featureManagement/featureFlags.ts new file mode 100644 index 00000000..7702e555 --- /dev/null +++ b/src/featureManagement/featureFlags.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import type { + FeatureFlag as AzAppConfigFeatureFlag, + FeatureFlagAllocation as AzAppConfigFeatureFlagAllocation, + FeatureFlagConditions as AzAppConfigFeatureFlagConditions, + FeatureFilter as AzAppConfigFeatureFilter, + FeatureFlagTelemetryConfiguration as AzAppConfigFeatureFlagTelemetryConfiguration, + FeatureFlagVariantDefinition as AzAppConfigFeatureFlagVariantDefinition, + GroupAllocation as AzAppConfigGroupAllocation, + PercentileAllocation as AzAppConfigPercentileAllocation, + UserAllocation as AzAppConfigUserAllocation +} from "@azure/app-configuration"; + +export interface FeatureFilter { + name: AzAppConfigFeatureFilter["name"]; + parameters?: Record; +} + +export interface FeatureFlagConditions { + client_filters: FeatureFilter[]; + requirement_type?: AzAppConfigFeatureFlagConditions["requirementType"]; +} + +export interface FeatureFlagVariant { + name: AzAppConfigFeatureFlagVariantDefinition["name"]; + configuration_value?: unknown; + status_override?: AzAppConfigFeatureFlagVariantDefinition["statusOverride"]; +} + +export interface FeatureFlagAllocation { + default_when_disabled?: AzAppConfigFeatureFlagAllocation["defaultWhenDisabled"]; + default_when_enabled?: AzAppConfigFeatureFlagAllocation["defaultWhenEnabled"]; + percentile?: AzAppConfigPercentileAllocation[]; + user?: AzAppConfigUserAllocation[]; + group?: AzAppConfigGroupAllocation[]; + seed?: AzAppConfigFeatureFlagAllocation["seed"]; +} + +export interface FeatureFlagTelemetry { + enabled: AzAppConfigFeatureFlagTelemetryConfiguration["enabled"]; + metadata?: AzAppConfigFeatureFlagTelemetryConfiguration["metadata"]; +} + +export interface FeatureFlag { + id: AzAppConfigFeatureFlag["name"]; + enabled: AzAppConfigFeatureFlag["enabled"]; + description?: AzAppConfigFeatureFlag["description"]; + conditions: FeatureFlagConditions; + variants?: FeatureFlagVariant[]; + allocation?: FeatureFlagAllocation; + telemetry?: FeatureFlagTelemetry; +} diff --git a/src/jsonKeyValueAdapter.ts b/src/jsonKeyValueAdapter.ts index 3ad03841..56735825 100644 --- a/src/jsonKeyValueAdapter.ts +++ b/src/jsonKeyValueAdapter.ts @@ -43,11 +43,7 @@ export class JsonKeyValueAdapter implements IKeyValueAdapter { return [setting.key, parsedValue]; } - async onChangeDetected(): Promise { - return; - } - - #tryParseJson(value: string): { success: true; result: unknown } | { success: false } { + #tryParseJson(value: string): { success: true; result: unknown } | { success: false } { try { return { success: true, result: JSON.parse(value) }; } catch (error) { diff --git a/src/keyValueAdapter.ts b/src/keyValueAdapter.ts index 222461dd..98573fc9 100644 --- a/src/keyValueAdapter.ts +++ b/src/keyValueAdapter.ts @@ -14,8 +14,13 @@ export interface IKeyValueAdapter { */ processKeyValue(setting: ConfigurationSetting): Promise<[string, unknown]>; + /** + * This method deduplicates and warms up Key Vault secret requests so that processKeyValue only reads from cache. + */ + preload?(settings: ConfigurationSetting[]): Promise; + /** * This method is called when a change is detected in the configuration setting. */ - onChangeDetected(): Promise; + onChangeDetected?(): Promise; } diff --git a/src/keyvault/keyVaultKeyValueAdapter.ts b/src/keyvault/keyVaultKeyValueAdapter.ts index e16fbd25..60a01244 100644 --- a/src/keyvault/keyVaultKeyValueAdapter.ts +++ b/src/keyvault/keyVaultKeyValueAdapter.ts @@ -7,16 +7,14 @@ import { AzureKeyVaultSecretProvider } from "./keyVaultSecretProvider.js"; import { KeyVaultOptions } from "./keyVaultOptions.js"; import { RefreshTimer } from "../refresh/refreshTimer.js"; import { ArgumentError, KeyVaultReferenceError } from "../common/errors.js"; -import { KeyVaultReferenceErrorMessages } from "../common/errorMessages.js"; +import { KeyVaultReferenceErrorMessages, buildKeyVaultReferenceErrorMessage } from "../common/errorMessages.js"; import { KeyVaultSecretIdentifier, parseKeyVaultSecretIdentifier } from "@azure/keyvault-secrets"; -import { isRestError } from "@azure/core-rest-pipeline"; -import { AuthenticationError } from "@azure/identity"; export class AzureKeyVaultKeyValueAdapter implements IKeyValueAdapter { #keyVaultOptions: KeyVaultOptions | undefined; #keyVaultSecretProvider: AzureKeyVaultSecretProvider; - constructor(keyVaultOptions: KeyVaultOptions | undefined, refreshTimer?: RefreshTimer) { + constructor(keyVaultOptions?: KeyVaultOptions, refreshTimer?: RefreshTimer) { this.#keyVaultOptions = keyVaultOptions; this.#keyVaultSecretProvider = new AzureKeyVaultSecretProvider(keyVaultOptions, refreshTimer); } @@ -35,17 +33,44 @@ export class AzureKeyVaultKeyValueAdapter implements IKeyValueAdapter { parseSecretReference(setting).value.secretId ); } catch (error) { - throw new KeyVaultReferenceError(buildKeyVaultReferenceErrorMessage("Invalid Key Vault reference.", setting), { cause: error }); + throw new KeyVaultReferenceError(buildKeyVaultReferenceErrorMessage("Invalid Key Vault reference.", undefined, setting), { cause: error }); } - try { - const secretValue = await this.#keyVaultSecretProvider.getSecretValue(secretIdentifier); - return [setting.key, secretValue]; - } catch (error) { - if (isRestError(error) || error instanceof AuthenticationError) { - throw new KeyVaultReferenceError(buildKeyVaultReferenceErrorMessage("Failed to resolve Key Vault reference.", setting, secretIdentifier.sourceId), { cause: error }); + const secretValue = await this.#keyVaultSecretProvider.getSecretValue(secretIdentifier); + return [setting.key, secretValue]; + } + + async preload(settings: ConfigurationSetting[]): Promise { + if (!this.#keyVaultOptions) { + return; // no-op when keyVaultOptions is not configured + } + // Deduplicate references by secret identifier (sourceId). + const uniqueSecrets = new Map(); + for (const setting of settings) { + if (!this.canProcess(setting)) { + continue; + } + let secretIdentifier: KeyVaultSecretIdentifier; + try { + secretIdentifier = parseKeyVaultSecretIdentifier( + parseSecretReference(setting).value.secretId + ); + } catch (error) { + throw new KeyVaultReferenceError(buildKeyVaultReferenceErrorMessage("Invalid Key Vault reference.", undefined, setting), { cause: error }); + } + if (!uniqueSecrets.has(secretIdentifier.sourceId)) { + uniqueSecrets.set(secretIdentifier.sourceId, secretIdentifier); + } + } + + // Resolve failures surface as KeyVaultReferenceError from the provider, identified by secret identifier. + const uniqueSecretIdentifiers = [...uniqueSecrets.values()]; + if (this.#keyVaultOptions.parallelSecretResolutionEnabled) { + await Promise.all(uniqueSecretIdentifiers.map(secretIdentifier => this.#keyVaultSecretProvider.loadSecretValue(secretIdentifier))); + } else { + for (const secretIdentifier of uniqueSecretIdentifiers) { + await this.#keyVaultSecretProvider.loadSecretValue(secretIdentifier); } - throw error; } } @@ -54,7 +79,3 @@ export class AzureKeyVaultKeyValueAdapter implements IKeyValueAdapter { return; } } - -function buildKeyVaultReferenceErrorMessage(message: string, setting: ConfigurationSetting, secretIdentifier?: string ): string { - return `${message} Key: '${setting.key}' Label: '${setting.label ?? ""}' ETag: '${setting.etag ?? ""}' ${secretIdentifier ? ` SecretIdentifier: '${secretIdentifier}'` : ""}`; -} diff --git a/src/keyvault/keyVaultOptions.ts b/src/keyvault/keyVaultOptions.ts index 7f960872..f6ba0dab 100644 --- a/src/keyvault/keyVaultOptions.ts +++ b/src/keyvault/keyVaultOptions.ts @@ -31,9 +31,9 @@ export interface KeyVaultOptions { /** * Specifies the callback used to resolve key vault references that have no applied SecretClient. * @param keyVaultReference The Key Vault reference to resolve. - * @returns The secret value. + * @returns The secret value, which can be of any type. */ - secretResolver?: (keyVaultReference: URL) => string | Promise; + secretResolver?: (keyVaultReference: URL) => any | Promise; /** * Specifies whether to resolve the secret value in parallel. diff --git a/src/keyvault/keyVaultSecretProvider.ts b/src/keyvault/keyVaultSecretProvider.ts index 2d5e113b..663d1cef 100644 --- a/src/keyvault/keyVaultSecretProvider.ts +++ b/src/keyvault/keyVaultSecretProvider.ts @@ -3,9 +3,11 @@ import { KeyVaultOptions, MIN_SECRET_REFRESH_INTERVAL_IN_MS } from "./keyVaultOptions.js"; import { RefreshTimer } from "../refresh/refreshTimer.js"; -import { ArgumentError } from "../common/errors.js"; +import { ArgumentError, KeyVaultReferenceError } from "../common/errors.js"; import { SecretClient, KeyVaultSecretIdentifier } from "@azure/keyvault-secrets"; -import { KeyVaultReferenceErrorMessages } from "../common/errorMessages.js"; +import { KeyVaultReferenceErrorMessages, buildKeyVaultReferenceErrorMessage } from "../common/errorMessages.js"; +import { isRestError } from "@azure/core-rest-pipeline"; +import { AuthenticationError } from "@azure/identity"; export class AzureKeyVaultSecretProvider { #keyVaultOptions: KeyVaultOptions | undefined; @@ -14,7 +16,7 @@ export class AzureKeyVaultSecretProvider { #secretClients: Map; // map key vault hostname to corresponding secret client #cachedSecretValues: Map = new Map(); // map secret identifier to secret value - constructor(keyVaultOptions: KeyVaultOptions | undefined, refreshTimer?: RefreshTimer) { + constructor(keyVaultOptions?: KeyVaultOptions, refreshTimer?: RefreshTimer) { if (keyVaultOptions?.secretRefreshIntervalInMs !== undefined) { if (refreshTimer === undefined) { throw new ArgumentError("Refresh timer must be specified when Key Vault secret refresh is enabled."); @@ -33,21 +35,34 @@ export class AzureKeyVaultSecretProvider { } } - async getSecretValue(secretIdentifier: KeyVaultSecretIdentifier): Promise { + async loadSecretValue(secretIdentifier: KeyVaultSecretIdentifier): Promise { const identifierKey = secretIdentifier.sourceId; - - // If the refresh interval is not expired, return the cached value if available. - if (this.#cachedSecretValues.has(identifierKey) && - (!this.#secretRefreshTimer || !this.#secretRefreshTimer.canRefresh())) { - return this.#cachedSecretValues.get(identifierKey); + const shouldRefresh = this.#secretRefreshTimer?.canRefresh() ?? false; + if (this.#cachedSecretValues.has(identifierKey) && !shouldRefresh) { + return this.#cachedSecretValues.get(identifierKey); // already cached and still fresh + } + let secretValue: unknown; + try { + secretValue = await this.#getSecretValueFromKeyVault(secretIdentifier); + } catch (error) { + if (isRestError(error) || error instanceof AuthenticationError) { + throw new KeyVaultReferenceError(buildKeyVaultReferenceErrorMessage("Failed to resolve Key Vault reference.", secretIdentifier.sourceId), { cause: error }); + } + throw error; } - - // Fallback to fetching the secret value from Key Vault. - const secretValue = await this.#getSecretValueFromKeyVault(secretIdentifier); this.#cachedSecretValues.set(identifierKey, secretValue); return secretValue; } + // Serves the secret value from cache when available; otherwise loads it from Key Vault on demand. + async getSecretValue(secretIdentifier: KeyVaultSecretIdentifier): Promise { + const identifierKey = secretIdentifier.sourceId; + if (this.#cachedSecretValues.has(identifierKey)) { + return this.#cachedSecretValues.get(identifierKey); // serve from cache + } + return this.loadSecretValue(secretIdentifier); // fallback: load on demand + } + clearCache(): void { if (this.#minSecretRefreshTimer.canRefresh()) { this.#cachedSecretValues.clear(); diff --git a/src/load.ts b/src/load.ts index c4e1a1c9..8fdd1254 100644 --- a/src/load.ts +++ b/src/load.ts @@ -5,7 +5,7 @@ import { TokenCredential } from "@azure/identity"; import { AzureAppConfiguration } from "./appConfiguration.js"; import { AzureAppConfigurationImpl } from "./appConfigurationImpl.js"; import { AzureAppConfigurationOptions } from "./appConfigurationOptions.js"; -import { ConfigurationClientManager } from "./configurationClientManager.js"; +import { AppConfigurationClientManager } from "./appConfigurationClientManager.js"; import { AnonymousRequestPipelinePolicy, RemoveSyncTokenPipelinePolicy } from "./afd/afdRequestPipelinePolicy.js"; import { instanceOfTokenCredential } from "./common/utils.js"; import { ArgumentError } from "./common/errors.js"; @@ -40,7 +40,7 @@ export async function load( ): Promise { const startTimestamp = Date.now(); let options: AzureAppConfigurationOptions | undefined; - const clientManager = new ConfigurationClientManager(connectionStringOrEndpoint, credentialOrOptions, appConfigOptions); + const clientManager = new AppConfigurationClientManager(connectionStringOrEndpoint, credentialOrOptions, appConfigOptions); await clientManager.init(); if (!instanceOfTokenCredential(credentialOrOptions)) { diff --git a/src/requestTracing/constants.ts b/src/requestTracing/constants.ts index afc823cd..34b3fef6 100644 --- a/src/requestTracing/constants.ts +++ b/src/requestTracing/constants.ts @@ -53,6 +53,7 @@ export const KEY_VAULT_REFRESH_CONFIGURED_TAG = "RefreshesKeyVault"; export const FAILOVER_REQUEST_TAG = "Failover"; export const AFD_USED_TAG = "AFD"; export const SNAPSHOT_REFERENCE_TAG = "SnapshotRef"; +export const ENHANCED_FEATURE_FLAG_TAG = "EnhFF"; // Compact feature tags export const FEATURES_KEY = "Features"; diff --git a/src/requestTracing/utils.ts b/src/requestTracing/utils.ts index 2e54e33c..1e028169 100644 --- a/src/requestTracing/utils.ts +++ b/src/requestTracing/utils.ts @@ -1,16 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { OperationOptions } from "@azure/core-client"; -import { - AppConfigurationClient, - ConfigurationSettingId, - GetConfigurationSettingOptions, - ListConfigurationSettingsOptions, - CheckConfigurationSettingsOptions, - GetSnapshotOptions, - ListConfigurationSettingsForSnapshotOptions -} from "@azure/app-configuration"; +import { OperationOptions } from "@azure-rest/core-client"; import { AzureAppConfigurationOptions } from "../appConfigurationOptions.js"; import { FeatureFlagTracingOptions } from "./featureFlagTracingOptions.js"; import { AIConfigurationTracingOptions } from "./aiConfigurationTracingOptions.js"; @@ -44,7 +35,8 @@ import { DELIMITER, AI_CONFIGURATION_TAG, AI_CHAT_COMPLETION_CONFIGURATION_TAG, - SNAPSHOT_REFERENCE_TAG + SNAPSHOT_REFERENCE_TAG, + ENHANCED_FEATURE_FLAG_TAG } from "./constants.js"; export interface RequestTracingOptions { @@ -58,64 +50,17 @@ export interface RequestTracingOptions { fmVersion: string | undefined; aiConfigurationTracing: AIConfigurationTracingOptions | undefined; useSnapshotReference: boolean; + useEnhancedFeatureFlag: boolean; } // Utils -export function listConfigurationSettingsWithTrace( - requestTracingOptions: RequestTracingOptions, - client: AppConfigurationClient, - listOptions: ListConfigurationSettingsOptions -) { - const actualListOptions = applyRequestTracing(requestTracingOptions, listOptions); - return client.listConfigurationSettings(actualListOptions); -} - -export function checkConfigurationSettingsWithTrace( - requestTracingOptions: RequestTracingOptions, - client: AppConfigurationClient, - checkOptions: CheckConfigurationSettingsOptions -) { - const actualCheckOptions = applyRequestTracing(requestTracingOptions, checkOptions); - return client.checkConfigurationSettings(actualCheckOptions); -} - -export function getConfigurationSettingWithTrace( - requestTracingOptions: RequestTracingOptions, - client: AppConfigurationClient, - configurationSettingId: ConfigurationSettingId, - getOptions?: GetConfigurationSettingOptions, -) { - const actualGetOptions = applyRequestTracing(requestTracingOptions, getOptions); - return client.getConfigurationSetting(configurationSettingId, actualGetOptions); -} - -export function getSnapshotWithTrace( - requestTracingOptions: RequestTracingOptions, - client: AppConfigurationClient, - snapshotName: string, - getOptions?: GetSnapshotOptions -) { - const actualGetOptions = applyRequestTracing(requestTracingOptions, getOptions); - return client.getSnapshot(snapshotName, actualGetOptions); -} - -export function listConfigurationSettingsForSnapshotWithTrace( - requestTracingOptions: RequestTracingOptions, - client: AppConfigurationClient, - snapshotName: string, - listOptions?: ListConfigurationSettingsForSnapshotOptions -) { - const actualListOptions = applyRequestTracing(requestTracingOptions, listOptions); - return client.listConfigurationSettingsForSnapshot(snapshotName, actualListOptions); -} - -function applyRequestTracing(requestTracingOptions: RequestTracingOptions, operationOptions?: T) { +export function applyRequestTracing(requestTracingOptions: RequestTracingOptions, operationOptions?: T) { const actualOptions = { ...operationOptions }; if (requestTracingOptions.enabled) { actualOptions.requestOptions = { ...actualOptions.requestOptions, - customHeaders: { - ...actualOptions.requestOptions?.customHeaders, + headers: { + ...actualOptions.requestOptions?.headers, [CORRELATION_CONTEXT_HEADER_NAME]: createCorrelationContextHeader(requestTracingOptions) } }; @@ -198,6 +143,7 @@ export function requestTracingEnabled(): boolean { function usesAnyTracingFeature(requestTracingOptions: RequestTracingOptions): boolean { return (requestTracingOptions.appConfigOptions?.loadBalancingEnabled ?? false) || (requestTracingOptions.aiConfigurationTracing?.usesAnyTracingFeature() ?? false) || + requestTracingOptions.useEnhancedFeatureFlag || requestTracingOptions.isAfdUsed; } @@ -218,6 +164,9 @@ function createFeaturesString(requestTracingOptions: RequestTracingOptions): str if (requestTracingOptions.useSnapshotReference) { tags.push(SNAPSHOT_REFERENCE_TAG); } + if (requestTracingOptions.useEnhancedFeatureFlag) { + tags.push(ENHANCED_FEATURE_FLAG_TAG); + } return tags.join(DELIMITER); } diff --git a/src/version.ts b/src/version.ts index 82eb2eea..20ea7759 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,4 +1,4 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export const VERSION = "2.5.0-preview"; +export const VERSION = "2.7.0-preview"; diff --git a/test/afd.test.ts b/test/afd.test.ts index f575bde3..2e793fcf 100644 --- a/test/afd.test.ts +++ b/test/afd.test.ts @@ -10,7 +10,7 @@ const expect = chai.expect; import { AppConfigurationClient } from "@azure/app-configuration"; import { load, loadFromAzureFrontDoor } from "../src/index.js"; import { ErrorMessages } from "../src/common/errorMessages.js"; -import { createMockedKeyValue, createMockedFeatureFlag, HttpRequestHeadersPolicy, getCachedIterator, sinon, restoreMocks, createMockedConnectionString, createMockedAzureFrontDoorEndpoint, sleepInMs } from "./utils/testHelper.js"; +import { createMockedKeyValue, createMockedFeatureFlag, HttpRequestHeadersPolicy, getCachedIterator, sinon, restoreMocks, createMockedConnectionString, createMockedAzureFrontDoorEndpoint, sleepInMs, mockFeatureFlagClientListFeatureFlags } from "./utils/testHelper.js"; import { X_MS_DATE_HEADER } from "../src/afd/constants.js"; import { isBrowser } from "../src/requestTracing/utils.js"; @@ -97,7 +97,7 @@ describe("loadFromAzureFrontDoor", function() { userAgent = headerPolicy.headers.get("User-Agent"); } - expect(userAgent).satisfy((ua: string) => ua.startsWith("javascript-appconfiguration-provider")); + expect(userAgent).satisfy((ua: string) => ua.includes("javascript-appconfiguration-provider")); expect(headerPolicy.headers.get("Authorization")).to.be.undefined; expect(headerPolicy.headers.get("Sync-Token")).to.be.undefined; }); @@ -115,6 +115,8 @@ describe("loadFromAzureFrontDoor", function() { stub.onCall(1).returns(getCachedIterator([ { items: [ff], response: { status: 200, headers: createTimestampHeaders("2025-09-07T00:00:00Z") } } ])); + // the dedicated feature flag endpoint returns no feature flags + mockFeatureFlagClientListFeatureFlags([]); const appConfig = await loadFromAzureFrontDoor(createMockedAzureFrontDoorEndpoint(), { selectors: [{ keyFilter: "app.*" }], @@ -215,6 +217,8 @@ describe("loadFromAzureFrontDoor", function() { listStub.onCall(2).returns(getCachedIterator([ { items: [ff_updated], response: { status: 200, headers: createTimestampHeaders("2025-09-07T00:00:03Z") } } ])); + // the dedicated feature flag endpoint returns no feature flags + mockFeatureFlagClientListFeatureFlags([]); const appConfig = await loadFromAzureFrontDoor(createMockedAzureFrontDoorEndpoint(), { featureFlagOptions: { diff --git a/test/clientOptions.test.ts b/test/clientOptions.test.ts index 349e3195..e256259e 100644 --- a/test/clientOptions.test.ts +++ b/test/clientOptions.test.ts @@ -8,6 +8,10 @@ chai.use(chaiAsPromised); const expect = chai.expect; import { load } from "../src/index.js"; import { createMockedConnectionString } from "./utils/testHelper.js"; +import { AppConfigurationClientManager, getClientOptions } from "../src/appConfigurationClientManager.js"; +import { getFeatureFlagClientOptions } from "../src/appConfigurationClient.js"; +import { KnownAppConfigurationApiVersion } from "@azure/app-configuration"; +import { ErrorMessages } from "../src/common/errorMessages.js"; import nock from "nock"; class HttpRequestCountPolicy { @@ -39,6 +43,60 @@ describe("custom client options", function () { nock.restore(); }); + it("should reject an unsupported API version", () => { + const createClientManager = () => new AppConfigurationClientManager(createMockedConnectionString(fakeEndpoint), { + clientOptions: { + apiVersion: KnownAppConfigurationApiVersion.V20260401 + } + }); + + expect(createClientManager).throws(ErrorMessages.API_VERSION_NOT_SUPPORTED); + }); + + it("should reject a malformed API version", () => { + const createFeatureFlagClientOptions = () => getFeatureFlagClientOptions({ + apiVersion: "2026-13-01-preview" + }); + + expect(createFeatureFlagClientOptions).throws(ErrorMessages.API_VERSION_NOT_SUPPORTED); + }); + + it("should allow the stable API version with the minimum date", () => { + expect(() => getFeatureFlagClientOptions({ apiVersion: "2026-05-01" })).not.throws(); + }); + + it("should allow an API version later than the minimum", () => { + expect(() => getFeatureFlagClientOptions({ apiVersion: "2026-06-01-preview" })).not.throws(); + }); + + it("should use equivalent options for configuration and feature flag clients", () => { + const countPolicy = new HttpRequestCountPolicy(); + const configurationClientOptions = getClientOptions({ + clientOptions: { + apiVersion: "2026-05-01-preview", + audience: "https://appconfig.azure.com", + allowInsecureConnection: true, + additionalPolicies: [{ + policy: countPolicy, + position: "perCall" + }], + retryOptions: { + maxRetries: 4, + maxRetryDelayInMs: 10_000 + }, + userAgentOptions: { + userAgentPrefix: "custom-user-agent" + } + } + }); + const featureFlagClientOptions = getFeatureFlagClientOptions(configurationClientOptions)!; + + expect(featureFlagClientOptions).deep.equals(configurationClientOptions); + expect(featureFlagClientOptions).not.equals(configurationClientOptions); + expect(featureFlagClientOptions.retryOptions).not.equals(configurationClientOptions.retryOptions); + expect(featureFlagClientOptions.userAgentOptions).not.equals(configurationClientOptions.userAgentOptions); + }); + it("should retry 2 times by default", async () => { const countPolicy = new HttpRequestCountPolicy(); const loadPromise = () => { diff --git a/test/failover.test.ts b/test/failover.test.ts index 3d4f510c..15edc42a 100644 --- a/test/failover.test.ts +++ b/test/failover.test.ts @@ -8,7 +8,7 @@ chai.use(chaiAsPromised); const expect = chai.expect; import { load } from "../src/index.js"; import { createMockedConnectionString, createMockedFeatureFlag, createMockedKeyValue, mockConfigurationManagerGetClients, restoreMocks } from "./utils/testHelper.js"; -import { getValidDomain, isValidEndpoint } from "../src/configurationClientManager.js"; +import { getValidDomain, isValidEndpoint } from "../src/appConfigurationClientManager.js"; const mockedKVs = [{ key: "app.settings.fontColor", diff --git a/test/featureFlag.test.ts b/test/featureFlag.test.ts index 6e9dea0d..c0bb3fd5 100644 --- a/test/featureFlag.test.ts +++ b/test/featureFlag.test.ts @@ -6,7 +6,8 @@ import * as chai from "chai"; import chaiAsPromised from "chai-as-promised"; import { featureFlagContentType } from "@azure/app-configuration"; import { load } from "../src/index.js"; -import { mockAppConfigurationClientGetSnapshot, mockAppConfigurationClientListConfigurationSettingsForSnapshot, createMockedConnectionString, createMockedEndpoint, createMockedFeatureFlag, createMockedKeyValue, mockAppConfigurationClientListConfigurationSettings, restoreMocks } from "./utils/testHelper.js"; +import { convert } from "../src/featureManagement/featureFlagConverter.js"; +import { mockAppConfigurationClientGetSnapshot, mockAppConfigurationClientListConfigurationSettingsForSnapshot, createMockedConnectionString, createMockedEndpoint, createMockedFeatureFlag, createMockedEnhancedFeatureFlag, createMockedKeyValue, mockAppConfigurationClientListConfigurationSettings, mockFeatureFlagClientListFeatureFlags, restoreMocks, sleepInMs, expectEnhancedFeatureFlagJsonError } from "./utils/testHelper.js"; chai.use(chaiAsPromised); const expect = chai.expect; @@ -207,6 +208,7 @@ describe("feature flags", function () { before(() => { mockAppConfigurationClientListConfigurationSettings([mockedKVs]); + mockFeatureFlagClientListFeatureFlags([]); }); after(() => { @@ -500,4 +502,225 @@ describe("feature flags", function () { restoreMocks(); }); }); + +describe("enhanced feature flags", function () { + + afterEach(() => { + restoreMocks(); + }); + + it("should load feature flags from the dedicated feature flag endpoint", async () => { + // no feature flags; two enhanced feature flags returned by the dedicated endpoint + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("NewAlpha", { enabled: true }), + createMockedEnhancedFeatureFlag("NewBeta", { enabled: false }) + ]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { enabled: true } + }); + + const featureFlags = settings.get("feature_management").feature_flags as any[]; + expect(featureFlags.length).equals(2); + expect(featureFlags.find(ff => ff.id === "NewAlpha").enabled).equals(true); + expect(featureFlags.find(ff => ff.id === "NewBeta").enabled).equals(false); + }); + + it("should load an enhanced feature flag with null optional fields", async () => { + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("Minimal", { + description: null, + conditions: null, + variants: null, + allocation: null, + telemetry: null + }) + ]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { enabled: true } + }); + + const featureFlag = (settings.get("feature_management").feature_flags as any[]) + .find(ff => ff.id === "Minimal"); + expect(featureFlag).not.undefined; + expect(featureFlag.conditions.client_filters).deep.equals([]); + expect(featureFlag).not.have.property("description"); + expect(featureFlag).not.have.property("variants"); + expect(featureFlag).not.have.property("allocation"); + expect(featureFlag).not.have.property("telemetry"); + }); + + it("should parse enhanced feature flag filter parameters", async () => { + const audience = { + Users: ["test@contoso.com"], + Groups: [{ Name: "contoso.com", RolloutPercentage: 50 }], + DefaultRolloutPercentage: 0 + }; + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("Targeted", { + conditions: { + requirementType: "Any", + filters: [{ + name: "Microsoft.Targeting", + parameters: { + Audience: JSON.stringify(audience), + JsonArray: " [\"one\",\"two\"] ", + PlainText: "not-json", + Percentage: "50", + NullValue: null, + UndefinedValue: undefined + } + }] + } + }) + ]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { enabled: true } + }); + + const featureFlag = (settings.get("feature_management").feature_flags as any[]) + .find(ff => ff.id === "Targeted"); + const parameters = featureFlag.conditions.client_filters[0].parameters; + expect(parameters.Audience).deep.equals(audience); + expect(parameters.JsonArray).deep.equals(["one", "two"]); + expect(parameters.PlainText).equals("not-json"); + expect(parameters.Percentage).equals("50"); + expect(parameters.NullValue).equals(null); + expect(parameters).has.property("UndefinedValue", undefined); + }); + + it("should preserve invalid JSON in enhanced feature flag filter parameters as a string", () => { + const enhancedFeatureFlag = createMockedEnhancedFeatureFlag("InvalidParameter", { + conditions: { + filters: [{ + name: "CustomFilter", + parameters: { Value: "{not-json}" } + }] + } + }); + + const featureFlag = convert(enhancedFeatureFlag); + expect(featureFlag.conditions.client_filters[0].parameters?.Value).equals("{not-json}"); + }); + + it("should parse enhanced feature flag variants based on content type", () => { + const enhancedFeatureFlag = createMockedEnhancedFeatureFlag("VariantContentType", { + variants: [ + { name: "Json", value: "{\"color\":\"blue\"}", contentType: "application/json" }, + { name: "Text", value: "{\"color\":\"blue\"}", contentType: "text/plain" } + ] + }); + + const featureFlag = convert(enhancedFeatureFlag); + expect(featureFlag.variants?.[0].configuration_value).deep.equals({ color: "blue" }); + expect(featureFlag.variants?.[1].configuration_value).equals("{\"color\":\"blue\"}"); + }); + + it("should throw for invalid JSON in an enhanced feature flag variant", () => { + const enhancedFeatureFlag = createMockedEnhancedFeatureFlag("InvalidVariant", { + variants: [{ name: "Json", value: "{not-json}", contentType: "application/json" }] + }); + + expectEnhancedFeatureFlagJsonError(() => convert(enhancedFeatureFlag), "InvalidVariant"); + }); + + it("should let an enhanced feature flag supersede a feature flag with the same name", async () => { + // "Shared" is enabled and "ClassicOnly" exists; the dedicated endpoint returns "Shared" disabled + const featureFlagSettings = [ + createMockedFeatureFlag("Shared", { enabled: true }), + createMockedFeatureFlag("ClassicOnly", { enabled: true }) + ]; + mockAppConfigurationClientListConfigurationSettings([featureFlagSettings]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("Shared", { enabled: false }) + ]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { enabled: true } + }); + + const featureFlags = settings.get("feature_management").feature_flags as any[]; + // "Shared" appears once (from the dedicated endpoint, disabled); "ClassicOnly" remains + expect(featureFlags.length).equals(2); + expect(featureFlags.filter(ff => ff.id === "Shared").length).equals(1); + expect(featureFlags.find(ff => ff.id === "Shared").enabled).equals(false); + expect(featureFlags.find(ff => ff.id === "ClassicOnly").enabled).equals(true); + }); + + it("should convert an enhanced feature flag into the feature management schema", async () => { + const enhancedFeatureFlag = createMockedEnhancedFeatureFlag("Variant", { + conditions: { + requirementType: "All", + filters: [{ name: "Microsoft.TimeWindow", parameters: { Start: JSON.stringify("Mon, 01 Jan 2024 00:00:00 GMT") } }] + }, + variants: [ + { name: "Off", value: false, statusOverride: "Disabled" }, + { name: "On", value: true } + ], + allocation: { + defaultWhenEnabled: "Off", + defaultWhenDisabled: "Off", + percentile: [{ variant: "On", from: 0, to: 50 }], + seed: "seed-value" + }, + telemetry: { enabled: true } + }); + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[enhancedFeatureFlag]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { enabled: true } + }); + + const featureFlag = (settings.get("feature_management").feature_flags as any[]).find(ff => ff.id === "Variant"); + expect(featureFlag).not.undefined; + expect(featureFlag.enabled).equals(true); + expect(featureFlag.conditions.requirement_type).equals("All"); + expect(featureFlag.conditions.client_filters[0].name).equals("Microsoft.TimeWindow"); + expect(featureFlag.variants[0].name).equals("Off"); + expect(featureFlag.variants[0].configuration_value).equals(false); + expect(featureFlag.variants[0].status_override).equals("Disabled"); + expect(featureFlag.allocation.default_when_enabled).equals("Off"); + expect(featureFlag.allocation.percentile[0].variant).equals("On"); + // telemetry enabled => metadata populated with the feature flag reference and allocation id + expect(featureFlag.telemetry.metadata).not.undefined; + expect(featureFlag.telemetry.metadata.FeatureFlagReference).equals(`${createMockedEndpoint()}/ff/Variant`); + expect(featureFlag.telemetry.metadata.AllocationId).not.undefined; + }); + + it("should refresh feature flags when the dedicated endpoint changes", async () => { + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("NewFlag", { enabled: true }) + ]]); + + const settings = await load(createMockedConnectionString(), { + featureFlagOptions: { + enabled: true, + refresh: { enabled: true, refreshIntervalInMs: 1000 } + } + }); + + let featureFlag = (settings.get("feature_management").feature_flags as any[]).find(ff => ff.id === "NewFlag"); + expect(featureFlag.enabled).equals(true); + + // the enhanced feature flag on the dedicated endpoint changes + restoreMocks(); + mockAppConfigurationClientListConfigurationSettings([[]]); + mockFeatureFlagClientListFeatureFlags([[ + createMockedEnhancedFeatureFlag("NewFlag", { enabled: false }) + ]]); + + await sleepInMs(1000 + 1); + await settings.refresh(); + + featureFlag = (settings.get("feature_management").feature_flags as any[]).find(ff => ff.id === "NewFlag"); + expect(featureFlag.enabled).equals(false); + }); +}); /* eslint-enable @typescript-eslint/no-unused-expressions */ diff --git a/test/keyvault.test.ts b/test/keyvault.test.ts index feeb2941..17b6e1a0 100644 --- a/test/keyvault.test.ts +++ b/test/keyvault.test.ts @@ -142,6 +142,220 @@ describe("key vault reference", function () { }); }); +describe("key vault reference deduplication", function () { + afterEach(() => { + restoreMocks(); + }); + + // 5 settings all referencing the same secret URI (same sourceId). + const sameSecretUri = "https://fake-vault-name.vault.azure.net/secrets/fakeSecretName"; + function mockDuplicateReferences() { + const kvs = ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"] + .map((key) => createMockedKeyVaultReference(key, sameSecretUri)); + mockAppConfigurationClientListConfigurationSettings([kvs]); + } + + it("should resolve duplicate references with a single Key Vault request in parallel mode", async () => { + mockDuplicateReferences(); + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + const stub = sinon.stub(client, "getSecret").callsFake(async () => { + // Introduce a delay so that all references start before the first one resolves. + await sleepInMs(100); + return { value: "SecretValue" } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretClients: [client], + parallelSecretResolutionEnabled: true + } + }); + + expect(stub.callCount).eq(1); + for (const key of ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"]) { + expect(settings.get(key)).eq("SecretValue"); + } + }); + + it("should resolve duplicate references with a single Key Vault request in sequential mode", async () => { + mockDuplicateReferences(); + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + const stub = sinon.stub(client, "getSecret").callsFake(async () => { + return { value: "SecretValue" } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretClients: [client] + } + }); + + expect(stub.callCount).eq(1); + for (const key of ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"]) { + expect(settings.get(key)).eq("SecretValue"); + } + }); + + it("should invoke secret resolver only once for duplicate references", async () => { + mockDuplicateReferences(); + const resolver = sinon.stub().callsFake(async () => { + await sleepInMs(100); + return "ResolvedSecretValue"; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretResolver: resolver, + parallelSecretResolutionEnabled: true + } + }); + + expect(resolver.callCount).eq(1); + for (const key of ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"]) { + expect(settings.get(key)).eq("ResolvedSecretValue"); + } + }); + + it("should fetch different versions of the same secret independently", async () => { + const versionedUri = "https://fake-vault-name.vault.azure.net/secrets/fakeSecretName/741a0fc52610449baffd6e1c55b9d459"; + const kvs = [ + createMockedKeyVaultReference("TestKey", sameSecretUri), + createMockedKeyVaultReference("TestKeyVersioned", versionedUri) + ]; + mockAppConfigurationClientListConfigurationSettings([kvs]); + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + const stub = sinon.stub(client, "getSecret").callsFake(async (_name, options) => { + await sleepInMs(100); + return { value: options?.version ? "VersionedValue" : "LatestValue" } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretClients: [client], + parallelSecretResolutionEnabled: true + } + }); + + expect(stub.callCount).eq(2); + expect(settings.get("TestKey")).eq("LatestValue"); + expect(settings.get("TestKeyVersioned")).eq("VersionedValue"); + }); + + it("should recover and not cache the failure when preload fails to fetch a secret", async () => { + mockDuplicateReferences(); + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + const stub = sinon.stub(client, "getSecret"); + // The preload fetch (best-effort) rejects and must not be cached; the on-demand resolution then + // recovers by re-fetching successfully. + stub.onCall(0).callsFake(async () => { + await sleepInMs(100); + throw new Error("Key Vault unavailable"); + }); + stub.callsFake(async () => { + return { value: "SecretValue" } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretClients: [client], + parallelSecretResolutionEnabled: true + } + }); + + // The failed preload is not cached, so all references still resolve successfully. + for (const key of ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"]) { + expect(settings.get(key)).eq("SecretValue"); + } + }); + + it("should re-fetch once per unique secret on a key-value change reload", async () => { + const secretKeys = ["TestKey1", "TestKey2", "TestKey3", "TestKey4", "TestKey5"]; + // Mutable page so the sentinel can change without re-stubbing (which would tear down the fake clock). + const kvPage = [ + ...secretKeys.map((key) => createMockedKeyVaultReference(key, sameSecretUri)), + createMockedKeyValue({ key: "sentinel", value: "v1", etag: "sentinel-etag-1" }) + ]; + mockAppConfigurationClientListConfigurationSettings([kvPage]); + mockAppConfigurationClientGetConfigurationSetting(kvPage); + + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + let secretValue = "SecretValue-initial"; + let callCount = 0; + sinon.stub(client, "getSecret").callsFake(async () => { + callCount++; + return { value: secretValue } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + refreshOptions: { + enabled: true, + refreshIntervalInMs: 1000, + watchedSettings: [{ key: "sentinel" }] + }, + keyVaultOptions: { + secretClients: [client], + parallelSecretResolutionEnabled: true + } + }); + // Initial load resolves the duplicates with a single request. + expect(callCount).eq(1); + + // Install the fake clock seeded with the current time so the refresh timers (created during load) stay consistent. + const clock = sinon.useFakeTimers({ now: Date.now() }); + try { + // Advance past the min secret refresh interval so the key-value change reload clears the cache. + await clock.tickAsync(60_000 + 100); + + // Change the watched sentinel (new etag) and the secret value in place to trigger a reload. + kvPage[kvPage.length - 1] = createMockedKeyValue({ key: "sentinel", value: "v2", etag: "sentinel-etag-2" }); + secretValue = "SecretValue-reloaded"; + const callCountBeforeReload = callCount; + + await settings.refresh(); + + // The key-value change reload clears the cache and re-fetches, but only once for the unique secret. + expect(callCount - callCountBeforeReload).eq(1); + for (const key of secretKeys) { + expect(settings.get(key)).eq("SecretValue-reloaded"); + } + } finally { + clock.restore(); + } + }); + + it("should re-fetch once per unique secret on each refresh round", async () => { + mockDuplicateReferences(); + const client = new SecretClient("https://fake-vault-name.vault.azure.net", createMockedTokenCredential()); + let callCount = 0; + sinon.stub(client, "getSecret").callsFake(async () => { + callCount++; + return { value: `SecretValue-${callCount}` } as KeyVaultSecret; + }); + + const settings = await load(createMockedConnectionString(), { + keyVaultOptions: { + secretClients: [client], + secretRefreshIntervalInMs: 60_000, + parallelSecretResolutionEnabled: true + } + }); + // Initial load resolves duplicates with a single request. + expect(callCount).eq(1); + expect(settings.get("TestKey1")).eq("SecretValue-1"); + + // Advance past the secret refresh interval using a fake clock so the refresh round re-fetches once. + const clock = sinon.useFakeTimers({ now: Date.now() }); + try { + await clock.tickAsync(60_000 + 100); + await settings.refresh(); + } finally { + clock.restore(); + } + expect(callCount).eq(2); + expect(settings.get("TestKey1")).eq("SecretValue-2"); + }); +}); + describe("key vault secret refresh", function () { beforeEach(() => { diff --git a/test/load.test.ts b/test/load.test.ts index d1f109e1..8f357fd6 100644 --- a/test/load.test.ts +++ b/test/load.test.ts @@ -101,6 +101,18 @@ const mockedKVs = [{ key: "keyWithEmptyTag", value: "valueWithEmptyTag", tags: {"emptyTag": ""} +}, { + key: "app6_markets", + value: JSON.stringify({ gb: { url: "https://example.com/gb" }, dk: { url: "https://example.com/dk" } }), + contentType: "application/json" +}, { + key: "app6_markets.markets.dk", + value: JSON.stringify({ currency: "DKK" }), + contentType: "application/json" +}, { + key: "app6_markets.markets.gb", + value: JSON.stringify({ currency: "GBP" }), + contentType: "application/json" } ].map(createMockedKeyValue); @@ -579,6 +591,33 @@ describe("load", function () { }).to.throw("Invalid separator '%'. Supported values: '.', ',', ';', '-', '_', '__', '/', ':'."); }); + it("should call constructConfigurationObject twice without throwing for JSON content-type keys with overlapping hierarchy", async () => { + const connectionString = createMockedConnectionString(); + const settings = await load(connectionString, { + selectors: [{ + keyFilter: "app6_*" + }], + trimKeyPrefixes: ["app6_"] + }); + expect(settings).not.undefined; + + // First call should succeed + const data1 = settings.constructConfigurationObject({ separator: "." }); + expect(data1).not.undefined; + expect(data1.markets.gb.url).eq("https://example.com/gb"); + expect(data1.markets.dk.url).eq("https://example.com/dk"); + expect(data1.markets.markets.dk.currency).eq("DKK"); + expect(data1.markets.markets.gb.currency).eq("GBP"); + + // Second call should also succeed (idempotent) + const data2 = settings.constructConfigurationObject({ separator: "." }); + expect(data2).not.undefined; + expect(data2.markets.gb.url).eq("https://example.com/gb"); + expect(data2.markets.dk.url).eq("https://example.com/dk"); + expect(data2.markets.markets.dk.currency).eq("DKK"); + expect(data2.markets.markets.gb.currency).eq("GBP"); + }); + it("should load key values from snapshot", async () => { const snapshotName = "Test"; const snapshotResponses = new Map([ diff --git a/test/loadBalance.test.ts b/test/loadBalance.test.ts index 8651ecea..07fb98a1 100644 --- a/test/loadBalance.test.ts +++ b/test/loadBalance.test.ts @@ -7,8 +7,8 @@ chai.use(chaiAsPromised); const expect = chai.expect; import { load } from "../src/index.js"; import { restoreMocks, createMockedConnectionString, createMockedKeyValue, sleepInMs, createMockedEndpoint, mockConfigurationManagerGetClients, mockAppConfigurationClientLoadBalanceMode } from "./utils/testHelper.js"; -import { AppConfigurationClient } from "@azure/app-configuration"; -import { ConfigurationClientWrapper } from "../src/configurationClientWrapper.js"; +import { AppConfigurationClientWrapper } from "../src/appConfigurationClientWrapper.js"; +import { AppConfigurationClient } from "../src/appConfigurationClient.js"; const mockedKVs = [ { value: "red", key: "app.settings.fontColor" }, @@ -17,14 +17,18 @@ const mockedKVs = [ ].map(createMockedKeyValue); const fakeEndpoint_1 = createMockedEndpoint("fake_1"); const fakeEndpoint_2 = createMockedEndpoint("fake_2"); -const fakeClientWrapper_1 = new ConfigurationClientWrapper(fakeEndpoint_1, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint_1))); -const fakeClientWrapper_2 = new ConfigurationClientWrapper(fakeEndpoint_2, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint_2))); -const clientRequestCounter_1 = {count: 0}; -const clientRequestCounter_2 = {count: 0}; +const fakeClientWrapper_1 = new AppConfigurationClientWrapper(fakeEndpoint_1, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint_1))); +const fakeClientWrapper_2 = new AppConfigurationClientWrapper(fakeEndpoint_2, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint_2))); +const clientCallCounts_1 = { configurationSettings: 0, enhancedFeatureFlags: 0 }; +const clientCallCounts_2 = { configurationSettings: 0, enhancedFeatureFlags: 0 }; describe("load balance", function () { beforeEach(() => { + clientCallCounts_1.configurationSettings = 0; + clientCallCounts_1.enhancedFeatureFlags = 0; + clientCallCounts_2.configurationSettings = 0; + clientCallCounts_2.enhancedFeatureFlags = 0; }); afterEach(() => { @@ -33,8 +37,8 @@ describe("load balance", function () { it("should load balance the request when loadBalancingEnabled", async () => { mockConfigurationManagerGetClients([fakeClientWrapper_1, fakeClientWrapper_2], false); - mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_1, clientRequestCounter_1); - mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_2, clientRequestCounter_2); + mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_1, clientCallCounts_1); + mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_2, clientCallCounts_2); const connectionString = createMockedConnectionString(); const settings = await load(connectionString, { @@ -50,28 +54,31 @@ describe("load balance", function () { } } }); - // one request for key values, one request for feature flags - expect(clientRequestCounter_1.count).eq(1); - expect(clientRequestCounter_2.count).eq(1); + // Configuration-setting requests are split between clients; the dedicated feature-flag request rotates back to client 1. + expect(clientCallCounts_1.configurationSettings).eq(1); + expect(clientCallCounts_1.enhancedFeatureFlags).eq(1); + expect(clientCallCounts_2.configurationSettings).eq(1); + expect(clientCallCounts_2.enhancedFeatureFlags).eq(0); await sleepInMs(2 * 1000 + 1); await settings.refresh(); - // refresh request for feature flags - expect(clientRequestCounter_1.count).eq(2); - expect(clientRequestCounter_2.count).eq(1); + expect(clientCallCounts_1.configurationSettings).eq(1); + expect(clientCallCounts_1.enhancedFeatureFlags).eq(2); + expect(clientCallCounts_2.configurationSettings).eq(2); + expect(clientCallCounts_2.enhancedFeatureFlags).eq(0); await sleepInMs(2 * 1000 + 1); await settings.refresh(); - expect(clientRequestCounter_1.count).eq(2); - expect(clientRequestCounter_2.count).eq(2); + expect(clientCallCounts_1.configurationSettings).eq(1); + expect(clientCallCounts_1.enhancedFeatureFlags).eq(3); + expect(clientCallCounts_2.configurationSettings).eq(3); + expect(clientCallCounts_2.enhancedFeatureFlags).eq(0); }); it("should not load balance the request when loadBalance disabled", async () => { - clientRequestCounter_1.count = 0; - clientRequestCounter_2.count = 0; mockConfigurationManagerGetClients([fakeClientWrapper_1, fakeClientWrapper_2], false); - mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_1, clientRequestCounter_1); - mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_2, clientRequestCounter_2); + mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_1, clientCallCounts_1); + mockAppConfigurationClientLoadBalanceMode([mockedKVs], fakeClientWrapper_2, clientCallCounts_2); const connectionString = createMockedConnectionString(); // loadBalancingEnabled is default to false @@ -87,14 +94,16 @@ describe("load balance", function () { } } }); - // one request for key values, one request for feature flags - expect(clientRequestCounter_1.count).eq(2); - expect(clientRequestCounter_2.count).eq(0); + expect(clientCallCounts_1.configurationSettings).eq(2); + expect(clientCallCounts_1.enhancedFeatureFlags).eq(1); + expect(clientCallCounts_2.configurationSettings).eq(0); + expect(clientCallCounts_2.enhancedFeatureFlags).eq(0); await sleepInMs(2 * 1000 + 1); await settings.refresh(); - // refresh request for feature flags - expect(clientRequestCounter_1.count).eq(3); - expect(clientRequestCounter_2.count).eq(0); + expect(clientCallCounts_1.configurationSettings).eq(3); + expect(clientCallCounts_1.enhancedFeatureFlags).eq(2); + expect(clientCallCounts_2.configurationSettings).eq(0); + expect(clientCallCounts_2.enhancedFeatureFlags).eq(0); }); }); diff --git a/test/refresh.test.ts b/test/refresh.test.ts index 7bab4652..deadbe23 100644 --- a/test/refresh.test.ts +++ b/test/refresh.test.ts @@ -7,7 +7,7 @@ import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); const expect = chai.expect; import { load } from "../src/index.js"; -import { mockAppConfigurationClientListConfigurationSettings, mockAppConfigurationClientGetConfigurationSetting, restoreMocks, createMockedConnectionString, createMockedKeyValue, sleepInMs, createMockedFeatureFlag } from "./utils/testHelper.js"; +import { mockAppConfigurationClientListConfigurationSettings, mockAppConfigurationClientListConfigurationSettingsWithStringStatus, mockFeatureFlagClientListFeatureFlags, mockAppConfigurationClientGetConfigurationSetting, restoreMocks, createMockedConnectionString, createMockedKeyValue, sleepInMs, createMockedFeatureFlag } from "./utils/testHelper.js"; import * as uuid from "uuid"; let mockedKVs: any[] = []; @@ -513,6 +513,54 @@ describe("dynamic refresh", function () { // Verify changes are reflected expect(settings.get("TestTagKey")).eq("newValue"); }); + + it("should refresh key values when page response status is string", async () => { + restoreMocks(); // restore the mock set up in beforeEach + const initialKVs = [ + { value: "red", key: "app.settings.fontColor" }, + { value: "40", key: "app.settings.fontSize" } + ].map(createMockedKeyValue); + mockAppConfigurationClientListConfigurationSettingsWithStringStatus([initialKVs], listKvCallback); + mockAppConfigurationClientGetConfigurationSetting(initialKVs, getKvCallback); + + const connectionString = createMockedConnectionString(); + const settings = await load(connectionString, { + refreshOptions: { + enabled: true, + refreshIntervalInMs: 2000 + } + }); + expect(listKvRequestCount).eq(1); + expect(settings).not.undefined; + expect(settings.get("app.settings.fontColor")).eq("red"); + + let refreshSuccessfulCount = 0; + settings.onRefresh(() => { + refreshSuccessfulCount++; + }); + + // no change yet, the page response status is "304" + await sleepInMs(2 * 1000 + 1); + await settings.refresh(); + expect(listKvRequestCount).eq(2); // one more conditional request to detect change + expect(refreshSuccessfulCount).eq(0); // no change in key values, because page etags are the same. + + // change key value + restoreMocks(); + const changedKVs = [ + { value: "blue", key: "app.settings.fontColor" }, + { value: "40", key: "app.settings.fontSize" } + ].map(createMockedKeyValue); + mockAppConfigurationClientListConfigurationSettingsWithStringStatus([changedKVs], listKvCallback); + mockAppConfigurationClientGetConfigurationSetting(changedKVs, getKvCallback); + + // the page response status is "200" when changed + await sleepInMs(2 * 1000 + 1); + await settings.refresh(); + expect(listKvRequestCount).eq(4); // 2 + 2 more requests: one conditional request to detect change and one request to reload all key values + expect(refreshSuccessfulCount).eq(1); // change in key values, because page etags are different. + expect(settings.get("app.settings.fontColor")).eq("blue"); + }); }); describe("dynamic refresh feature flags", function () { @@ -531,6 +579,7 @@ describe("dynamic refresh feature flags", function () { createMockedFeatureFlag("Beta", { enabled: true }) ]; mockAppConfigurationClientListConfigurationSettings([mockedKVs], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); mockAppConfigurationClientGetConfigurationSetting(mockedKVs, getKvCallback); const connectionString = createMockedConnectionString(); @@ -585,6 +634,7 @@ describe("dynamic refresh feature flags", function () { createMockedFeatureFlag("Beta_2", { enabled: true }), ]; mockAppConfigurationClientListConfigurationSettings([page1, page2], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); mockAppConfigurationClientGetConfigurationSetting([...page1, ...page2], getKvCallback); const connectionString = createMockedConnectionString(); @@ -618,6 +668,7 @@ describe("dynamic refresh feature flags", function () { page2[0] = createMockedFeatureFlag("Beta_1", { enabled: false }); restoreMocks(); mockAppConfigurationClientListConfigurationSettings([page1, page2], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); mockAppConfigurationClientGetConfigurationSetting([...page1, ...page2], getKvCallback); await sleepInMs(2 * 1000 + 1); @@ -633,6 +684,7 @@ describe("dynamic refresh feature flags", function () { createMockedFeatureFlag("ProdFeature", { enabled: false }, { tags: { "env": "prod" } }) ]; mockAppConfigurationClientListConfigurationSettings([mockedKVs], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); mockAppConfigurationClientGetConfigurationSetting(mockedKVs, getKvCallback); const connectionString = createMockedConnectionString(); @@ -672,5 +724,62 @@ describe("dynamic refresh feature flags", function () { expect(updatedFeatureManagement.feature_flags[0].id).eq("DevFeature"); expect(updatedFeatureManagement.feature_flags[0].enabled).eq(false); }); + + it("should refresh feature flags when page response status is string", async () => { + // mock multiple pages of feature flags + const page1 = [ + createMockedFeatureFlag("Alpha_1", { enabled: true }), + createMockedFeatureFlag("Alpha_2", { enabled: true }), + ]; + const page2 = [ + createMockedFeatureFlag("Beta_1", { enabled: true }), + createMockedFeatureFlag("Beta_2", { enabled: true }), + ]; + mockAppConfigurationClientListConfigurationSettingsWithStringStatus([page1, page2], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); + mockAppConfigurationClientGetConfigurationSetting([...page1, ...page2], getKvCallback); + + const connectionString = createMockedConnectionString(); + const settings = await load(connectionString, { + featureFlagOptions: { + enabled: true, + selectors: [{ + keyFilter: "*" + }], + refresh: { + enabled: true, + refreshIntervalInMs: 2000 // 2 seconds for quick test. + } + } + }); + expect(listKvRequestCount).eq(2); + expect(getKvRequestCount).eq(0); + + let refreshSuccessfulCount = 0; + settings.onRefresh(() => { + refreshSuccessfulCount++; + }); + + // no change yet, the page response status is "304" + await sleepInMs(2 * 1000 + 1); + await settings.refresh(); + expect(listKvRequestCount).eq(3); // one conditional request to detect change + expect(getKvRequestCount).eq(0); + expect(refreshSuccessfulCount).eq(0); // no change in feature flags, because page etags are the same. + + // change feature flag Beta_1 to false + page2[0] = createMockedFeatureFlag("Beta_1", { enabled: false }); + restoreMocks(); + mockAppConfigurationClientListConfigurationSettingsWithStringStatus([page1, page2], listKvCallback); + mockFeatureFlagClientListFeatureFlags([]); + mockAppConfigurationClientGetConfigurationSetting([...page1, ...page2], getKvCallback); + + // the page response status is "200" when changed + await sleepInMs(2 * 1000 + 1); + await settings.refresh(); + expect(listKvRequestCount).eq(5); // 3 + 2 more requests: one conditional request to detect change and one request to reload all feature flags + expect(getKvRequestCount).eq(0); + expect(refreshSuccessfulCount).eq(1); // change in feature flags, because page etags are different. + }); }); /* eslint-enable @typescript-eslint/no-unused-expressions */ diff --git a/test/requestTracing.test.ts b/test/requestTracing.test.ts index f3aadf70..010ad45f 100644 --- a/test/requestTracing.test.ts +++ b/test/requestTracing.test.ts @@ -7,8 +7,8 @@ import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); const expect = chai.expect; import { AppConfigurationClient } from "@azure/app-configuration"; -import { HttpRequestHeadersPolicy, createMockedConnectionString, createMockedKeyValue, createMockedFeatureFlag, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, restoreMocks, sinon, sleepInMs } from "./utils/testHelper.js"; -import { ConfigurationClientManager } from "../src/configurationClientManager.js"; +import { HttpRequestHeadersPolicy, createMockedConnectionString, createMockedKeyValue, createMockedFeatureFlag, createMockedTokenCredential, mockAppConfigurationClientListConfigurationSettings, mockFeatureFlagClientListFeatureFlags, restoreMocks, sinon, sleepInMs } from "./utils/testHelper.js"; +import { AppConfigurationClientManager } from "../src/appConfigurationClientManager.js"; import { load, loadFromAzureFrontDoor } from "../src/index.js"; import { isBrowser } from "../src/requestTracing/utils.js"; @@ -35,7 +35,7 @@ describe("request tracing", function () { after(() => { }); - it("should have correct user agent prefix", async () => { + it("should include the provider identifier in the user agent", async () => { try { await load(createMockedConnectionString(fakeEndpoint), { clientOptions, @@ -53,7 +53,7 @@ describe("request tracing", function () { userAgent = headerPolicy.headers.get("User-Agent"); } - expect(userAgent).satisfy((ua: string) => ua.startsWith("javascript-appconfiguration-provider")); + expect(userAgent).satisfy((ua: string) => ua.includes("javascript-appconfiguration-provider")); }); it("should have request type in correlation-context header", async () => { @@ -105,7 +105,7 @@ describe("request tracing", function () { it("should have replica count in correlation-context header", async () => { const replicaCount = 2; - sinon.stub(ConfigurationClientManager.prototype, "getReplicaCount").returns(replicaCount); + sinon.stub(AppConfigurationClientManager.prototype, "getReplicaCount").returns(replicaCount); try { await load(createMockedConnectionString(fakeEndpoint), { clientOptions, @@ -131,7 +131,7 @@ describe("request tracing", function () { }); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; - expect(headerPolicy.headers.get("User-Agent")).satisfy((ua: string) => ua.startsWith("javascript-appconfiguration-provider")); + expect(headerPolicy.headers.get("User-Agent")).satisfy((ua: string) => ua.includes("javascript-appconfiguration-provider")); const correlationContext = headerPolicy.headers.get("Correlation-Context"); expect(correlationContext).not.undefined; expect(correlationContext.includes("AFD")).eq(true); @@ -244,18 +244,15 @@ describe("request tracing", function () { }); it("should have filter type in correlation-context header if feature flags use feature filters", async () => { - let correlationContext: string = ""; - const listKvCallback = (listOptions) => { - correlationContext = listOptions?.requestOptions?.customHeaders[CORRELATION_CONTEXT_HEADER_NAME] ?? ""; - }; - mockAppConfigurationClientListConfigurationSettings([[ createMockedFeatureFlag("Alpha_1", { conditions: { client_filters: [ { name: "Microsoft.TimeWindow" } ] } }), createMockedFeatureFlag("Alpha_2", { conditions: { client_filters: [ { name: "Microsoft.Targeting" } ] } }), createMockedFeatureFlag("Alpha_3", { conditions: { client_filters: [ { name: "CustomFilter" } ] } }) - ]], listKvCallback); + ]]); + mockFeatureFlagClientListFeatureFlags([]); const settings = await load(createMockedConnectionString(fakeEndpoint), { + clientOptions, featureFlagOptions: { enabled: true, selectors: [ {keyFilter: "*"} ], @@ -266,34 +263,31 @@ describe("request tracing", function () { } }); - expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Startup")).eq(true); + restoreMocks(); await sleepInMs(1_000 + 1_000); try { await settings.refresh(); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; + const correlationContext = headerPolicy.headers.get(CORRELATION_CONTEXT_HEADER_NAME); expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Watch")).eq(true); - expect(correlationContext?.includes("Filter=CSTM+TIME+TRGT")).eq(true); + expect(correlationContext.includes("RequestType=Watch")).eq(true); + expect(correlationContext.includes("Filter=CSTM+TIME+TRGT")).eq(true); restoreMocks(); }); it("should have max variants in correlation-context header if feature flags use variants", async () => { - let correlationContext: string = ""; - const listKvCallback = (listOptions) => { - correlationContext = listOptions?.requestOptions?.customHeaders[CORRELATION_CONTEXT_HEADER_NAME] ?? ""; - }; - mockAppConfigurationClientListConfigurationSettings([[ createMockedFeatureFlag("Alpha_1", { variants: [ {name: "a"}, {name: "b"}] }), createMockedFeatureFlag("Alpha_2", { variants: [ {name: "a"}, {name: "b"}, {name: "c"}] }), createMockedFeatureFlag("Alpha_3", { variants: [] }) - ]], listKvCallback); + ]]); + mockFeatureFlagClientListFeatureFlags([]); const settings = await load(createMockedConnectionString(fakeEndpoint), { + clientOptions, featureFlagOptions: { enabled: true, selectors: [ {keyFilter: "*"} ], @@ -304,32 +298,29 @@ describe("request tracing", function () { } }); - expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Startup")).eq(true); + restoreMocks(); await sleepInMs(1_000 + 1_000); try { await settings.refresh(); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; + const correlationContext = headerPolicy.headers.get(CORRELATION_CONTEXT_HEADER_NAME); expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Watch")).eq(true); - expect(correlationContext?.includes("MaxVariants=3")).eq(true); + expect(correlationContext.includes("RequestType=Watch")).eq(true); + expect(correlationContext.includes("MaxVariants=3")).eq(true); restoreMocks(); }); it("should have telemety tag in correlation-context header if feature flags enable telemetry", async () => { - let correlationContext: string = ""; - const listKvCallback = (listOptions) => { - correlationContext = listOptions?.requestOptions?.customHeaders[CORRELATION_CONTEXT_HEADER_NAME] ?? ""; - }; - mockAppConfigurationClientListConfigurationSettings([[ createMockedFeatureFlag("Alpha_1", { telemetry: {enabled: true} }) - ]], listKvCallback); + ]]); + mockFeatureFlagClientListFeatureFlags([]); const settings = await load(createMockedConnectionString(fakeEndpoint), { + clientOptions, featureFlagOptions: { enabled: true, selectors: [ {keyFilter: "*"} ], @@ -340,33 +331,30 @@ describe("request tracing", function () { } }); - expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Startup")).eq(true); + restoreMocks(); await sleepInMs(1_000 + 1_000); try { await settings.refresh(); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; + const correlationContext = headerPolicy.headers.get(CORRELATION_CONTEXT_HEADER_NAME); expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Watch")).eq(true); - expect(correlationContext?.includes("FFFeatures=Telemetry")).eq(true); + expect(correlationContext.includes("RequestType=Watch")).eq(true); + expect(correlationContext.includes("FFFeatures=Telemetry")).eq(true); restoreMocks(); }); it("should have seed tag in correlation-context header if feature flags use allocation seed", async () => { - let correlationContext: string = ""; - const listKvCallback = (listOptions) => { - correlationContext = listOptions?.requestOptions?.customHeaders[CORRELATION_CONTEXT_HEADER_NAME] ?? ""; - }; - mockAppConfigurationClientListConfigurationSettings([[ createMockedFeatureFlag("Alpha_1", { telemetry: {enabled: true} }), createMockedFeatureFlag("Alpha_2", { allocation: {seed: "123"} }) - ]], listKvCallback); + ]]); + mockFeatureFlagClientListFeatureFlags([]); const settings = await load(createMockedConnectionString(fakeEndpoint), { + clientOptions, featureFlagOptions: { enabled: true, selectors: [ {keyFilter: "*"} ], @@ -377,48 +365,44 @@ describe("request tracing", function () { } }); - expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Startup")).eq(true); + restoreMocks(); await sleepInMs(1_000 + 1_000); try { await settings.refresh(); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; + const correlationContext = headerPolicy.headers.get(CORRELATION_CONTEXT_HEADER_NAME); expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Watch")).eq(true); - expect(correlationContext?.includes("FFFeatures=Seed+Telemetry")).eq(true); + expect(correlationContext.includes("RequestType=Watch")).eq(true); + expect(correlationContext.includes("FFFeatures=Seed+Telemetry")).eq(true); restoreMocks(); }); it("should have AI tag in correlation-context header if key values use AI configuration", async () => { - let correlationContext: string = ""; - const listKvCallback = (listOptions) => { - correlationContext = listOptions?.requestOptions?.customHeaders[CORRELATION_CONTEXT_HEADER_NAME] ?? ""; - }; - mockAppConfigurationClientListConfigurationSettings([[ createMockedKeyValue({ contentType: "application/json; profile=\"https://azconfig.io/mime-profiles/ai/chat-completion\"" }) - ]], listKvCallback); + ]]); const settings = await load(createMockedConnectionString(fakeEndpoint), { + clientOptions, refreshOptions: { enabled: true, refreshIntervalInMs: 1000 } }); - expect(correlationContext).not.undefined; - expect(correlationContext?.includes("RequestType=Startup")).eq(true); + restoreMocks(); await sleepInMs(1000 + 1); try { await settings.refresh(); } catch { /* empty */ } expect(headerPolicy.headers).not.undefined; + const correlationContext = headerPolicy.headers.get(CORRELATION_CONTEXT_HEADER_NAME); expect(correlationContext).not.undefined; - expect(correlationContext?.includes("Features=AI+AICC")).eq(true); + expect(correlationContext.includes("Features=AI+AICC")).eq(true); restoreMocks(); }); diff --git a/test/utils/testHelper.ts b/test/utils/testHelper.ts index 745f4480..9b62d651 100644 --- a/test/utils/testHelper.ts +++ b/test/utils/testHelper.ts @@ -2,16 +2,33 @@ // Licensed under the MIT license. import * as sinon from "sinon"; -import { AppConfigurationClient, ConfigurationSetting, featureFlagContentType, secretReferenceContentType } from "@azure/app-configuration"; +import * as chai from "chai"; +import { AppConfigurationClient as ConfigurationClient, ConfigurationSetting, FeatureFlagClient, featureFlagContentType, secretReferenceContentType } from "@azure/app-configuration"; import { ClientSecretCredential } from "@azure/identity"; import { KeyVaultSecret, SecretClient } from "@azure/keyvault-secrets"; import * as uuid from "uuid"; -import { RestError } from "@azure/core-rest-pipeline"; -import { ConfigurationClientManager } from "../../src/configurationClientManager.js"; -import { ConfigurationClientWrapper } from "../../src/configurationClientWrapper.js"; +import { RestError, PipelineRequest, PipelineResponse, SendRequest } from "@azure/core-rest-pipeline"; +import { AppConfigurationClientManager } from "../../src/appConfigurationClientManager.js"; +import { AppConfigurationClientWrapper } from "../../src/appConfigurationClientWrapper.js"; +import { AppConfigurationClient } from "../../src/appConfigurationClient.js"; const sleepInMs = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +function expectEnhancedFeatureFlagJsonError(action: () => unknown, featureFlagName: string): void { + let thrownError: unknown; + try { + action(); + } catch (error) { + thrownError = error; + } + + chai.expect(thrownError).instanceOf(SyntaxError); + const syntaxError = thrownError as SyntaxError; + chai.expect(syntaxError.message).contains(`Enhanced feature flag '${featureFlagName}':`); + chai.expect(syntaxError.cause).instanceOf(SyntaxError); + chai.expect(syntaxError.message).contains((syntaxError.cause as SyntaxError).message); +} + // Async, browser-safe SHA-256 using native crypto.subtle when available; falls back to tiny FNV-1a for Node without subtle. async function _sha256(input: string): Promise { let crypto; @@ -51,7 +68,7 @@ function _filterKVs(unfilteredKvs: ConfigurationSetting[], listOptions: any) { } let tagsMatched = true; if (tagsFilter.length > 0) { - tagsMatched = tagsFilter.every(tag => { + tagsMatched = tagsFilter.every((tag: string) => { const [tagName, tagValue] = tag.split("="); if (tagValue === "\0") { return kv.tags && kv.tags[tagName] === null; @@ -63,7 +80,7 @@ function _filterKVs(unfilteredKvs: ConfigurationSetting[], listOptions: any) { }); } -function getMockedIterator(pages: ConfigurationSetting[][], kvs: ConfigurationSetting[], listOptions: any) { +function getMockedIterator(pages: ConfigurationSetting[][], kvs: ConfigurationSetting[], listOptions: any, useStringStatus: boolean = false) { const mockIterator: AsyncIterableIterator & { byPage(): AsyncIterableIterator } = { [Symbol.asyncIterator](): AsyncIterableIterator { kvs = _filterKVs(pages.flat(), listOptions); @@ -74,7 +91,7 @@ function getMockedIterator(pages: ConfigurationSetting[][], kvs: ConfigurationSe return Promise.resolve({ done: !value, value }); }, byPage(): AsyncIterableIterator { - let remainingPages; + let remainingPages: ConfigurationSetting[][]; const pageEtags = listOptions?.pageEtags ? [...listOptions.pageEtags] : undefined; // a copy of the original list return { [Symbol.asyncIterator](): AsyncIterableIterator { @@ -95,7 +112,7 @@ function getMockedIterator(pages: ConfigurationSetting[][], kvs: ConfigurationSe value: { items, etag, - _response: { status: statusCode } + _response: { status: useStringStatus ? `${statusCode}` : statusCode } } }; } @@ -128,21 +145,21 @@ function getCachedIterator(pages: Array<{ byPage(): AsyncIterableIterator { return { [Symbol.asyncIterator](): AsyncIterableIterator { return this; }, - next() { + async next() { const page = pages.shift(); if (!page) { - return Promise.resolve({ done: true, value: undefined }); + return { done: true, value: undefined }; } - const etag = _sha256(JSON.stringify(page.items)); + const etag = await _sha256(JSON.stringify(page.items)); - return Promise.resolve({ + return { done: false, value: { items: page.items, etag, _response: page.response } - }); + }; } }; } @@ -150,7 +167,7 @@ function getCachedIterator(pages: Array<{ return iterator as any; } -function getMockedHeadIterator(pages: ConfigurationSetting[][], listOptions: any) { +function getMockedHeadIterator(pages: ConfigurationSetting[][], listOptions: any, useStringStatus: boolean = false) { const mockIterator: AsyncIterableIterator & { byPage(): AsyncIterableIterator } = { [Symbol.asyncIterator](): AsyncIterableIterator { return this; @@ -180,7 +197,88 @@ function getMockedHeadIterator(pages: ConfigurationSetting[][], listOptions: any value: { items: [], // HEAD request returns no items etag, - _response: { status: statusCode } + _response: { status: useStringStatus ? `${statusCode}` : statusCode } + } + }; + } + } + }; + } + }; + + return mockIterator as any; +} + +function _filterFeatureFlags(featureFlags: any[], listOptions: any): any[] { + const nameFilter: string | undefined = listOptions?.nameFilter; + const labelFilter: string | undefined = listOptions?.labelFilter; + const tagsFilter: string[] = listOptions?.tagsFilter ?? []; + + return featureFlags.filter((ff) => { + // name filter: "*"/undefined matches all, trailing "*" is a prefix wildcard, otherwise exact match + let nameMatched = true; + if (nameFilter !== undefined && nameFilter !== "*") { + if (nameFilter.endsWith("*")) { + nameMatched = ff.name.startsWith(nameFilter.slice(0, -1)); + } else { + nameMatched = ff.name === nameFilter; + } + } + + // label filter: "\0" (LabelFilter.Null) matches feature flags without a label + let labelMatched = true; + if (labelFilter !== undefined) { + if (labelFilter === "\0") { + labelMatched = ff.label === undefined || ff.label === ""; + } else { + labelMatched = ff.label === labelFilter; + } + } + + // tag filters: every "key=value" must match + let tagsMatched = true; + tagsFilter.forEach((tagFilter: string) => { + const [tagName, tagValue] = tagFilter.split("="); + if (!ff.tags || ff.tags[tagName] !== tagValue) { + tagsMatched = false; + } + }); + + return nameMatched && labelMatched && tagsMatched; + }); +} + +function getMockedFeatureFlagIterator(pages: any[][], listOptions: any, useStringStatus: boolean = false) { + const mockIterator: AsyncIterableIterator & { byPage(): AsyncIterableIterator } = { + [Symbol.asyncIterator](): AsyncIterableIterator { + return this; + }, + next() { + return Promise.resolve({ done: true, value: undefined }); + }, + byPage(): AsyncIterableIterator { + let remainingPages: any[][]; + const pageEtags = listOptions?.pageEtags ? [...listOptions.pageEtags] : undefined; + return { + [Symbol.asyncIterator](): AsyncIterableIterator { + remainingPages = [...pages]; + return this; + }, + async next() { + const pageItems = remainingPages.shift(); + const pageEtag = pageEtags?.shift(); + if (pageItems === undefined) { + return { done: true, value: undefined }; + } else { + const items = _filterFeatureFlags(pageItems ?? [], listOptions); + const etag = await _sha256(JSON.stringify(items)); + const statusCode = pageEtag === etag ? 304 : 200; + return { + done: false, + value: { + items, + etag, + _response: { status: useStringStatus ? `${statusCode}` : statusCode } } }; } @@ -192,6 +290,19 @@ function getMockedHeadIterator(pages: ConfigurationSetting[][], listOptions: any return mockIterator as any; } +/** + * Mocks the listFeatureFlags method of FeatureFlagClient to return the provided pages of feature flags. + * @param pages List of pages, each page is a list of typed feature flags (see createMockedEnhancedFeatureFlag). + */ +function mockFeatureFlagClientListFeatureFlags(pages: any[][], customCallback?: (listOptions: any) => any) { + sinon.stub(FeatureFlagClient.prototype, "listFeatureFlags").callsFake((listOptions) => { + if (customCallback) { + customCallback(listOptions); + } + return getMockedFeatureFlagIterator(pages, listOptions); + }); +} + /** * Mocks the listConfigurationSettings method of AppConfigurationClient to return the provided pages of ConfigurationSetting. * E.g. @@ -199,9 +310,9 @@ function getMockedHeadIterator(pages: ConfigurationSetting[][], listOptions: any * * @param pages List of pages, each page is a list of ConfigurationSetting */ -function mockAppConfigurationClientListConfigurationSettings(pages: ConfigurationSetting[][], customCallback?: (listOptions) => any) { +function mockAppConfigurationClientListConfigurationSettings(pages: ConfigurationSetting[][], customCallback?: (listOptions: any) => any) { - sinon.stub(AppConfigurationClient.prototype, "listConfigurationSettings").callsFake((listOptions) => { + sinon.stub(ConfigurationClient.prototype, "listConfigurationSettings").callsFake((listOptions) => { if (customCallback) { customCallback(listOptions); } @@ -210,42 +321,75 @@ function mockAppConfigurationClientListConfigurationSettings(pages: Configuratio return getMockedIterator(pages, kvs, listOptions); }); - sinon.stub(AppConfigurationClient.prototype, "checkConfigurationSettings").callsFake((listOptions) => { + sinon.stub(ConfigurationClient.prototype, "checkConfigurationSettings").callsFake((listOptions) => { if (customCallback) { customCallback(listOptions); } return getMockedHeadIterator(pages, listOptions); }); + } -function mockAppConfigurationClientLoadBalanceMode(pages: ConfigurationSetting[][], clientWrapper: ConfigurationClientWrapper, countObject: { count: number }) { +function mockAppConfigurationClientListConfigurationSettingsWithStringStatus(pages: ConfigurationSetting[][], customCallback?: (listOptions: any) => any) { + + sinon.stub(ConfigurationClient.prototype, "listConfigurationSettings").callsFake((listOptions) => { + if (customCallback) { + customCallback(listOptions); + } + + const kvs = _filterKVs(pages.flat(), listOptions); + return getMockedIterator(pages, kvs, listOptions, true); + }); + + sinon.stub(ConfigurationClient.prototype, "checkConfigurationSettings").callsFake((listOptions) => { + if (customCallback) { + customCallback(listOptions); + } + + return getMockedHeadIterator(pages, listOptions, true); + }); + +} + +function mockAppConfigurationClientLoadBalanceMode( + pages: ConfigurationSetting[][], + clientWrapper: AppConfigurationClientWrapper, + callCounts: { configurationSettings: number; enhancedFeatureFlags: number } +) { sinon.stub(clientWrapper.client, "listConfigurationSettings").callsFake((listOptions) => { - countObject.count += 1; + callCounts.configurationSettings += 1; const kvs = _filterKVs(pages.flat(), listOptions); return getMockedIterator(pages, kvs, listOptions); }); sinon.stub(clientWrapper.client, "checkConfigurationSettings").callsFake((listOptions) => { - countObject.count += 1; + callCounts.configurationSettings += 1; return getMockedHeadIterator(pages, listOptions); }); + sinon.stub(clientWrapper.client, "listFeatureFlags").callsFake((listOptions) => { + callCounts.enhancedFeatureFlags += 1; + return getMockedFeatureFlagIterator([], listOptions); + }); } -function mockConfigurationManagerGetClients(fakeClientWrappers: ConfigurationClientWrapper[], isFailoverable: boolean, ...pages: ConfigurationSetting[][]) { +function mockConfigurationManagerGetClients(fakeClientWrappers: AppConfigurationClientWrapper[], isFailoverable: boolean, ...pages: ConfigurationSetting[][]) { // Stub the getClients method on the class prototype - sinon.stub(ConfigurationClientManager.prototype, "getClients").callsFake(async () => { + sinon.stub(AppConfigurationClientManager.prototype, "getClients").callsFake(async () => { if (fakeClientWrappers?.length > 0) { return fakeClientWrappers; } - const clients: ConfigurationClientWrapper[] = []; + const clients: AppConfigurationClientWrapper[] = []; const fakeEndpoint = createMockedEndpoint("fake"); - const fakeStaticClientWrapper = new ConfigurationClientWrapper(fakeEndpoint, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint))); + const fakeStaticClientWrapper = new AppConfigurationClientWrapper(fakeEndpoint, new AppConfigurationClient(createMockedConnectionString(fakeEndpoint))); sinon.stub(fakeStaticClientWrapper.client, "listConfigurationSettings").callsFake(() => { throw new RestError("Internal Server Error", { statusCode: 500 }); }); sinon.stub(fakeStaticClientWrapper.client, "checkConfigurationSettings").callsFake(() => { throw new RestError("Internal Server Error", { statusCode: 500 }); }); + sinon.stub(fakeStaticClientWrapper.client, "listFeatureFlags").callsFake(() => { + throw new RestError("Internal Server Error", { statusCode: 500 }); + }); clients.push(fakeStaticClientWrapper); if (!isFailoverable) { @@ -253,7 +397,7 @@ function mockConfigurationManagerGetClients(fakeClientWrappers: ConfigurationCli } const fakeReplicaEndpoint = createMockedEndpoint("fake-replica"); - const fakeDynamicClientWrapper = new ConfigurationClientWrapper(fakeReplicaEndpoint, new AppConfigurationClient(createMockedConnectionString(fakeReplicaEndpoint))); + const fakeDynamicClientWrapper = new AppConfigurationClientWrapper(fakeReplicaEndpoint, new AppConfigurationClient(createMockedConnectionString(fakeReplicaEndpoint))); clients.push(fakeDynamicClientWrapper); sinon.stub(fakeDynamicClientWrapper.client, "listConfigurationSettings").callsFake((listOptions) => { const kvs = _filterKVs(pages.flat(), listOptions); @@ -262,12 +406,15 @@ function mockConfigurationManagerGetClients(fakeClientWrappers: ConfigurationCli sinon.stub(fakeDynamicClientWrapper.client, "checkConfigurationSettings").callsFake((listOptions) => { return getMockedHeadIterator(pages, listOptions); }); + sinon.stub(fakeDynamicClientWrapper.client, "listFeatureFlags").callsFake((listOptions) => { + return getMockedFeatureFlagIterator([], listOptions); + }); return clients; }); } -function mockAppConfigurationClientGetConfigurationSetting(kvList: any[], customCallback?: (options) => any) { - sinon.stub(AppConfigurationClient.prototype, "getConfigurationSetting").callsFake((settingId, options) => { +function mockAppConfigurationClientGetConfigurationSetting(kvList: any[], customCallback?: (options: any) => any) { + sinon.stub(ConfigurationClient.prototype, "getConfigurationSetting").callsFake((settingId, options) => { if (customCallback) { customCallback(options); } @@ -285,8 +432,8 @@ function mockAppConfigurationClientGetConfigurationSetting(kvList: any[], custom }); } -function mockAppConfigurationClientGetSnapshot(snapshotResponses: Map, customCallback?: (options) => any) { - sinon.stub(AppConfigurationClient.prototype, "getSnapshot").callsFake((name, options) => { +function mockAppConfigurationClientGetSnapshot(snapshotResponses: Map, customCallback?: (options: any) => any) { + sinon.stub(ConfigurationClient.prototype, "getSnapshot").callsFake((name, options) => { if (customCallback) { customCallback(options); } @@ -299,8 +446,8 @@ function mockAppConfigurationClientGetSnapshot(snapshotResponses: Map, customCallback?: (options) => any) { - sinon.stub(AppConfigurationClient.prototype, "listConfigurationSettingsForSnapshot").callsFake((name, listOptions) => { +function mockAppConfigurationClientListConfigurationSettingsForSnapshot(snapshotResponses: Map, customCallback?: (options: any) => any) { + sinon.stub(ConfigurationClient.prototype, "listConfigurationSettingsForSnapshot").callsFake((name, listOptions) => { if (customCallback) { customCallback(listOptions); } @@ -321,7 +468,7 @@ function mockSecretClientGetSecret(uriValueList: [string, string][]) { dict.set(uri, value); } - sinon.stub(SecretClient.prototype, "getSecret").callsFake(async function (secretName, options) { + sinon.stub(SecretClient.prototype, "getSecret").callsFake(async function (this: SecretClient, secretName, options) { const url = new URL(this.vaultUrl); url.pathname = `/secrets/${secretName}`; if (options?.version) { @@ -411,6 +558,15 @@ const createMockedSnapshotReference = (key: string, snapshotName: string): Confi isReadOnly: false, }); +// Creates an enhanced feature flag as returned by the dedicated feature flag endpoint (FeatureFlagClient.listFeatureFlags). +const createMockedEnhancedFeatureFlag = (name: string, props?: any) => Object.assign({ + name, + enabled: true, + conditions: { filters: [] }, + lastModified: new Date(), + etag: uuid.v4() +}, props); + class HttpRequestHeadersPolicy { headers: any; name: string; @@ -419,7 +575,7 @@ class HttpRequestHeadersPolicy { this.headers = {}; this.name = "HttpRequestHeadersPolicy"; } - sendRequest(req, next) { + sendRequest(req: PipelineRequest, next: SendRequest): Promise { this.headers = req.headers; return next(req).then(resp => resp); } @@ -428,6 +584,8 @@ class HttpRequestHeadersPolicy { export { sinon, mockAppConfigurationClientListConfigurationSettings, + mockAppConfigurationClientListConfigurationSettingsWithStringStatus, + mockFeatureFlagClientListFeatureFlags, mockAppConfigurationClientGetConfigurationSetting, mockAppConfigurationClientGetSnapshot, mockAppConfigurationClientListConfigurationSettingsForSnapshot, @@ -445,7 +603,9 @@ export { createMockedJsonKeyValue, createMockedKeyValue, createMockedFeatureFlag, + createMockedEnhancedFeatureFlag, createMockedSnapshotReference, + expectEnhancedFeatureFlagJsonError, sleepInMs, HttpRequestHeadersPolicy diff --git a/vitest.browser.config.ts b/vitest.browser.config.ts index b263ba7c..bce558aa 100644 --- a/vitest.browser.config.ts +++ b/vitest.browser.config.ts @@ -1,10 +1,11 @@ +import { playwright } from "@vitest/browser-playwright"; import { defineConfig } from "vitest/config"; export default defineConfig({ test: { browser: { enabled: true, - provider: "playwright", + provider: playwright(), headless: true, instances: [ { browser: "chromium" },